-
Notifications
You must be signed in to change notification settings - Fork 0
/
zfs.subr
437 lines (370 loc) · 12 KB
/
zfs.subr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
if [ ! "$_CBSD_ZFS_SUBR" ]; then
_CBSD_ZFS_SUBR=1
###
# return 0 if $1 is not valid ZFS mountpoint
# return 1 if $1 is valid ZFS mountpoint and mounted
# return 2 if $1 is valid ZFS mountpoint and not mounted
# if zfsmnt /mnt; then
# echo " not zfs (mounted or not) mountpoint"
# fi
# export ZPOOL for name ZFS for $1 mountpoint
zfsmnt() {
local _A
ZPOOL=$(${ZFS_CMD} list -Ho name,mountpoint | while read _name _mnt; do
[ "${_mnt}" = "${1}" ] && echo ${_name} && exit 2
done)
if [ $? -eq 2 ]; then
# Check for mounted
_A=$( ${ZFS_CMD} get -Ho value mounted ${ZPOOL} )
[ "${_A}" = "yes" ] && return 1
return 2
else
return 0
fi
}
# return 0 if $1 is not valid ZFS filesystem
# return 1 if $1 is valid ZFS mountpoint and mounted
# return 2 if $1 is valid ZFS mountpoint and not mounted
# if zfsfs /mnt; then
# echo " not zfs (mounted or not) mounted"
# fi
zfsfs() {
local _A
_A=$(${ZFS_CMD} list -Ho name | while read _name; do
[ "${_name}" = "${1}" ] && exit 2
done)
if [ $? -eq 2 ]; then
# Check for mounted
_A=$( ${ZFS_CMD} get -Ho value mounted ${1} )
[ "${_A}" = "yes" ] && return 1
return 2
else
return 0
fi
}
# export zmnt if $zroot exist, return 1
getmnt() {
local _res
[ -z "$1" ] && return 1
zmnt=$( ${ZFS_CMD} get -Ho value mountpoint ${1} )
return $?
}
# return 0 if ${ZPOOL}/$1 zfs source exist
# if zfsroot jail1; then
# echo "zroot/$jail1 exist
# fi
zfsroot() {
[ -z "$1" ] && return 0
${ZFS_CMD} list -H -o name | while read _mnt; do
[ "$_mnt" = "${ZPOOL}/${1}" ] && exit 0
done
return $?
}
# $1 - oldjname
# $2 - newjname
zfs_snapshot_rename()
{
local _fs _jname _mod _snapname _oldjname _newjname
_oldjname="$1"
_newjname="$2"
[ -z "${_oldjname}" -o -z "${_newjname}" ] && return 0
# [ -n "${_oldjname}" ] && _mod="${ZPOOL}/${_oldjname}"
_mod="${ZPOOL}"
for _fs in $( ${ZFS_CMD} list -H -r -t snapshot -o name ${_mod} 2>/dev/null ); do
_jname=$( ${ZFS_CMD} get -H -o value -s local cbsdsnap:jname "${_fs}" 2>/dev/null )
[ -z "${_jname}" ] && continue
[ -n "${_oldjname}" -a "${_oldjname}" != "${_jname}" ] && continue
_snapname=$( ${ZFS_CMD} get -H -o value -s local cbsdsnap:snapname "${_fs}" 2>/dev/null )
[ -z "${_snapname}" ] && continue
${ZFS_CMD} set cbsdsnap:jname=${_newjname} ${ZPOOL}@${_snapname}
# ${ECHO} "${N1_COLOR}ZFS snapshot renamed: ${N2_COLOR}${_snapname}${N0_COLOR}"
done
}
# test if symlink point to zvol
# extract and return 0 with is_zvol params as zvol
# $1 - path to symlink
is_getzvol()
{
is_zvol=
local _zvol_pref=
local _res=1
local tmp_zvol=
[ -z "${1}" ] && return 1
[ ! -h "${1}" ] && return 1
tmp_zvol=$( ${READLINK_CMD} ${1} 2>/dev/null )
if [ -n "${tmp_zvol}" ]; then
_zvol_pref=$( substr --pos=0 --len=10 --str=${tmp_zvol} )
if [ "${_zvol_pref}" = "/dev/zvol/" ]; then
_ret=0
is_zvol=$( echo ${tmp_zvol} | ${SED_CMD} s:/dev/zvol/::g )
else
_ret=1
is_zvol=
fi
else
is_zvol=
fi
return ${_ret}
}
# create ZVOL from file
# -b 0,1 - show progressbar (1 - by default), via cbsdtee
# -f full path to file
# -p alternative parent ZPOOL name (datadir zpool by default)
# -n ZVOL name (by default: basename of ${_file}
# if ! zfs_create_zvol_from_file -f /boot/kernel/kernel -n kernelvolume; then
# echo ";=("
# fi
# return 0 when on success
# return 1 when error
# return 2 when zvol already exist
zfs_create_zvol_from_file()
{
local _file= _pool= _zvol_name= DATA= _human_bytes= _res _bar=1 _zvol_rec_size=0
local _ebytes _ebytes_data _ebytes_data_orig _human_data_bytes
local i _def_val _zvol_opts_merged _zvol_opts zfs_custom_opt
while getopts "b:f:o:p:n:" opt; do
case "${opt}" in
b) _bar="${OPTARG}" ;;
f) _file="${OPTARG}" ;;
o) zfs_custom_opt="${OPTARG}" ;;
p) _pool="${OPTARG}" ;;
n) _zvol_name="${OPTARG}" ;;
esac
shift $(($OPTIND - 1))
done
if [ "${fsfeat}" = "0" ]; then
echo "zfs_create_zvol_from_file: zfsfeat = 0"
cbsdlogger NOTICE ${CBSD_APP}: zfs_create_zvol_from_file: zfs feature off, skipp"
return 1
fi
if [ ! -r "${_file}" ]; then
echo "zfs_create_zvol_from_file: no such file: ${_file}"
cbsdlogger NOTICE ${CBSD_APP}: zfs_create_zvol_from_file no such file: ${_file}"
return 1
fi
_ebytes=$( ${STAT_CMD} -f "%z" ${_file} 2>/dev/null )
_ebytes_data=$( ${STAT_CMD} -f "%b" ${_file} 2>/dev/null )
_ebytes_data=$(( _ebytes_data * 512 )) # real referenced size/data
if [ ${_ebytes} -lt 128 ]; then
echo "zfs_create_zvol_from_file: file size too small: ${_ebytes} bytes"
cbsdlogger NOTICE ${CBSD_APP}: zfs_create_zvol_from_file: file size too small: ${_ebytes} bytes
return 1
fi
[ -z "${_zvol_name}" ] && _zvol_name=$( ${BASENAME_CMD} ${_file} )
if conv2human "${_ebytes}"; then
_human_bytes=${convval}
else
_human_bytes="${_ebytes}"
fi
if conv2human "${_ebytes_data}"; then
_human_data_bytes=${convval}
else
_human_data_bytes="${_ebytes_data}"
fi
. ${zfstool}
if [ -z "${_pool}" ]; then
DATA=$( ${ZFS_CMD} get -Ho value name ${jaildatadir} )
else
DATA="${_pool}"
fi
if [ -r "/dev/zvol/${DATA}/${_zvol_name}" ]; then
echo "zfs_create_zvol_from_file: zvol already exist: ${_zvol_name}"
cbsdlogger NOTICE ${CBSD_APP}: zfs_create_zvol_from_file: zvol already exist: ${_zvol_name}
return 2
fi
_zvol_rec_size=$( ${ZFS_CMD} get -Hp -o value recordsize ${DATA} )
# volume size must be a multiple of volume block size
_ebytes=$( roundup --num=${_ebytes} --multiple=${_zvol_rec_size} 2>/dev/null )
cbsdlogger NOTICE ${CBSD_APP}: zfs_create_zvol_from_file: roundup by recsize ${_zvol_rec_size}: [${_ebytes}]
if [ -z "${_ebytes}" ]; then
echo "zfs_create_zvol_from_file: roundup error: roundup --num=${_ebytes} --multiple=${_zvol_rec_size}"
return 1
fi
if is_number ${_ebytes}; then
echo "zfs_create_zvol_from_file: roundup error: not number: [${_ebytes}]"
cbsdlogger NOTICE ${CBSD_APP}: zfs_create_zvol_from_file: roundup by recsize ${_zvol_rec_size}: [${_ebytes}]
return 1
fi
# default_vm_zvol_volblocksize etc...
readconf zfs.conf
_zvol_opts=
_zvol_opts_merged=
# lookup for "default_ci_zvol_*" defaults
for i in ${default_ci_zvol_managed_feature}; do
eval _def_val="\$default_ci_zvol_$i"
if [ -n "${_def_val}" ]; then
if [ -z "${_zvol_opts}" ]; then
_zvol_opts="-o ${i}=${_def_val}"
else
_zvol_opts="${_zvol_opts} -o ${i}=${_def_val}"
fi
fi
done
if [ -z "${zfs_custom_opt}" ]; then
# no merge with custom zvol_opts=
_zvol_opts_merged="${_zvol_opts}"
else
_zvol_opts_merged=$( zfs_merge_opts -d "${zfs_custom_opt}" -s "${_zvol_opts}" 2>/dev/null )
fi
_msg=$( ${ZFS_CMD} create -V ${_ebytes} ${_zvol_opts_merged} ${DATA}/${_zvol_name} 2>&1 )
_res=$?
if [ ${_res} -ne 0 ]; then
cbsdlogger NOTICE ${CBSD_APP}: zfs_create_zvol_from_file: zfs_create_zvol_from_file: ${ZFS_CMD} create -V ${_ebytes} ${_zvol_opts_merged} ${DATA}/${_zvol_name}: ${_msg}
return 1
fi
if [ ${_bar} -eq 1 ]; then
${ECHO} "${N1_COLOR}Original size: ${_human_bytes}, real referenced size/data: ${_human_data_bytes}${N0_COLOR}"
${ECHO} "${N1_COLOR}Converting ${N2_COLOR}${_file}${N1_COLOR} -> ${N2_COLOR}/dev/zvol/${DATA}/${_zvol_name}${N1_COLOR}: ${N2_COLOR}${_human_bytes}${N1_COLOR}...${N0_COLOR}"
/usr/bin/nice -n 20 ${DD_CMD} if=${_file} bs=4m | ${miscdir}/cbsdtee -e ${_ebytes} > /dev/zvol/${DATA}/${_zvol_name}
echo
else
/usr/bin/nice -n 20 ${DD_CMD} if=${_file} of=/dev/zvol/${DATA}/${_zvol_name} bs=4m
echo
fi
# set readonly for gold volume
${ZFS_CMD} set readonly=on ${DATA}/${_zvol_name}
return 0
}
# -n _zvol_name - destination zvol name in ${_zvol_dst} ( when
# not specified, use basename from ${_source} file )
# -s source file, _source
# -z zvol_dst (when not specified, get parent from ${jaildatadir}
convert_source_image_to_zvol()
{
local _source _orig_source DATA _zvol_dst _zvol_name
[ ${zfsfeat} -ne 1 ] && return 0
while getopts "n:s:z:" opt; do
case "${opt}" in
n)
_zvol_name="${OPTARG}"
;;
s)
_orig_source="${OPTARG}"
;;
z)
_zvol_dst="${OPTARG}"
;;
esac
shift $(($OPTIND - 1))
done
if [ -z "${_zvol_dst}" ]; then
_zvol_dst=$( ${ZFS_CMD} get -Ho value name ${jaildatadir} )
cbsdlogger NOTICE ${CBSD_APP}: convert_source_image_to_zvol: auto zvol_dst selected: ${_zvol_dst}
fi
if [ -z "${_zvol_dst}" ]; then
${ECHO} "${N1_COLOR}convert_source_image_zvol: empty _zvol_dst${N0_COLOR}"
cbsdlogger NOTICE ${CBSD_APP}: convert_source_image_to_zvol: empty _zvol_dst
return 0
fi
if [ -z "${_orig_source}" ]; then
${ECHO} "${N1_COLOR}convert_source_image_zvol: empty _source, use -s <file>${N0_COLOR}"
cbsdlogger NOTICE ${CBSD_APP}: convert_source_image_to_zvol: empty _orig_source
return 0
fi
if [ ! -r "${_orig_source}" ]; then
${ECHO} "${N1_COLOR}convert_source_image_zvol: file not readable: ${N2_COLOR}${_orig_source}${N0_COLOR}"
cbsdlogger NOTICE ${CBSD_APP}: convert_source_image_to_zvol: file not readable: ${_orig_source}
return 0
fi
[ -z "${_zvol_name}" ] && _zvol_name=$( ${BASENAME_CMD} ${_orig_source} )
if [ -r "/dev/zvol/${_zvol_dst}/${_zvol_name}" ]; then
cbsdlogger NOTICE ${CBSD_APP}: convert_source_image_to_zvol: already exist: /dev/zvol/${_zvol_dst}/${_zvol_name}, nothing to do
return 0 # already exist
fi
zfs_create_zvol_from_file -f ${_orig_source} -n ${_zvol_name} -p ${_zvol_dst}
if [ -r "/dev/zvol/${_zvol_dst}/${_zvol_name}" ]; then
cbsdlogger NOTICE ${CBSD_APP}: convert_source_image_to_zvol: re-create symlink ${_orig_source}:/dev/zvol/${_zvol_dst}/${_zvol_name}
# re-create symlink
${RM_CMD} -f ${_orig_source}
${LN_CMD} -s /dev/zvol/${_zvol_dst}/${_zvol_name} ${_orig_source}
fi
}
# -p - by full path to symlink/zvol
# -v - by zvol
# return 0 on success, 1 on fail
# e.g: _res=$( get_dsk_zfs_guid -p ${_dsk_fullpath} )
# if [ $? -eq 0 ]; then
# echo "guid: ${_res}"
# fi
get_dsk_zfs_guid()
{
local _dsk_fullpath _is_zvol _res
local tmp_zvol _zvol_pref _is_zvol
while getopts "p:v:" opt; do
case "${opt}" in
p)
_dsk_fullpath="${OPTARG}"
;;
v)
_is_zvol="${OPTARG}"
;;
esac
shift $(($OPTIND - 1))
done
if [ -z "${_is_zvol}" ]; then
if [ -z "${_dsk_fullpath}" ]; then
${ECHO} "${N1_COLOR}skipp get_dsk_zfs_guid: empty fullpath via -p${N0_COLOR}" 1>&2 # to stderr
return 1
fi
if [ ! -h "${_dsk_fullpath}" ]; then
${ECHO} "${N1_COLOR}skipp get_dsk_zfs_guid: not symlink to zvol: ${N2_COLOR}${_dsk_fullpath}${N0_COLOR}" 1>&2 # to stderr
return 1
fi
tmp_zvol=$( ${READLINK_CMD} ${_dsk_fullpath} 2>/dev/null )
_zvol_pref=$( substr --pos=0 --len=10 --str=${tmp_zvol} )
# not started with /dev/zvol ?
if [ "${_zvol_pref}" != "/dev/zvol/" ]; then
${ECHO} "${N1_COLOR}skipp dsk_modify_dsk_zfs_guid error: no /dev/zvol/ prefix: ${N2_COLOR}${_zvol_pref}${N0_COLOR}" 1>&2 # to stderr
return 1
fi
_is_zvol=$( echo ${tmp_zvol} | ${SED_CMD} s:/dev/zvol/::g )
fi
_res=$( ${ZFS_CMD} get -Hp -o value guid ${_is_zvol} 2>/dev/null )
if [ -z "${_res}" ]; then
${ECHO} "${N1_COLOR}skipp dsk_modify_dsk_zfs_guid error: unable to determine guid for: ${N2_COLOR}${_is_zvol}${N0_COLOR}" 1>&2 # to stderr
return 1
fi
printf "${_res}"
return 0
}
# merge two (source and destination) args string "-o arg1=x arg2=y"
# into one with duplicate removal ( destination args/val win )
zfs_merge_opts()
{
local _source _source2 _dest i j _s1 _s2 _sfeat _pos _exist
while getopts "d:s:" opt; do
case "${opt}" in
d)
_dest="${OPTARG}"
;;
s)
_source="${OPTARG}"
;;
esac
shift $(($OPTIND - 1))
done
for i in ${_source}; do
if [ "${i}" != "-o" ]; then
strpos --str="${i}" --search="="
_pos=$?
[ ${_pos} -eq 0 ] && continue # not param=val args?!
_sfeat=$( substr --pos=0 --len=${_pos} --str=${i} ) # now we have source param
_exist=0
for j in ${_dest}; do
[ "${j}" = "-o" ] && continue
strpos --str="${j}" --search="="
_pos=$?
[ ${_pos} -eq 0 ] && continue # not param=val args?!
_dfeat=$( substr --pos=0 --len=${_pos} --str=${j} ) # now we have dest param
if [ "${_sfeat}" = "${_dfeat}" ]; then
_exist=1
break
fi
done
[ ${_exist} -eq 0 ] && _source2="-o ${i} ${_source2}"
fi
done
echo -n "${_dest} ${_source2}"
}
###
fi