common/fuzzy: if the fuzz verb is random, keep fuzzing until we get a new value
[xfstests-dev.git] / common / inject
1 ##/bin/bash
2 # Routines for injecting errors into filesystems
3 #-----------------------------------------------------------------------
4 #  Copyright (c) 2016 Oracle.  All Rights Reserved.
5 #  This program is free software; you can redistribute it and/or modify
6 #  it under the terms of the GNU General Public License as published by
7 #  the Free Software Foundation; either version 2 of the License, or
8 #  (at your option) any later version.
9 #
10 #  This program is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #  GNU General Public License for more details.
14 #
15 #  You should have received a copy of the GNU General Public License
16 #  along with this program; if not, write to the Free Software
17 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18 #  USA
19 #
20 #  Contact information: Oracle Corporation, 500 Oracle Parkway,
21 #  Redwood Shores, CA 94065, USA, or: http://www.oracle.com/
22 #-----------------------------------------------------------------------
23 . ./common/log
24
25 # Tests whether $FSTYP is one of the filesystems that supports error injection
26 _require_error_injection()
27 {
28         case "$FSTYP" in
29         "xfs")
30                 grep -q 'debug 1' /proc/fs/xfs/stat || \
31                         _notrun "XFS error injection requires CONFIG_XFS_DEBUG"
32                 ;;
33         *)
34                 _notrun "Error injection not supported on filesystem type: $FSTYP"
35         esac
36 }
37
38 # Find the errortag injection knob in sysfs for a given xfs mount's
39 # block device.
40 _find_xfs_mountdev_errortag_knob()
41 {
42         dev="$1"
43         knob="$2"
44         shortdev="$(_short_dev "${dev}")"
45         tagfile="/sys/fs/xfs/${shortdev}/errortag/${knob}"
46
47         # Some of the new sysfs errortag knobs were previously available via
48         # another sysfs path.
49         case "${knob}" in
50         "log_bad_crc")
51                 if [ ! -w "${tagfile}" ]; then
52                         tagfile="/sys/fs/xfs/${shortdev}/log/log_badcrc_factor"
53                 fi
54                 ;;
55         "drop_writes")
56                 if [ ! -w "${tagfile}" ]; then
57                         tagfile="/sys/fs/xfs/${shortdev}/drop_writes"
58                 fi
59                 if [ ! -w "${tagfile}" ]; then
60                         tagfile="/sys/fs/xfs/${shortdev}/fail_writes"
61                 fi
62                 ;;
63         *)
64                 ;;
65         esac
66
67         echo "${tagfile}"
68 }
69
70 # Requires that xfs_io inject command knows about this error type
71 _require_xfs_io_error_injection()
72 {
73         type="$1"
74         _require_error_injection
75
76         # Can we find the error injection knobs via the new errortag
77         # configuration mechanism?
78         knob="$(_find_xfs_mountdev_errortag_knob "${TEST_DEV}" "${type}")"
79         test -w "${knob}" && return
80
81         # NOTE: We can't actually test error injection here because xfs
82         # hasn't always range checked the argument to xfs_errortag_add.
83         # We also don't want to trip an error before we're ready to deal
84         # with it.
85
86         $XFS_IO_PROG -x -c 'inject' $TEST_DIR | grep -q "$type" || \
87                 _notrun "XFS error injection $type unknown."
88 }
89
90 # Inject an error into the test fs
91 _test_inject_error()
92 {
93         type="$1"
94         value="$2"
95
96         knob="$(_find_xfs_mountdev_errortag_knob "${TEST_DEV}" "${type}")"
97         if [ -w "${knob}" ]; then
98                 test -z "${value}" && value="default"
99                 echo -n "${value}" > "${knob}"
100         elif [ -z "${value}" ] || [ "${value}" = "default" ]; then
101                 $XFS_IO_PROG -x -c "inject $type" $TEST_DIR
102         else
103                 _fail "Cannot inject error ${type} value ${value}."
104         fi
105 }
106
107 # Inject an error into the scratch fs
108 _scratch_inject_error()
109 {
110         type="$1"
111         value="$2"
112
113         knob="$(_find_xfs_mountdev_errortag_knob "${SCRATCH_DEV}" "${type}")"
114         if [ -w "${knob}" ]; then
115                 test -z "${value}" && value="default"
116                 echo -n "${value}" > "${knob}"
117         elif [ -z "${value}" ] || [ "${value}" = "default" ]; then
118                 $XFS_IO_PROG -x -c "inject $type" $SCRATCH_MNT
119         else
120                 _fail "Cannot inject error ${type} value ${value}."
121         fi
122 }
123
124 # Unmount and remount the scratch device, dumping the log
125 _scratch_inject_logprint()
126 {
127         local opts="$1"
128
129         if test -n "$opts"; then
130                 opts="-o $opts"
131         fi
132         _scratch_unmount
133         _scratch_dump_log
134         _scratch_mount "$opts"
135 }
136
137 # Unmount and remount the test device, dumping the log
138 _test_inject_logprint()
139 {
140         local opts="$1"
141
142         if test -n "$opts"; then
143                 opts="-o $opts"
144         fi
145         _test_unmount
146         _test_dump_log
147         _test_mount "$opts"
148 }