summaryrefslogtreecommitdiffstats
path: root/misc/e2fuzz.sh
diff options
context:
space:
mode:
Diffstat (limited to 'misc/e2fuzz.sh')
-rwxr-xr-xmisc/e2fuzz.sh327
1 files changed, 327 insertions, 0 deletions
diff --git a/misc/e2fuzz.sh b/misc/e2fuzz.sh
new file mode 100755
index 0000000..389f2ca
--- /dev/null
+++ b/misc/e2fuzz.sh
@@ -0,0 +1,327 @@
+#!/bin/bash
+
+# Test harness to fuzz a filesystem over and over...
+# Copyright (C) 2014 Oracle.
+
+DIR=/tmp
+PASSES=10000
+SZ=32m
+SCRIPT_DIR="$(dirname "$0")"
+FEATURES="has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit,metadata_csum,bigalloc,sparse_super2,inline_data"
+BLK_SZ=4096
+INODE_SZ=256
+EXTENDED_OPTS="discard"
+EXTENDED_FSCK_OPTIONS=""
+RUN_FSCK=1
+OVERRIDE_PATH=1
+HAS_FUSE2FS=0
+USE_FUSE2FS=0
+MAX_FSCK=10
+SRCDIR=/etc
+test -x "${SCRIPT_DIR}/fuse2fs" && HAS_FUSE2FS=1
+
+print_help() {
+ echo "Usage: $0 OPTIONS"
+ echo "-b: FS block size is this. (${BLK_SZ})"
+ echo "-B: Corrupt this many bytes per run."
+ echo "-d: Create test files in this directory. (${DIR})"
+ echo "-E: Extended mke2fs options."
+ echo "-f: Do not run e2fsck after each pass."
+ echo "-F: Extended e2fsck options."
+ echo "-I: Create inodes of this size. (${INODE_SZ})"
+ echo "-n: Run this many passes. (${PASSES})"
+ echo "-O: Create FS with these features."
+ echo "-p: Use system's mke2fs/e2fsck/tune2fs tools."
+ echo "-s: Create FS images of this size. (${SZ})"
+ echo "-S: Copy files from this dir. (${SRCDIR})"
+ echo "-x: Run e2fsck at most this many times. (${MAX_FSCK})"
+ test "${HAS_FUSE2FS}" -gt 0 && echo "-u: Use fuse2fs instead of the kernel."
+ exit 0
+}
+
+GETOPT="d:n:s:O:I:b:B:E:F:fpx:S:"
+test "${HAS_FUSE2FS}" && GETOPT="${GETOPT}u"
+
+while getopts "${GETOPT}" opt; do
+ case "${opt}" in
+ "B")
+ E2FUZZ_ARGS="${E2FUZZ_ARGS} -b ${OPTARG}"
+ ;;
+ "d")
+ DIR="${OPTARG}"
+ ;;
+ "n")
+ PASSES="${OPTARG}"
+ ;;
+ "s")
+ SZ="${OPTARG}"
+ ;;
+ "O")
+ FEATURES="${FEATURES},${OPTARG}"
+ ;;
+ "I")
+ INODE_SZ="${OPTARG}"
+ ;;
+ "b")
+ BLK_SZ="${OPTARG}"
+ ;;
+ "E")
+ EXTENDED_OPTS="${OPTARG}"
+ ;;
+ "F")
+ EXTENDED_FSCK_OPTS="-E ${OPTARG}"
+ ;;
+ "f")
+ RUN_FSCK=0
+ ;;
+ "p")
+ OVERRIDE_PATH=0
+ ;;
+ "u")
+ USE_FUSE2FS=1
+ ;;
+ "x")
+ MAX_FSCK="${OPTARG}"
+ ;;
+ "S")
+ SRCDIR="${OPTARG}"
+ ;;
+ *)
+ print_help
+ ;;
+ esac
+done
+
+if [ "${OVERRIDE_PATH}" -gt 0 ]; then
+ PATH="${SCRIPT_DIR}:${SCRIPT_DIR}/../e2fsck/:${PATH}"
+ export PATH
+fi
+
+TESTDIR="${DIR}/tests/"
+TESTMNT="${DIR}/mnt/"
+BASE_IMG="${DIR}/e2fuzz.img"
+
+cat > /tmp/mke2fs.conf << ENDL
+[defaults]
+ base_features = ${FEATURES}
+ default_mntopts = acl,user_xattr,block_validity
+ enable_periodic_fsck = 0
+ blocksize = ${BLK_SZ}
+ inode_size = ${INODE_SZ}
+ inode_ratio = 4096
+ cluster_size = $((BLK_SZ * 2))
+ options = ${EXTENDED_OPTS}
+ENDL
+MKE2FS_CONFIG=/tmp/mke2fs.conf
+export MKE2FS_CONFIG
+
+# Set up FS image
+echo "+ create fs image"
+umount "${TESTDIR}"
+umount "${TESTMNT}"
+rm -rf "${TESTDIR}"
+rm -rf "${TESTMNT}"
+mkdir -p "${TESTDIR}"
+mkdir -p "${TESTMNT}"
+rm -rf "${BASE_IMG}"
+truncate -s "${SZ}" "${BASE_IMG}"
+mke2fs -F -v "${BASE_IMG}"
+if [ $? -ne 0 ]; then
+ exit $?
+fi
+
+# Populate FS image
+echo "+ populate fs image"
+modprobe loop
+mount "${BASE_IMG}" "${TESTMNT}" -o loop
+if [ $? -ne 0 ]; then
+ exit $?
+fi
+SRC_SZ="$(du -ks "${SRCDIR}" | awk '{print $1}')"
+FS_SZ="$(( $(stat -f "${TESTMNT}" -c '%a * %S') / 1024 ))"
+NR="$(( (FS_SZ * 4 / 10) / SRC_SZ ))"
+if [ "${NR}" -lt 1 ]; then
+ NR=1
+fi
+echo "+ make ${NR} copies"
+seq 1 "${NR}" | while read nr; do
+ cp -pRdu "${SRCDIR}" "${TESTMNT}/test.${nr}" 2> /dev/null
+done
+umount "${TESTMNT}"
+e2fsck -fn "${BASE_IMG}"
+if [ $? -ne 0 ]; then
+ echo "fsck failed??"
+ exit 1
+fi
+
+# Run tests
+echo "+ run test"
+ret=0
+seq 1 "${PASSES}" | while read pass; do
+ echo "+ pass ${pass}"
+ PASS_IMG="${TESTDIR}/e2fuzz-${pass}.img"
+ FSCK_IMG="${TESTDIR}/e2fuzz-${pass}.fsck"
+ FUZZ_LOG="${TESTDIR}/e2fuzz-${pass}.fuzz.log"
+ OPS_LOG="${TESTDIR}/e2fuzz-${pass}.ops.log"
+
+ echo "++ corrupt image"
+ cp "${BASE_IMG}" "${PASS_IMG}"
+ if [ $? -ne 0 ]; then
+ exit $?
+ fi
+ tune2fs -L "e2fuzz-${pass}" "${PASS_IMG}"
+ e2fuzz -v "${PASS_IMG}" ${E2FUZZ_ARGS} > "${FUZZ_LOG}"
+ if [ $? -ne 0 ]; then
+ exit $?
+ fi
+
+ echo "++ mount image"
+ if [ "${USE_FUSE2FS}" -gt 0 ]; then
+ "${SCRIPT_DIR}/fuse2fs" "${PASS_IMG}" "${TESTMNT}"
+ res=$?
+ else
+ mount "${PASS_IMG}" "${TESTMNT}" -o loop
+ res=$?
+ fi
+
+ if [ "${res}" -eq 0 ]; then
+ echo "+++ ls -laR"
+ ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}"
+
+ echo "+++ cat files"
+ find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}"
+
+ echo "+++ expand"
+ find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do
+ attr -l "$f" > /dev/null 2>> "${OPS_LOG}"
+ if [ -f "$f" -a -w "$f" ]; then
+ dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}"
+ fi
+ mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}"
+ done
+ sync
+
+ echo "+++ create files"
+ cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
+ sync
+
+ echo "+++ remove files"
+ rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
+
+ umount "${TESTMNT}"
+ res=$?
+ if [ "${res}" -ne 0 ]; then
+ ret=1
+ break
+ fi
+ sync
+ test "${USE_FUSE2FS}" -gt 0 && sleep 2
+ fi
+ if [ "${RUN_FSCK}" -gt 0 ]; then
+ cp "${PASS_IMG}" "${FSCK_IMG}"
+ pass_img_sz="$(stat -c '%s' "${PASS_IMG}")"
+
+ seq 1 "${MAX_FSCK}" | while read fsck_pass; do
+ echo "++ fsck pass ${fsck_pass}: $(which e2fsck) -fy ${FSCK_IMG} ${EXTENDED_FSCK_OPTS}"
+ FSCK_LOG="${TESTDIR}/e2fuzz-${pass}-${fsck_pass}.log"
+ e2fsck -fy "${FSCK_IMG}" ${EXTENDED_FSCK_OPTS} > "${FSCK_LOG}" 2>&1
+ res=$?
+ echo "++ fsck returns ${res}"
+ if [ "${res}" -eq 0 ]; then
+ exit 0
+ elif [ "${fsck_pass}" -eq "${MAX_FSCK}" ]; then
+ echo "++ fsck did not fix in ${MAX_FSCK} passes."
+ exit 1
+ fi
+ if [ "${res}" -gt 0 -a \
+ "$(grep 'Memory allocation failed' "${FSCK_LOG}" | wc -l)" -gt 0 ]; then
+ echo "++ Ran out of memory, get more RAM"
+ exit 0
+ fi
+ if [ "${res}" -gt 0 -a \
+ "$(grep 'Could not allocate block' "${FSCK_LOG}" | wc -l)" -gt 0 -a \
+ "$(dumpe2fs -h "${FSCK_IMG}" | grep '^Free blocks:' | awk '{print $3}')0" -eq 0 ]; then
+ echo "++ Ran out of space, get a bigger image"
+ exit 0
+ fi
+ if [ "${fsck_pass}" -gt 1 ]; then
+ diff -u "${TESTDIR}/e2fuzz-${pass}-$((fsck_pass - 1)).log" "${FSCK_LOG}"
+ if [ $? -eq 0 ]; then
+ echo "++ fsck makes no progress"
+ exit 2
+ fi
+ fi
+
+ fsck_img_sz="$(stat -c '%s' "${FSCK_IMG}")"
+ if [ "${fsck_img_sz}" -ne "${pass_img_sz}" ]; then
+ echo "++ fsck image size changed"
+ exit 3
+ fi
+ done
+ fsck_loop_ret=$?
+ if [ "${fsck_loop_ret}" -gt 0 ]; then
+ break;
+ fi
+ fi
+
+ echo "+++ check fs for round 2"
+ FSCK_LOG="${TESTDIR}/e2fuzz-${pass}-round2.log"
+ e2fsck -fn "${FSCK_IMG}" ${EXTENDED_FSCK_OPTS} >> "${FSCK_LOG}" 2>&1
+ res=$?
+ if [ "${res}" -ne 0 ]; then
+ echo "++++ fsck failed."
+ exit 1
+ fi
+
+ echo "++ mount image (2)"
+ mount "${FSCK_IMG}" "${TESTMNT}" -o loop
+ res=$?
+
+ if [ "${res}" -eq 0 ]; then
+ echo "+++ ls -laR (2)"
+ ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}"
+
+ echo "+++ cat files (2)"
+ find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}"
+
+ echo "+++ expand (2)"
+ find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do
+ attr -l "$f" > /dev/null 2>> "${OPS_LOG}"
+ if [ -f "$f" -a -w "$f" ]; then
+ dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}"
+ fi
+ mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}"
+ done
+ sync
+
+ echo "+++ create files (2)"
+ cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
+ sync
+
+ echo "+++ remove files (2)"
+ rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
+
+ umount "${TESTMNT}"
+ res=$?
+ if [ "${res}" -ne 0 ]; then
+ ret=1
+ break
+ fi
+ sync
+ test "${USE_FUSE2FS}" -gt 0 && sleep 2
+
+ echo "+++ check fs (2)"
+ e2fsck -fn "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1
+ res=$?
+ if [ "${res}" -ne 0 ]; then
+ echo "++ fsck failed."
+ exit 1
+ fi
+ else
+ echo "++ mount(2) failed with ${res}"
+ exit 1
+ fi
+ rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" "${TESTDIR}"/e2fuzz*.log
+done
+
+exit $ret