328 lines
7.6 KiB
Bash
Executable File
328 lines
7.6 KiB
Bash
Executable File
#!/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
|