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