common/rc: fix _get_max_lfs_filesize on 32-bit platforms
[xfstests-dev.git] / common / btrfs
1 #
2 # Common btrfs specific functions
3 #
4
5 _btrfs_get_subvolid()
6 {
7         mnt=$1
8         name=$2
9
10         $BTRFS_UTIL_PROG sub list $mnt | grep $name | awk '{ print $2 }'
11 }
12
13 # _require_btrfs_command <command> [<subcommand>|<option>]
14 # We check for btrfs and (optionally) features of the btrfs command
15 # It can both subfunction like "inspect-internal dump-tree" and
16 # options like "check --qgroup-report"
17 _require_btrfs_command()
18 {
19         local cmd=$1
20         local param=$2
21         local safe_param
22
23         _require_command "$BTRFS_UTIL_PROG" btrfs
24         if [ -z "$1" ]; then
25                 return 1;
26         fi
27         $BTRFS_UTIL_PROG $cmd --help &> /dev/null
28         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd)"
29
30         test -z "$param" && return
31
32         # If $param is an option, replace leading "-"s for grep
33         if [ ${param:0:1} == "-" ]; then
34                 safe_param=$(echo $param | sed 's/^-*//')
35                 $BTRFS_UTIL_PROG $cmd --help | grep -wq $safe_param || \
36                         _notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param)"
37                 return
38         fi
39
40         $BTRFS_UTIL_PROG $cmd $param --help &> /dev/null
41         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd $param)"
42 }
43
44 # Require extra check on btrfs qgroup numbers
45 _require_btrfs_qgroup_report()
46 {
47         _require_btrfs_command check --qgroup-report
48         touch ${RESULT_DIR}/require_scratch.require_qgroup_report
49 }
50
51 _require_btrfs_dump_super()
52 {
53         if [ ! -x "$BTRFS_SHOW_SUPER_PROG" ]; then
54                 _require_command "$BTRFS_UTIL_PROG" btrfs
55                 if ! $BTRFS_UTIL_PROG inspect-internal dump-super --help >& /dev/null; then
56                         _notrun "Missing btrfs-show-super or inspect-internal dump-super"
57                 fi
58                 BTRFS_SHOW_SUPER_PROG="$BTRFS_UTIL_PROG inspect-internal dump-super"
59         fi
60 }
61
62 _run_btrfs_util_prog()
63 {
64         run_check $BTRFS_UTIL_PROG $*
65 }
66
67 _require_btrfs_mkfs_feature()
68 {
69         if [ -z $1 ]; then
70                 echo "Missing feature name argument for _require_btrfs_mkfs_feature"
71                 exit 1
72         fi
73         feat=$1
74         $MKFS_BTRFS_PROG -O list-all 2>&1 | \
75                 grep '^[ \t]*'"$feat"'\b' > /dev/null 2>&1
76         [ $? -eq 0 ] || \
77                 _notrun "Feature $feat not supported in the available version of mkfs.btrfs"
78 }
79
80 _require_btrfs_fs_feature()
81 {
82         if [ -z $1 ]; then
83                 echo "Missing feature name argument for _require_btrfs_fs_feature"
84                 exit 1
85         fi
86         feat=$1
87         modprobe btrfs > /dev/null 2>&1
88         [ -e /sys/fs/btrfs/features/$feat ] || \
89                 _notrun "Feature $feat not supported by the available btrfs version"
90 }
91
92 _require_btrfs_fs_sysfs()
93 {
94         modprobe btrfs > /dev/null 2>&1
95         [ -e /sys/fs/btrfs/features ] || \
96                 _notrun "Sysfs not supported by the available btrfs version"
97
98 }
99
100 _check_btrfs_filesystem()
101 {
102         device=$1
103
104         # If type is set, we're mounted
105         type=`_fs_type $device`
106         ok=1
107
108         if [ "$type" = "$FSTYP" ]; then
109                 # mounted ...
110                 mountpoint=`_umount_or_remount_ro $device`
111         fi
112
113         if [ -f ${RESULT_DIR}/require_scratch.require_qgroup_report ]; then
114                 $BTRFS_UTIL_PROG check $device --qgroup-report > $tmp.qgroup_report 2>&1
115                 if grep -qE "Counts for qgroup.*are different" $tmp.qgroup_report ; then
116                         _log_err "_check_btrfs_filesystem: filesystem on $device has wrong qgroup numbers"
117                         echo "*** qgroup_report.$FSTYP output ***"      >>$seqres.full
118                         cat $tmp.qgroup_report                          >>$seqres.full
119                         echo "*** qgroup_report.$FSTYP output ***"      >>$seqres.full
120                 fi
121                 rm -f $tmp.qgroup_report
122         fi
123
124         $BTRFS_UTIL_PROG check $device >$tmp.fsck 2>&1
125         if [ $? -ne 0 ]; then
126                 _log_err "_check_btrfs_filesystem: filesystem on $device is inconsistent"
127                 echo "*** fsck.$FSTYP output ***"       >>$seqres.full
128                 cat $tmp.fsck                           >>$seqres.full
129                 echo "*** end fsck.$FSTYP output"       >>$seqres.full
130
131                 ok=0
132         fi
133         rm -f $tmp.fsck
134
135         if [ $ok -eq 0 ]; then
136                 echo "*** mount output ***"             >>$seqres.full
137                 _mount                                  >>$seqres.full
138                 echo "*** end mount output"             >>$seqres.full
139         elif [ "$type" = "$FSTYP" ]; then
140                 # was mounted ...
141                 _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
142                 ok=$?
143         fi
144
145         if [ $ok -eq 0 ]; then
146                 status=1
147                 if [ "$iam" != "check" ]; then
148                         exit 1
149                 fi
150                 return 1
151         fi
152
153         return 0
154 }
155
156 _require_btrfs_dev_del_by_devid()
157 {
158         $BTRFS_UTIL_PROG device delete --help | egrep devid > /dev/null 2>&1
159         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old "\
160                         "(must support 'btrfs device delete <devid> /<mnt>')"
161 }
162
163 # get btrfs profile configs being tested
164 #
165 # A set of pre-set profile configs are exported via _btrfs_profile_configs
166 # array. Default configs can be overridden by setting BTRFS_PROFILE_CONFIGS
167 # var in the format "metadata_profile:data_profile", multiple configs can be
168 # seperated by space, e.g.
169 # export BTRFS_PROFILE_CONFIGS="raid0:raid0 raid1:raid1 dup:single"
170 _btrfs_get_profile_configs()
171 {
172         if [ "$FSTYP" != "btrfs" ]; then
173                 return
174         fi
175
176         if [ -z "$BTRFS_PROFILE_CONFIGS" ]; then
177                 # Default configurations to test.
178                 local configs=(
179                         "single:single"
180                         "dup:single"
181                         "raid0:raid0"
182                         "raid1:raid0"
183                         "raid1:raid1"
184                         "raid10:raid10"
185                         "raid5:raid5"
186                         "raid6:raid6"
187                 )
188         else
189                 # User-provided configurations.
190                 local configs=(${BTRFS_PROFILE_CONFIGS[@]})
191         fi
192
193         _btrfs_profile_configs=()
194         for cfg in "${configs[@]}"; do
195                 local supported=true
196                 local profiles=(${cfg/:/ })
197                 if [ "$1" == "replace" ]; then
198                         # We can't do replace with these profiles because they
199                         # imply only one device ($SCRATCH_DEV), and we need to
200                         # keep $SCRATCH_DEV around for _scratch_mount
201                         # and _check_scratch_fs.
202                         local unsupported=(
203                                 "dup"
204                         )
205                 elif [ "$1" == "replace-missing" ]; then
206                         # We can't replace missing devices with these profiles
207                         # because there isn't enough redundancy.
208                         local unsupported=(
209                                 "single"
210                                 "dup"
211                                 "raid0"
212                         )
213                 else
214                         local unsupported=()
215                 fi
216                 for unsupp in "${unsupported[@]}"; do
217                         if [ "${profiles[0]}" == "$unsupp" -o "${profiles[1]}" == "$unsupp" ]; then
218                              if [ -z "$BTRFS_PROFILE_CONFIGS" ]; then
219                                      # For the default config, just omit it.
220                                      supported=false
221                              else
222                                      # For user-provided config, don't run the test.
223                                      _notrun "Profile $unsupp not supported for $1"
224                              fi
225                         fi
226                 done
227                 if "$supported"; then
228                         _btrfs_profile_configs+=("-m ${profiles[0]} -d ${profiles[1]}")
229                 fi
230         done
231         export _btrfs_profile_configs
232 }
233
234 # stress btrfs by running balance operation in a loop
235 _btrfs_stress_balance()
236 {
237         local options=$@
238         while true; do
239                 $BTRFS_UTIL_PROG balance start $options
240         done
241 }
242
243 # stress btrfs by creating/mounting/umounting/deleting subvolume in a loop
244 _btrfs_stress_subvolume()
245 {
246         local btrfs_dev=$1
247         local btrfs_mnt=$2
248         local subvol_name=$3
249         local subvol_mnt=$4
250         local stop_file=$5
251
252         mkdir -p $subvol_mnt
253         while [ ! -e $stop_file ]; do
254                 $BTRFS_UTIL_PROG subvolume create $btrfs_mnt/$subvol_name
255                 $MOUNT_PROG -o subvol=$subvol_name $btrfs_dev $subvol_mnt
256                 $UMOUNT_PROG $subvol_mnt
257                 $BTRFS_UTIL_PROG subvolume delete $btrfs_mnt/$subvol_name
258         done
259 }
260
261 # stress btrfs by running scrub in a loop
262 _btrfs_stress_scrub()
263 {
264         local btrfs_mnt=$1
265         while true; do
266                 $BTRFS_UTIL_PROG scrub start -B $btrfs_mnt
267         done
268 }
269
270 # stress btrfs by defragmenting every file/dir in a loop and compress file
271 # contents while defragmenting if second argument is not "nocompress"
272 _btrfs_stress_defrag()
273 {
274         local btrfs_mnt=$1
275         local compress=$2
276
277         while true; do
278                 if [ "$compress" == "nocompress" ]; then
279                         find $btrfs_mnt \( -type f -o -type d \) -exec \
280                         $BTRFS_UTIL_PROG filesystem defrag {} \;
281                 else
282                         find $btrfs_mnt \( -type f -o -type d \) -exec \
283                         $BTRFS_UTIL_PROG filesystem defrag -clzo {} \;
284                         find $btrfs_mnt \( -type f -o -type d \) -exec \
285                         $BTRFS_UTIL_PROG filesystem defrag -czlib {} \;
286                 fi
287         done
288 }
289
290 # stress btrfs by remounting it with different compression algorithms in a loop
291 # run this with fsstress running at background could exercise the compression
292 # code path and ensure no race when switching compression algorithm with constant
293 # I/O activity.
294 _btrfs_stress_remount_compress()
295 {
296         local btrfs_mnt=$1
297         while true; do
298                 for algo in no zlib lzo; do
299                         $MOUNT_PROG -o remount,compress=$algo $btrfs_mnt
300                 done
301         done
302 }
303
304 # stress btrfs by replacing devices in a loop
305 # Note that at least 3 devices are needed in SCRATCH_DEV_POOL and the last
306 # device should be free(not used by btrfs)
307 _btrfs_stress_replace()
308 {
309         local btrfs_mnt=$1
310
311         # The device number in SCRATCH_DEV_POOL should be at least 3,
312         # one is SCRATCH_DEV, one is to be replaced, one is free device
313         # we won't replace SCRATCH_DEV, see below for reason
314         if [ "`echo $SCRATCH_DEV_POOL | wc -w`" -lt 3 ]; then
315                 echo "_btrfs_stress_replace requires at least 3 devices in SCRATCH_DEV_POOL"
316                 return
317         fi
318
319         # take the last device as the first free_dev
320         local free_dev="`echo $SCRATCH_DEV_POOL | $AWK_PROG '{print $NF}'`"
321
322         # free_dev should be really free
323         if $BTRFS_UTIL_PROG filesystem show $btrfs_mnt | grep -q "$free_dev"; then
324                 echo "_btrfs_stress_replace: $free_dev is used by btrfs"
325                 return
326         fi
327
328         # dev_pool is device list being currently used by btrfs (excluding SCRATCH_DEV)
329         # and can be replaced. We don't replace SCRATCH_DEV because it will be used in
330         # _scratch_mount and _check_scratch_fs etc.
331         local dev_pool=`echo $SCRATCH_DEV_POOL | sed -e "s# *$SCRATCH_DEV *##" \
332                         -e "s# *$free_dev *##"`
333
334         # set the first device in dev_pool as the first src_dev to be replaced
335         local src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
336
337         echo "dev_pool=$dev_pool"
338         echo "free_dev=$free_dev, src_dev=$src_dev"
339         while true; do
340                 echo "Replacing $src_dev with $free_dev"
341                 $BTRFS_UTIL_PROG replace start -fB $src_dev $free_dev $btrfs_mnt
342                 if [ $? -ne 0 ]; then
343                         # don't update src_dev and free_dev if replace failed
344                         continue
345                 fi
346                 dev_pool="$dev_pool $free_dev"
347                 dev_pool=`echo $dev_pool | sed -e "s# *$src_dev *##"`
348                 free_dev=$src_dev
349                 src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
350         done
351 }
352
353 # find the right option to force output in bytes, older versions of btrfs-progs
354 # print that by default, newer print human readable numbers with unit suffix
355 _btrfs_qgroup_units()
356 {
357         $BTRFS_UTIL_PROG qgroup show --help 2>&1 | grep -q -- --raw && echo "--raw"
358 }
359
360 _btrfs_compression_algos()
361 {
362         echo zlib
363         for feature in /sys/fs/btrfs/features/compress_*; do
364                 echo "${feature#/sys/fs/btrfs/features/compress_}"
365         done
366 }
367
368 # run btrfs balance start with required --full-balance if available.
369 _run_btrfs_balance_start()
370 {
371         local bal_opt=""
372
373         $BTRFS_UTIL_PROG balance start --help | grep -q "full-balance"
374         (( $? == 0 )) && bal_opt="--full-balance"
375
376         run_check $BTRFS_UTIL_PROG balance start $bal_opt $*
377 }
378
379 #return the sector size of the btrfs scratch fs
380 _scratch_btrfs_sectorsize()
381 {
382         $BTRFS_UTIL_PROG inspect-internal dump-super $SCRATCH_DEV |\
383                 grep sectorsize | awk '{print $2}'
384 }
385
386 _btrfs_supports_forget()
387 {
388         $BTRFS_UTIL_PROG device scan --help | grep -wq forget && \
389                 $BTRFS_UTIL_PROG device scan --forget > /dev/null 2>&1
390 }
391
392 _require_btrfs_forget_or_module_loadable()
393 {
394         _btrfs_supports_forget && return
395
396         _require_loadable_fs_module "btrfs"
397 }
398
399 _btrfs_forget_or_module_reload()
400 {
401         _btrfs_supports_forget && return
402
403         _reload_fs_module "btrfs"
404 }