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