btrfs/220: fix how we tests for mount options
[xfstests-dev.git] / tests / btrfs / 220
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (C) 2020 SUSE Linux Products GmbH. All Rights Reserved.
4 #
5 # FS QA Test 220
6 #
7 # Test all existent mount options of btrfs
8 # * device= argument is already being test by btrfs/125
9 # * space cache test already covered by test btrfs/131
10 seq=`basename $0`
11 seqres=$RESULT_DIR/$seq
12 echo "QA output created by $seq"
13
14 here=`pwd`
15 tmp=/tmp/$$
16 status=1        # failure is the default!
17 trap "cleanup; exit \$status" 0 1 2 3 15
18
19 # get standard environment, filters and checks
20 . ./common/rc
21 . ./common/filter
22
23 # remove previous $seqres.full before test
24 rm -f $seqres.full
25
26 _supported_fs btrfs
27 _require_scratch
28
29 cleanup()
30 {
31         cd /
32         rm -f $tmp.*
33 }
34
35 # Compare the mounted flags with $opt_check. When the comparison fails, $opt is
36 # echoed to help to track which option was used to trigger the unexpected
37 # results.
38 test_mount_flags()
39 {
40         local opt
41         local opt_check
42         local stripped
43         opt="$1"
44         opt_check="$2"
45
46         active_opt=$(cat /proc/self/mounts | grep $SCRATCH_MNT | \
47                                         $AWK_PROG '{ print $4 }')
48
49         if [ "$opt_check" != "$DEFAULT_OPTS" ]; then
50                 # We only care about the common things between defaults and the
51                 # active set, so strip out the uniq lines between the two, and
52                 # then we'll add this to our $opt_check which should equal
53                 # $active_opt.  We also strip 'rw' as we may be checking 'ro',
54                 # so we need to adjust that accordingly
55                 stripped=$(echo "$DEFAULT_OPTS,$active_opt" | tr ',' '\n' | \
56                                 sort | grep -v 'rw' | uniq -d | tr '\n' ',' | \
57                                 sed 's/.$//')
58                 opt_check="$opt_check,$stripped"
59         fi
60
61         # We diff by putting our wanted opts together with the current opts,
62         # turning it into one option per line, sort'ing, and then printing out
63         # any uniq lines left.  This will catch anything that is set that we're
64         # not expecting, or anything that wasn't set that we wanted.
65         #
66         # We strip 'rw' because some tests flip ro, so just ignore rw.
67         diff=$(echo "$opt_check,$active_opt" | tr ',' '\n' | \
68                 sort | grep -v 'rw' | uniq -u)
69         if [ -n "$diff" ]; then
70                 echo "Unexepcted mount options, checking for '$opt_check' in '$active_opt' using '$opt'"
71         fi
72 }
73
74 # Mounts using opt ($1), remounts using remount_opt ($2), and remounts again
75 # using opt again (1), checking if the mount opts are being enabled/disabled by
76 # using _check arguments ($3 and $4)
77 test_enable_disable_mount_opt()
78 {
79         local opt
80         local opt_check
81         local remount_opt
82         local remount_opt_check
83         opt="$1"
84         opt_check="$2"
85         remount_opt="$3"
86         remount_opt_check="$4"
87
88         _scratch_mount "-o $opt"
89
90         test_mount_flags $opt $opt_check
91
92         _scratch_remount $remount_opt
93
94         test_mount_flags $remount_opt $remount_opt_check
95
96         _scratch_remount $opt
97
98         test_mount_flags $opt $opt_check
99
100         _scratch_unmount
101 }
102
103 # Checks if mount options are applied and reverted correctly.
104 # By using options to mount ($1) and remount ($2), this function will mount,
105 # remount, and the mount with the original args, checking if the mount options
106 # match the _check args ($3 and $4).
107
108 # Later, opt and remount_opt are swapped, testing the counterpart option if used
109 # to first mount the fs.
110 test_roundtrip_mount()
111 {
112         local opt
113         local opt_check
114         local remount_opt
115         local remount_opt_check
116         opt="$1"
117         opt_check="$2"
118         remount_opt="$3"
119         remount_opt_check="$4"
120
121         # invert the args to make sure that both options work at mount and
122         # remount time
123         test_enable_disable_mount_opt $opt $opt_check $remount_opt $remount_opt_check
124         test_enable_disable_mount_opt $remount_opt $remount_opt_check $opt $opt_check
125 }
126
127 # Just mount and check if the options were mounted correctly by comparing the
128 # results with $opt_check
129 test_mount_opt()
130 {
131         local opt
132         local opt_check
133         local active_opt
134         opt="$1"
135         opt_check="$2"
136
137         _scratch_mount "-o $opt"
138
139         test_mount_flags $opt $opt_check
140
141         _scratch_unmount
142 }
143
144 # Test mount options that should fail, usually by wrong arguments to options
145 test_should_fail()
146 {
147         local opt
148         opt="$1"
149
150         # wrong $opt on purpose, should fail
151         _try_scratch_mount "-o $opt" >/dev/null 2>&1
152         if [ $? -ne 0 ]; then
153                 return
154         fi
155         echo "Option $opt should fail to mount"
156         _scratch_unmount
157 }
158
159 # Try to mount using $opt, and bail our if the mount fails without errors. If
160 # the mount succeeds, then compare the mount options with $opt_check
161 test_optional_mount_opts()
162 {
163         local opt
164         local opt_check
165         opt="$1"
166         opt_check="$2"
167
168         # $opt not enabled, return without running any tests
169         _try_scratch_mount "-o $opt" >/dev/null 2>&1 || return
170         _scratch_unmount
171
172         # option enabled, run the test
173         test_mount_opt $opt $opt_check
174 }
175
176 # Testes related to subvolumes, from subvol and subvolid options.
177 test_subvol()
178 {
179         test_should_fail "subvol=vol2"
180
181         _scratch_mount "-o subvol=vol1"
182         if [ ! -f "$SCRATCH_MNT/file.txt" ]; then
183                 echo "file.txt not found inside vol1 using subvol=vol1 mount option"
184         fi
185         _scratch_unmount
186
187         test_should_fail "subvolid=222"
188
189         _scratch_mount "-o subvolid=256"
190         if [ ! -f "$SCRATCH_MNT/file.txt" ]; then
191                 echo "file.txt not found inside vol1 using subvolid=256 mount option"
192         fi
193         _scratch_unmount
194
195         # subvol and subvolid should point to the same subvolume
196         test_should_fail "-o subvol=vol1,subvolid=1234132"
197
198         test_mount_opt "subvol=vol1,subvolid=256" "subvolid=256,subvol=/vol1"
199         test_roundtrip_mount "subvol=vol1" "subvolid=256,subvol=/vol1" "subvolid=256" "subvolid=256,subvol=/vol1"
200 }
201
202 # These options are enable at kernel compile time, so no bother if they fail
203 test_optional_kernel_features()
204 {
205         # Test options that are enabled by kernel config, and so can fail safely
206         test_optional_mount_opts "check_int" "check_int"
207         test_optional_mount_opts "check_int_data" "check_int_data"
208         test_optional_mount_opts "check_int_print_mask=123" "check_int_print_mask=123"
209
210         test_should_fail "fragment=invalid"
211         test_optional_mount_opts "fragment=all" "fragment=data,fragment=metadata"
212         test_optional_mount_opts "fragment=data" "fragment=data"
213         test_optional_mount_opts "fragment=metadata" "fragment=metadata"
214 }
215
216 test_non_revertible_options()
217 {
218         test_mount_opt "clear_cache" "clear_cache"
219         test_mount_opt "degraded" "degraded"
220
221         test_mount_opt "inode_cache" "inode_cache"
222
223         # nologreplay should be used only with
224         test_should_fail "nologreplay"
225         test_mount_opt "nologreplay,ro" "ro,rescue=nologreplay"
226
227         # norecovery should be used only with. This options is an alias to nologreplay
228         test_should_fail "norecovery"
229         test_mount_opt "norecovery,ro" "ro,rescue=nologreplay"
230         test_mount_opt "rescan_uuid_tree" "rescan_uuid_tree"
231         test_mount_opt "skip_balance" "skip_balance"
232         test_mount_opt "user_subvol_rm_allowed" "user_subvol_rm_allowed"
233
234         test_should_fail "rescue=invalid"
235
236         # nologreplay requires readonly
237         test_should_fail "rescue=nologreplay"
238         test_mount_opt "rescue=nologreplay,ro" "ro,rescue=nologreplay"
239 }
240
241 # All these options can be reverted (with their "no" counterpart), or can have
242 # their values set to default on remount
243 test_revertible_options()
244 {
245         test_roundtrip_mount "acl" "$DEFAULT_OPTS" "noacl" "noacl"
246         test_roundtrip_mount "autodefrag" "autodefrag" "noautodefrag" "$DEFAULT_OPTS"
247         test_roundtrip_mount "barrier" "$DEFAULT_OPTS" "nobarrier" "nobarrier"
248
249         test_should_fail "commit=-10"
250         # commit=0 sets the default, so btrfs hides this mount opt
251         test_roundtrip_mount "commit=35" "commit=35" "commit=0" "$DEFAULT_OPTS"
252
253         test_should_fail "compress=invalid"
254         test_should_fail "compress-force=invalid"
255         test_roundtrip_mount "compress" "compress=zlib:3" "compress=lzo" "compress=lzo"
256         test_roundtrip_mount "compress=zstd" "compress=zstd:3" "compress=no" "$DEFAULT_OPTS"
257         test_roundtrip_mount "compress-force=no" "$DEFAULT_OPTS" "compress-force=zstd" "compress-force=zstd:3"
258         # zlib's max level is 9 and zstd's max level is 15
259         test_roundtrip_mount "compress=zlib:20" "compress=zlib:9" "compress=zstd:16" "compress=zstd:15"
260         test_roundtrip_mount "compress-force=lzo" "compress-force=lzo" "compress-force=zlib:4" "compress-force=zlib:4"
261
262         # on remount, if we only pass datacow after nodatacow was used it will remain with nodatasum
263         test_roundtrip_mount "nodatacow" "nodatasum,nodatacow" "datacow,datasum" "$DEFAULT_OPTS"
264         # nodatacow disabled compression
265         test_roundtrip_mount "compress-force" "compress-force=zlib:3" "nodatacow" "nodatasum,nodatacow"
266
267         # nodatacow disabled both datacow and datasum, and datasum enabled datacow and datasum
268         test_roundtrip_mount "nodatacow" "nodatasum,nodatacow" "datasum" "$DEFAULT_OPTS"
269         test_roundtrip_mount "nodatasum" "nodatasum" "datasum" "$DEFAULT_OPTS"
270
271         test_should_fail "discard=invalid"
272         test_roundtrip_mount "discard" "discard" "discard=sync" "discard"
273         test_roundtrip_mount "discard=async" "discard=async" "discard=sync" "discard"
274         test_roundtrip_mount "discard=sync" "discard" "nodiscard" "$DEFAULT_OPTS"
275
276         test_roundtrip_mount "enospc_debug" "enospc_debug" "noenospc_debug" "$DEFAULT_OPTS"
277
278         test_should_fail "fatal_errors=pani"
279         # fatal_errors=bug is the default
280         test_roundtrip_mount "fatal_errors=panic" "fatal_errors=panic" "fatal_errors=bug" "$DEFAULT_OPTS"
281
282         test_roundtrip_mount "flushoncommit" "flushoncommit" "noflushoncommit" "$DEFAULT_OPTS"
283
284         # 2048 is the max_inline default value
285         test_roundtrip_mount "max_inline=1024" "max_inline=1024" "max_inline=2048" "$DEFAULT_OPTS"
286
287         test_roundtrip_mount "metadata_ratio=0" "$DEFAULT_OPTS" "metadata_ratio=10" "metadata_ratio=10"
288
289         # ssd_spread implies ssd, while nossd_spread only disables ssd_spread
290         test_roundtrip_mount "ssd_spread" "ssd_spread" "nossd" "nossd"
291         test_roundtrip_mount "ssd" "ssd" "nossd" "nossd"
292         test_mount_opt "ssd" "ssd"
293
294         test_should_fail "thread_pool=-10"
295         test_should_fail "thread_pool=0"
296         test_roundtrip_mount "thread_pool=10" "thread_pool=10" "thread_pool=50" "thread_pool=50"
297
298         test_roundtrip_mount "notreelog" "notreelog" "treelog" "$DEFAULT_OPTS"
299 }
300
301 # real QA test starts here
302 _scratch_mkfs >/dev/null
303
304 # This test checks mount options, so having random MOUNT_OPTIONS set could
305 # affect the results of a few of these tests.
306 MOUNT_OPTIONS=
307
308 # create a subvolume that will be used later
309 _scratch_mount
310
311 # We need to save the current default options so we can validate our changes
312 # from one mount option to the next one.
313 DEFAULT_OPTS=$(cat /proc/self/mounts | grep $SCRATCH_MNT | \
314                 $AWK_PROG '{ print $4 }')
315
316 $BTRFS_UTIL_PROG subvolume create "$SCRATCH_MNT/vol1" > /dev/null
317 touch "$SCRATCH_MNT/vol1/file.txt"
318 _scratch_unmount
319
320 test_optional_kernel_features
321
322 test_non_revertible_options
323
324 test_revertible_options
325
326 test_subvol
327
328 echo "Silence is golden"
329
330 status=0
331 exit