• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/bash
2
3# Test harness to fuzz a filesystem over and over...
4# Copyright (C) 2014 Oracle.
5
6DIR=/tmp
7PASSES=10000
8SZ=32m
9SCRIPT_DIR="$(dirname "$0")"
10FEATURES="has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit,metadata_csum,bigalloc,sparse_super2,inline_data"
11BLK_SZ=4096
12INODE_SZ=256
13EXTENDED_OPTS="discard"
14EXTENDED_FSCK_OPTIONS=""
15RUN_FSCK=1
16OVERRIDE_PATH=1
17HAS_FUSE2FS=0
18USE_FUSE2FS=0
19MAX_FSCK=10
20SRCDIR=/etc
21test -x "${SCRIPT_DIR}/fuse2fs" && HAS_FUSE2FS=1
22
23print_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
42GETOPT="d:n:s:O:I:b:B:E:F:fpx:S:"
43test "${HAS_FUSE2FS}" && GETOPT="${GETOPT}u"
44
45while 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
93done
94
95if [ "${OVERRIDE_PATH}" -gt 0 ]; then
96	PATH="${SCRIPT_DIR}:${SCRIPT_DIR}/../e2fsck/:${PATH}"
97	export PATH
98fi
99
100TESTDIR="${DIR}/tests/"
101TESTMNT="${DIR}/mnt/"
102BASE_IMG="${DIR}/e2fuzz.img"
103
104cat > /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}
114ENDL
115MKE2FS_CONFIG=/tmp/mke2fs.conf
116export MKE2FS_CONFIG
117
118# Set up FS image
119echo "+ create fs image"
120umount "${TESTDIR}"
121umount "${TESTMNT}"
122rm -rf "${TESTDIR}"
123rm -rf "${TESTMNT}"
124mkdir -p "${TESTDIR}"
125mkdir -p "${TESTMNT}"
126rm -rf "${BASE_IMG}"
127truncate -s "${SZ}" "${BASE_IMG}"
128mke2fs -F -v "${BASE_IMG}"
129if [ $? -ne 0 ]; then
130	exit $?
131fi
132
133# Populate FS image
134echo "+ populate fs image"
135modprobe loop
136mount "${BASE_IMG}" "${TESTMNT}" -o loop
137if [ $? -ne 0 ]; then
138	exit $?
139fi
140SRC_SZ="$(du -ks "${SRCDIR}" | awk '{print $1}')"
141FS_SZ="$(( $(stat -f "${TESTMNT}" -c '%a * %S') / 1024 ))"
142NR="$(( (FS_SZ * 4 / 10) / SRC_SZ ))"
143if [ "${NR}" -lt 1 ]; then
144	NR=1
145fi
146echo "+ make ${NR} copies"
147seq 1 "${NR}" | while read nr; do
148	cp -pRdu "${SRCDIR}" "${TESTMNT}/test.${nr}" 2> /dev/null
149done
150umount "${TESTMNT}"
151e2fsck -fn "${BASE_IMG}"
152if [ $? -ne 0 ]; then
153	echo "fsck failed??"
154	exit 1
155fi
156
157# Run tests
158echo "+ run test"
159ret=0
160seq 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
325done
326
327exit $ret
328