]>
Commit | Line | Data |
---|---|---|
c4d5b81e DW |
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})" | |
be2ad9ed | 37 | echo "-x: Run e2fsck at most this many times. (${MAX_FSCK})" |
c4d5b81e DW |
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 ))" | |
e0d5dd36 | 142 | NR="$(( (FS_SZ * 4 / 10) / SRC_SZ ))" |
c4d5b81e DW |
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" | |
be2ad9ed | 195 | find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do |
c4d5b81e | 196 | attr -l "$f" > /dev/null 2>> "${OPS_LOG}" |
c4d5b81e DW |
197 | if [ -f "$f" -a -w "$f" ]; then |
198 | dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}" | |
199 | fi | |
be2ad9ed | 200 | mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" |
c4d5b81e DW |
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}" | |
fac0c8ea | 222 | pass_img_sz="$(stat -c '%s' "${PASS_IMG}")" |
c4d5b81e DW |
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 | |
fac0c8ea DW |
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 | |
c4d5b81e DW |
260 | done |
261 | fsck_loop_ret=$? | |
262 | if [ "${fsck_loop_ret}" -gt 0 ]; then | |
263 | break; | |
264 | fi | |
265 | fi | |
e0d5dd36 DW |
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 | |
c4d5b81e DW |
324 | rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" "${TESTDIR}"/e2fuzz*.log |
325 | done | |
326 | ||
327 | exit $ret |