Whamcloud - gitweb
e2fsck: map PROMPT_* values to prompt messages
[tools/e2fsprogs.git] / misc / e2fuzz.sh
1 #!/bin/bash
2
3 # Test harness to fuzz a filesystem over and over...
4 # Copyright (C) 2014 Oracle.
5
6 DIR=/tmp
7 PASSES=10000
8 SZ=32m
9 SCRIPT_DIR="$(dirname "$0")"
10 FEATURES="has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit,metadata_csum,bigalloc,sparse_super2,inline_data"
11 BLK_SZ=4096
12 INODE_SZ=256
13 EXTENDED_OPTS="discard"
14 EXTENDED_FSCK_OPTIONS=""
15 RUN_FSCK=1
16 OVERRIDE_PATH=1
17 HAS_FUSE2FS=0
18 USE_FUSE2FS=0
19 MAX_FSCK=10
20 SRCDIR=/etc
21 test -x "${SCRIPT_DIR}/fuse2fs" && HAS_FUSE2FS=1
22
23 print_help() {
24         echo "Usage: $0 OPTIONS"
25         echo "-b:       FS block size is this. (${BLK_SZ})"
26         echo "-B:       Corrupt this many bytes per run."
27         echo "-d:       Create test files in this directory. (${DIR})"
28         echo "-E:       Extended mke2fs options."
29         echo "-f:       Do not run e2fsck after each pass."
30         echo "-F:       Extended e2fsck options."
31         echo "-I:       Create inodes of this size. (${INODE_SZ})"
32         echo "-n:       Run this many passes. (${PASSES})"
33         echo "-O:       Create FS with these features."
34         echo "-p:       Use system's mke2fs/e2fsck/tune2fs tools."
35         echo "-s:       Create FS images of this size. (${SZ})"
36         echo "-S:       Copy files from this dir. (${SRCDIR})"
37         echo "-x:       Run e2fsck at most this many times. (${MAX_FSCK})"
38         test "${HAS_FUSE2FS}" -gt 0 && echo "-u:        Use fuse2fs instead of the kernel."
39         exit 0
40 }
41
42 GETOPT="d:n:s:O:I:b:B:E:F:fpx:S:"
43 test "${HAS_FUSE2FS}" && GETOPT="${GETOPT}u"
44
45 while getopts "${GETOPT}" opt; do
46         case "${opt}" in
47         "B")
48                 E2FUZZ_ARGS="${E2FUZZ_ARGS} -b ${OPTARG}"
49                 ;;
50         "d")
51                 DIR="${OPTARG}"
52                 ;;
53         "n")
54                 PASSES="${OPTARG}"
55                 ;;
56         "s")
57                 SZ="${OPTARG}"
58                 ;;
59         "O")
60                 FEATURES="${FEATURES},${OPTARG}"
61                 ;;
62         "I")
63                 INODE_SZ="${OPTARG}"
64                 ;;
65         "b")
66                 BLK_SZ="${OPTARG}"
67                 ;;
68         "E")
69                 EXTENDED_OPTS="${OPTARG}"
70                 ;;
71         "F")
72                 EXTENDED_FSCK_OPTS="-E ${OPTARG}"
73                 ;;
74         "f")
75                 RUN_FSCK=0
76                 ;;
77         "p")
78                 OVERRIDE_PATH=0
79                 ;;
80         "u")
81                 USE_FUSE2FS=1
82                 ;;
83         "x")
84                 MAX_FSCK="${OPTARG}"
85                 ;;
86         "S")
87                 SRCDIR="${OPTARG}"
88                 ;;
89         *)
90                 print_help
91                 ;;
92         esac
93 done
94
95 if [ "${OVERRIDE_PATH}" -gt 0 ]; then
96         PATH="${SCRIPT_DIR}:${SCRIPT_DIR}/../e2fsck/:${PATH}"
97         export PATH
98 fi
99
100 TESTDIR="${DIR}/tests/"
101 TESTMNT="${DIR}/mnt/"
102 BASE_IMG="${DIR}/e2fuzz.img"
103
104 cat > /tmp/mke2fs.conf << ENDL
105 [defaults]
106         base_features = ${FEATURES}
107         default_mntopts = acl,user_xattr,block_validity
108         enable_periodic_fsck = 0
109         blocksize = ${BLK_SZ}
110         inode_size = ${INODE_SZ}
111         inode_ratio = 4096
112         cluster_size = $((BLK_SZ * 2))
113         options = ${EXTENDED_OPTS}
114 ENDL
115 MKE2FS_CONFIG=/tmp/mke2fs.conf
116 export MKE2FS_CONFIG
117
118 # Set up FS image
119 echo "+ create fs image"
120 umount "${TESTDIR}"
121 umount "${TESTMNT}"
122 rm -rf "${TESTDIR}"
123 rm -rf "${TESTMNT}"
124 mkdir -p "${TESTDIR}"
125 mkdir -p "${TESTMNT}"
126 rm -rf "${BASE_IMG}"
127 truncate -s "${SZ}" "${BASE_IMG}"
128 mke2fs -F -v "${BASE_IMG}"
129 if [ $? -ne 0 ]; then
130         exit $?
131 fi
132
133 # Populate FS image
134 echo "+ populate fs image"
135 modprobe loop
136 mount "${BASE_IMG}" "${TESTMNT}" -o loop
137 if [ $? -ne 0 ]; then
138         exit $?
139 fi
140 SRC_SZ="$(du -ks "${SRCDIR}" | awk '{print $1}')"
141 FS_SZ="$(( $(stat -f "${TESTMNT}" -c '%a * %S') / 1024 ))"
142 NR="$(( (FS_SZ * 4 / 10) / SRC_SZ ))"
143 if [ "${NR}" -lt 1 ]; then
144         NR=1
145 fi
146 echo "+ make ${NR} copies"
147 seq 1 "${NR}" | while read nr; do
148         cp -pRdu "${SRCDIR}" "${TESTMNT}/test.${nr}" 2> /dev/null
149 done
150 umount "${TESTMNT}"
151 e2fsck -fn "${BASE_IMG}"
152 if [ $? -ne 0 ]; then
153         echo "fsck failed??"
154         exit 1
155 fi
156
157 # Run tests
158 echo "+ run test"
159 ret=0
160 seq 1 "${PASSES}" | while read pass; do
161         echo "+ pass ${pass}"
162         PASS_IMG="${TESTDIR}/e2fuzz-${pass}.img"
163         FSCK_IMG="${TESTDIR}/e2fuzz-${pass}.fsck"
164         FUZZ_LOG="${TESTDIR}/e2fuzz-${pass}.fuzz.log"
165         OPS_LOG="${TESTDIR}/e2fuzz-${pass}.ops.log"
166
167         echo "++ corrupt image"
168         cp "${BASE_IMG}" "${PASS_IMG}"
169         if [ $? -ne 0 ]; then
170                 exit $?
171         fi
172         tune2fs -L "e2fuzz-${pass}" "${PASS_IMG}"
173         e2fuzz -v "${PASS_IMG}" ${E2FUZZ_ARGS} > "${FUZZ_LOG}"
174         if [ $? -ne 0 ]; then
175                 exit $?
176         fi
177
178         echo "++ mount image"
179         if [ "${USE_FUSE2FS}" -gt 0 ]; then
180                 "${SCRIPT_DIR}/fuse2fs" "${PASS_IMG}" "${TESTMNT}"
181                 res=$?
182         else
183                 mount "${PASS_IMG}" "${TESTMNT}" -o loop
184                 res=$?
185         fi
186
187         if [ "${res}" -eq 0 ]; then
188                 echo "+++ ls -laR"
189                 ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}"
190
191                 echo "+++ cat files"
192                 find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}"
193
194                 echo "+++ expand"
195                 find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do
196                         attr -l "$f" > /dev/null 2>> "${OPS_LOG}"
197                         if [ -f "$f" -a -w "$f" ]; then
198                                 dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}"
199                         fi
200                         mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}"
201                 done
202                 sync
203
204                 echo "+++ create files"
205                 cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
206                 sync
207
208                 echo "+++ remove files"
209                 rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
210
211                 umount "${TESTMNT}"
212                 res=$?
213                 if [ "${res}" -ne 0 ]; then
214                         ret=1
215                         break
216                 fi
217                 sync
218                 test "${USE_FUSE2FS}" -gt 0 && sleep 2
219         fi
220         if [ "${RUN_FSCK}" -gt 0 ]; then
221                 cp "${PASS_IMG}" "${FSCK_IMG}"
222                 pass_img_sz="$(stat -c '%s' "${PASS_IMG}")"
223
224                 seq 1 "${MAX_FSCK}" | while read fsck_pass; do
225                         echo "++ fsck pass ${fsck_pass}: $(which e2fsck) -fy ${FSCK_IMG} ${EXTENDED_FSCK_OPTS}"
226                         FSCK_LOG="${TESTDIR}/e2fuzz-${pass}-${fsck_pass}.log"
227                         e2fsck -fy "${FSCK_IMG}" ${EXTENDED_FSCK_OPTS} > "${FSCK_LOG}" 2>&1
228                         res=$?
229                         echo "++ fsck returns ${res}"
230                         if [ "${res}" -eq 0 ]; then
231                                 exit 0
232                         elif [ "${fsck_pass}" -eq "${MAX_FSCK}" ]; then
233                                 echo "++ fsck did not fix in ${MAX_FSCK} passes."
234                                 exit 1
235                         fi
236                         if [ "${res}" -gt 0 -a \
237                              "$(grep 'Memory allocation failed' "${FSCK_LOG}" | wc -l)" -gt 0 ]; then
238                                 echo "++ Ran out of memory, get more RAM"
239                                 exit 0
240                         fi
241                         if [ "${res}" -gt 0 -a \
242                              "$(grep 'Could not allocate block' "${FSCK_LOG}" | wc -l)" -gt 0 -a \
243                              "$(dumpe2fs -h "${FSCK_IMG}" | grep '^Free blocks:' | awk '{print $3}')0" -eq 0 ]; then
244                                 echo "++ Ran out of space, get a bigger image"
245                                 exit 0
246                         fi
247                         if [ "${fsck_pass}" -gt 1 ]; then
248                                 diff -u "${TESTDIR}/e2fuzz-${pass}-$((fsck_pass - 1)).log" "${FSCK_LOG}"
249                                 if [ $? -eq 0 ]; then
250                                         echo "++ fsck makes no progress"
251                                         exit 2
252                                 fi
253                         fi
254
255                         fsck_img_sz="$(stat -c '%s' "${FSCK_IMG}")"
256                         if [ "${fsck_img_sz}" -ne "${pass_img_sz}" ]; then
257                                 echo "++ fsck image size changed"
258                                 exit 3
259                         fi
260                 done
261                 fsck_loop_ret=$?
262                 if [ "${fsck_loop_ret}" -gt 0 ]; then
263                         break;
264                 fi
265         fi
266
267         echo "+++ check fs for round 2"
268         FSCK_LOG="${TESTDIR}/e2fuzz-${pass}-round2.log"
269         e2fsck -fn "${FSCK_IMG}" ${EXTENDED_FSCK_OPTS} >> "${FSCK_LOG}" 2>&1
270         res=$?
271         if [ "${res}" -ne 0 ]; then
272                 echo "++++ fsck failed."
273                 exit 1
274         fi
275
276         echo "++ mount image (2)"
277         mount "${FSCK_IMG}" "${TESTMNT}" -o loop
278         res=$?
279
280         if [ "${res}" -eq 0 ]; then
281                 echo "+++ ls -laR (2)"
282                 ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}"
283
284                 echo "+++ cat files (2)"
285                 find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}"
286
287                 echo "+++ expand (2)"
288                 find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do
289                         attr -l "$f" > /dev/null 2>> "${OPS_LOG}"
290                         if [ -f "$f" -a -w "$f" ]; then
291                                 dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}"
292                         fi
293                         mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}"
294                 done
295                 sync
296
297                 echo "+++ create files (2)"
298                 cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
299                 sync
300
301                 echo "+++ remove files (2)"
302                 rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
303
304                 umount "${TESTMNT}"
305                 res=$?
306                 if [ "${res}" -ne 0 ]; then
307                         ret=1
308                         break
309                 fi
310                 sync
311                 test "${USE_FUSE2FS}" -gt 0 && sleep 2
312
313                 echo "+++ check fs (2)"
314                 e2fsck -fn "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1
315                 res=$?
316                 if [ "${res}" -ne 0 ]; then
317                         echo "++ fsck failed."
318                         exit 1
319                 fi
320         else
321                 echo "++ mount(2) failed with ${res}"
322                 exit 1
323         fi
324         rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" "${TESTDIR}"/e2fuzz*.log
325 done
326
327 exit $ret