diff options
Diffstat (limited to 'misc/e2fuzz.sh')
-rwxr-xr-x | misc/e2fuzz.sh | 327 |
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 |