Skip to content

Instantly share code, notes, and snippets.

@djwong
Last active December 21, 2015 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save djwong/6372995 to your computer and use it in GitHub Desktop.
Save djwong/6372995 to your computer and use it in GitHub Desktop.
ext4 metadata checksumming test script
#!/bin/bash -e
# ext4 metadata checksum test script
# licensed under gplv2
# copyright (c) 2013 oracle corporation. all rights reserved.
function tncmount {
mount "$@" && return 0
sleep 1
set +e
mount "$@"
set -e
return $?
}
function tncfsck {
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck "$@" && return 0
sleep 1
set +e
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck "$@"
set -e
return $?
}
echo "ARGS: $@"
type attr || (echo "Must install attr program."; exit 5)
type /usr/bin/time || (echo "Must install time program."; exit 5)
type truncate || (echo "Must install truncate program."; exit 5)
DEV=/dev/sdb
MNT=/mnt
VALGRIND="valgrind" # --leak-check=full --show-reachable=yes"
VALGRIND=
MKFS_OPTS="64bit"
FUZZ="Fuzzy Wuzzy was a bear. Fuzzy Wuzzy had no hair. I guess he wasn't fuzzy, was he?"
ALL_VERBS="$(grep ^function $0 | grep '_test ' | awk '{print $2}')"
VERBS="${ALL_VERBS}"
DIR="$(dirname "$0")"
E2FSPROGS="${DIR}/../e2fsprogs-csum"
export LD_LIBRARY_PATH="${E2FSPROGS}/lib/:${LD_LIBRARY_PATH}"
BLK_SZ=4096
#MOUNT_OPTS="errors=remount-ro"
HUGE_DEV_NAME="HUGE"
FUZZ_DEV=0
if [ -c "/dev/ttyprintk" ]; then
MSGLOG="/dev/ttyprintk"
else
MSGLOG="/tmp/ttyprintk"
fi
INODE_SZ=256
SKIP_SPEED_TESTS=0
function print_help {
cat << ENDL
Usage: $0 [-b blocksize] [-d device] [-e mkfs_options] [-h huge_dev_name]
[-i inode_size] [-m mountpoint] [-o mkfs_features]
[-p path_to_e2fsprogs] [-v verbs] [-z mount_opts]
-f Create fuzz device
-l Use valgrind
-n No checksumming
-q Enable MMP
-f Create a backing device full of periods ('.') before running test.
-s Skip speed test
verbs is any combination of:
${ALL_VERBS}
ENDL
exit 1
}
while getopts "b:d:e:fh:i:lm:no:p:qsv:z:" OPTION; do
case "$OPTION" in
"b")
BLK_SZ="${OPTARG}"
;;
"d")
DEV="${OPTARG}"
;;
"e")
MKFS_FEATURES="${OPTARG}"
;;
"f")
FUZZ_DEV=1
exit 2
;;
"h")
HUGE_DEV_NAME="${OPTARG}"
;;
"i")
INODE_SZ="${OPTARG}"
;;
"l")
VALGRIND=valgrind
;;
"m")
MNT="${OPTARG}"
;;
"n")
NO_CSUM=1
;;
"o")
MKFS_OPTS="${OPTARG}"
;;
"p")
E2FSPROGS="${OPTARG}"
;;
"q")
MKFS_OPTS="${MKFS_OPTS},mmp"
;;
"s")
SKIP_SPEED_TESTS=1
;;
"v")
VERBS="${OPTARG}"
;;
"z")
MOUNT_OPTS="${OPTARG}"
;;
*)
print_help
exit 1
;;
esac
done
if [ ! -z "${MKFS_OPTS}" ]; then
MKFS_OPTS=",${MKFS_OPTS}"
fi
if [ ! -z "${MKFS_FEATURES}" ]; then
MKFS_FEATURES="-E ${MKFS_FEATURES}"
fi
if [ ! -z "${MOUNT_OPTS}" ]; then
MOUNT_OPTS="-o ${MOUNT_OPTS}"
fi
mount_cmd="mount"
fsck_cmd="$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck"
if [ "${TNC}" = "yes" ]; then
mount_cmd="tncmount"
fsck_cmd="tncfsck"
fi
function is_dev_huge {
if [ "$(blockdev --getsz "${DEV}")" -gt 34359738368 ]; then
return 0
fi
return 1
}
function msg {
if [ -x /usr/bin/figlet ]; then
figlet -f mono9 -w 132 "$@" > /dev/tty
echo "${curr_test}:" "$@" > "${MSGLOG}"
else
echo "${curr_test}:" "$@" | tee "${MSGLOG}"
fi
}
if [ ! -b "${DEV}" ]; then
echo "${DEV} is not a block device?"
exit 0
fi
if [ "$(blockdev --getsz "${DEV}")" -lt 3145728 ]; then
echo "${DEV} needs to be 1.5GB or bigger."
exit 0
fi
umount $MNT || true
rmmod ext4 || true
rmmod jbd2 || true
rmmod crc32c || true
rmmod crc32c-intel || true
modprobe ext4
#test -w /sys/module/ext4/parameters/mballoc_debug && echo 1 > /sys/module/ext4/parameters/mballoc_debug
cd /tmp
HUGE_DEV=
if is_dev_huge; then
HUGE_DEV="${DEV}"
else
# Tests can create a 20T huge device if the backing device is at least 1.5T.
if [ "$(blockdev --getsz "${DEV}")" -gt 3221225472 ]; then
${DIR}/hugedisk.sh "${HUGE_DEV_NAME}" "${DEV}" 0
HUGE_DEV="/dev/mapper/${HUGE_DEV_NAME}"
fi
fi
ulimit -c 999999999
# Make sure we have our mke2fs profile set up
MKE2FS_CONFIG="/tmp/mke2fs.conf"
export MKE2FS_CONFIG
# Try to force a change of reserved_gdt_blocks. Not gonna happen on
# > 16T filesystems but oh well.
MAX_BLOCKS="$(( 1024 * BYTES / BLK_SZ ))"
if [ "${MAX_BLOCKS}" -lt "$(( (2**32) - 1 ))" ]; then
MAX_BLOCKS="$(( (2**32) - 1))"
fi
RESIZE_PARAM=
if [ "$(echo "${MKFS_OPTS}" | grep -c '\^resize_inode')" -eq 0 ]; then
RESIZE_PARAM=",resize=${MAX_BLOCKS}"
fi
cat > "${MKE2FS_CONFIG}" << ENDL
# mkfs_opts = ${MKFS_OPTS}
[defaults]
base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr
default_mntopts = acl,user_xattr,block_validity
enable_periodic_fsck = 0
blocksize = 4096
inode_size = 256
inode_ratio = 16384
[fs_types]
ext4icsum = {
features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit$MKFS_OPTS
inode_size = ${INODE_SZ}
blocksize = ${BLK_SZ}
options = mmp_update_interval=5 #${RESIZE_PARAM}
lazy_itable_init = 1
cluster_size = $((BLK_SZ * 2))
}
ext4icsum_noresize = {
features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit$MKFS_OPTS
inode_size = ${INODE_SZ}
blocksize = ${BLK_SZ}
options = mmp_update_interval=5
lazy_itable_init = 1
cluster_size = $((BLK_SZ * 2))
}
ENDL
MKFS_OPTS=""
#dmesg -c > /dev/null
trap 'msg "test ended"' EXIT
msg "$0: Begin test @ $(date)"
grep 'features =' "${MKE2FS_CONFIG}" | sed -e 's/^\s*//g' > "${MSGLOG}"
set -x
#####################################
function simple_test {
msg "Create fs with files, no checksums"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/
mkdir -p $MNT/fragged
dd if=/dev/zero bs=4k count=1 of=$MNT/fragged/fragfile
sync
set +x
echo + frag
for i in `seq 1 8`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
echo moo > $MNT/ea_file
set +x
echo + set_ea
nr_attr="$((BLK_SZ * 100 / 4096))"
for i in `seq -w 1 ${nr_attr}`; do
attr -s $i -V $i $MNT/ea_file
done
set -x
umount $MNT
#########################################
msg "Enable checksums"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -o -type d -print0 | xargs -0 touch
attr -l $MNT/ea_file
umount $MNT
# Copy stuff into fs to create inodes w/ checksums
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/moo
cp -pR /usr/share/doc/ $MNT/moo/
umount $MNT
# Create htree dir
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir -p $MNT/bigdir2
set +x
echo + htree2
for i in `seq 1 256`; do
echo moo > "$MNT/bigdir2/$(echo "$(date)_$i" | md5sum)"
done
set -x
umount $MNT
# Check fs again
${fsck_cmd} -f -n $DEV
########################################
msg "Mess with extent tree"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
set +x
echo + frag
for i in `seq 9 18`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
umount $MNT
# Check fs again
${fsck_cmd} -f -n $DEV
# Keep rewriting the extent tree just to drive it crazy
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
set +x
echo + frag
for i in `seq 19 28`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
umount $MNT
# Check fs again
${fsck_cmd} -f -n $DEV
# Truncate the file to (29*4)-64 = 52K
#${E2FSPROGS}/debugfs/debugfs -R 'stat /fragged/fragfile' ${DEV} >> /tmp/log
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
truncate -s -64k $MNT/fragged/fragfile
umount $MNT
# Check fs again
${fsck_cmd} -f -n $DEV
# Keep rewriting the extent tree just to drive it crazy
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
set +x
echo + frag
for i in `seq 29 38`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
umount $MNT
# Check fs again
${fsck_cmd} -f -n $DEV
# Re-walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT/
# Check fs again
${fsck_cmd} -f -n $DEV
##################################################
msg "Disable checksums"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O ^metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -o -type d -print0 | xargs -0 touch
umount $MNT
# Copy stuff into fs to create inodes w/o checksums
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/oom
cp -pR /usr/share/doc/ $MNT/oom/
umount $MNT
# Re-walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT/
# Check fs again
${fsck_cmd} -f -n $DEV
####################################
msg "Re-enable checksums"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -o -type d -print0 | xargs -0 touch
umount $MNT
${fsck_cmd} -f -n $DEV
# Create big file
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
dd if=/dev/zero of=$MNT/bigfile bs=1024k count=16
umount $MNT
${fsck_cmd} -f -n $DEV
# Remove big file
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
rm -rf $MNT/bigfile
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
#############################
# create xattrs
msg "mess with xattrs"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo attrs > $MNT/attrfile
set +x
echo + set_xattrs
for i in `seq -w 1 ${nr_attrs}`; do
attr -s $i -V $i $MNT/attrfile
done
set -x
attr -l $MNT/attrfile
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#####################################
function frag_truncate_test {
msg "Fragment a file and then truncate it"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/fragged/
set +x
echo + frag
for i in `seq 1 64`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
umount $MNT
# Check fs again
${fsck_cmd} -f -n $DEV
# Truncate the file to (64*4)-64 = 192K (48 4k blocks)
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
truncate -s -64k $MNT/fragged/fragfile
umount $MNT
# Check fs again
${fsck_cmd} -f -n $DEV
}
#####################################
function meta_bg_remove_checksum_test {
msg "Create fs with files, meta_bg, and checksums"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum_noresize -O metadata_csum,meta_bg,^resize_inode $MKFS_FEATURES -F "${DEV}"
#${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/check0000
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/
mkdir -p $MNT/fragged
dd if=/dev/zero bs=4k count=1 of=$MNT/fragged/fragfile
sync
set +x
echo + frag
for i in `seq 1 8`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
echo moo > $MNT/ea_file
set +x
echo + set_ea
nr_attr="$((BLK_SZ * 100 / 4096))"
for i in `seq -w 1 ${nr_attr}`; do
attr -s $i -V $i $MNT/ea_file
done
set -x
umount $MNT
#${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/check0001
##################################################
msg "Disable checksums"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O ^metadata_csum $DEV
#${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/check0002
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -o -type d -print0 | xargs -0 touch
umount $MNT
# Copy stuff into fs to create inodes w/o checksums
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/oom
cp -pR /usr/share/doc/ $MNT/oom/
umount $MNT
# Re-walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT/
# Check fs again
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_inode_csum_test {
msg "Deliberately corrupt inode checksum"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -I $BLK_SZ -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/filldir
set +x
echo + filldir
for i in `seq 1 10000`; do
echo moo > $MNT/filldir/$i
done
set -x
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
umount $MNT
${fsck_cmd} -f -n $DEV
set +x
echo + corrupt_inode_csum
FIRST_GROUP=1
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Inode table' | sed -e 's/^.*at \([0-9]*\)-\([0-9]*\).*$/\1 \2/g' | while read start end; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
start=$((start + 11))
fi
echo -en " $start"
if [ $((end - start)) -gt 4 ]; then
end=$((start + 4))
fi
seq $start $end | while read block; do
offset=$(( (block * (BLK_SZ / 4)) + 31 ))
yes "${FUZZ}" | dd of=$DEV bs=4 seek=$offset count=1 > /dev/null 2> /dev/null
done
done
echo
set -x
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
(find $MNT -type f -o -type d -print0 | xargs -0 touch) || true
umount $MNT
# Repair fs
${fsck_cmd} -f -y $DEV || ${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -o -type d -print0 | xargs -0 touch
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_inode_test {
msg "Deliberately corrupt inode table"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/filldir
set +x
echo + filldir
for i in `seq 1 10000`; do
echo moo > $MNT/filldir/$i
done
set -x
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
umount $MNT
${fsck_cmd} -f -n $DEV
set +x
echo + corrupt_inode_table
BLOCKSIZE=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
BLOCKS=$(${E2FSPROGS}/misc/dumpe2fs $DEV -h | grep 'Inode blocks per group:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
FIRST_GROUP=1
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Inode table' | sed -e 's/^.*at \([0-9]*\)-.*$/\1/g' | while read f; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
f=$((f + 1))
fi
echo -en " $f"
yes "${FUZZ}" | dd of=$DEV bs=$BLOCKSIZE seek=$f count=$BLOCKS > /dev/null 2> /dev/null
done
echo
set -x
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
(find $MNT -type f -o -type d -print0 | xargs -0 touch) 2>&1 | head -n 50 || true
umount $MNT
# Repair fs
${fsck_cmd} -f -y $DEV || ${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -o -type d -print0 | xargs -0 touch
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_ibitmap_test {
msg "Deliberately corrupt inode bitmap"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
umount $MNT
set +x
echo + corrupt_inode_bitmap
BLOCKSIZE=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
FIRST_GROUP=1
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Inode bitmap at' | sed -e 's/^.*Inode bitmap at //g' -e 's/ .*$//g' | while read f; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
continue
fi
echo -en " $f"
yes "${FUZZ}" | dd of=$DEV bs=$BLOCKSIZE seek=$f count=1 > /dev/null 2> /dev/null
done
echo
set -x
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum || true
(find $MNT -type d | while read dir; do
echo "${dir}/file1.$$"
echo test > "${dir}/file1.$$"
if [ ! -e "${dir}/file1.$$" ]; then
# Beat on it a few more times just for good measure
for i in `seq 1 8`; do
echo test > "${dir}/file1.$$"
done
break
fi
done) || true
umount $MNT || true
# Repair fs
${fsck_cmd} -f -y $DEV || true
${fsck_cmd} -fy $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
ITER=0
find $MNT -type d | while read dir; do echo "${dir}/file2.$$"; echo test > "${dir}/file2.$$"; if [ $ITER -gt 20 ]; then break; fi; ITER=$((ITER + 1)); done
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_group_descr_test {
msg "Deliberately corrupt group descriptor"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
umount $MNT
#set +x
echo + corrupt_group_descr
BLOCKSIZE="$(${E2FSPROGS}/misc/dumpe2fs -h "${DEV}" | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')"
IS_64BIT="$(${E2FSPROGS}/misc/dumpe2fs -h "${DEV}" | grep -c 64bit)"
ITER=0
if [ "${IS_64BIT}" ]; then
GD_SZ=64
else
GD_SZ=32
fi
# Corrupt the GDs in the first and last ten blocks.
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Group descriptor.*at' | sed -e 's/^.*Group descriptors at \([0-9]*\)-\([0-9]*\)/\1 \2/g' -e 's/^.*Group descriptor at \([0-9]*\)/\1 \1/g' | while read s e crap; do
echo "${s} ${e}"
for blk in $(seq "${s}" "${e}" | head -n10) $(seq "${s}" "${e}" | tail -n10); do
GD="$(( (blk * BLOCKSIZE / GD_SZ) + 1))"
NUM_GDS="$(( (BLOCKSIZE / GD_SZ) - 1))"
echo -en " ${GD}"
yes "${FUZZ}" | dd of="${DEV}" bs="${GD_SZ}" seek="${GD}" count="${NUM_GDS}" > /dev/null 2> /dev/null
done
done
echo
set -x
# We shouldn't be able to mount
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum && (umount $MNT; ${fsck_cmd} -f -n $DEV; false)
# Repair fs
${fsck_cmd} -f -y $DEV || true
${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
ITER=0
find $MNT -type d | while read dir; do echo "${dir}/file2.$$"; echo test > "${dir}/file2.$$"; if [ $ITER -gt 20 ]; then break; fi; ITER=$((ITER + 1)); done
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_group_descr_at_runtime_bbitmap_test {
msg "Deliberately corrupt group descriptor at runtime"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
# Do everything with delayed allocation enabled...
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum,debug,block_validity
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
sync
#set +x
echo + corrupt_group_descr
BLOCKSIZE=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
FIRST_GROUP=0
GD_SZ=64
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Group descriptors at' | sed -e 's/^.*Group descriptors at //g' -e 's/-.*$//g' | while read f; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
continue
fi
echo -en " $f"
BLOCK="$(( f * (BLOCKSIZE / GD_SZ) + 1 ))"
yes "${FUZZ}" | dd of=$DEV bs=$GD_SZ seek=$BLOCK count=$(( (BLOCKSIZE / GD_SZ) - 1)) > /dev/null 2> /dev/null
done
echo
set -x
# Try to create a file on our still-mounted fs...
dd if=/dev/zero of=$MNT/bigfile bs=1024k count=256
sync
df $MNT; df -i $MNT
cat /proc/fs/ext4/*/mb_groups || true
dd if=/dev/zero of=$MNT/bigfile2 bs=1024k count=256
sync
umount $MNT
# Repair fs
${fsck_cmd} -f -y $DEV || true
${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
ITER=0
find $MNT -type d | while read dir; do echo "${dir}/file2.$$"; echo test > "${dir}/file2.$$"; if [ $ITER -gt 20 ]; then break; fi; ITER=$((ITER + 1)); done
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_group_descr_at_runtime_nodelalloc_bbitmap_test {
msg "Deliberately corrupt group descriptor at runtime, nodelalloc"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
# Do it over again, but with nodelalloc
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum,debug,block_validity,nodelalloc
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
sync
#set +x
echo + corrupt_group_descr
BLOCKSIZE=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
FIRST_GROUP=0
GD_SZ=64
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Group descriptors at' | sed -e 's/^.*Group descriptors at //g' -e 's/-.*$//g' | while read f; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
continue
fi
echo -en " $f"
BLOCK="$(( f * (BLOCKSIZE / GD_SZ) + 1 ))"
yes "${FUZZ}" | dd of=$DEV bs=$GD_SZ seek=$BLOCK count=$(( (BLOCKSIZE / GD_SZ) - 1)) > /dev/null 2> /dev/null
done
echo
set -x
# Try to create a file on our still-mounted fs...
dd if=/dev/zero of=$MNT/bigfile bs=1024k count=256 || true
sync
df $MNT; df -i $MNT
cat /proc/fs/ext4/*/mb_groups || true
dd if=/dev/zero of=$MNT/bigfile2 bs=1024k count=256 || true
sync
umount $MNT
# Repair fs
${fsck_cmd} -f -y $DEV || true
${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
ITER=0
find $MNT -type d | while read dir; do echo "${dir}/file2.$$"; echo test > "${dir}/file2.$$"; if [ $ITER -gt 20 ]; then break; fi; ITER=$((ITER + 1)); done
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_group_descr_at_runtime_ibitmap_test {
msg "Deliberately corrupt group descriptor at runtime, only inode allocations"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
# Do it over again, but with nodelalloc
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum,debug,block_validity,nodelalloc
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
sync
#set +x
echo + corrupt_group_descr
BLOCKSIZE=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
FIRST_GROUP=0
GD_SZ=64
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Group descriptors at' | sed -e 's/^.*Group descriptors at //g' -e 's/-.*$//g' | while read f; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
continue
fi
echo -en " $f"
BLOCK="$(( f * (BLOCKSIZE / GD_SZ) + 1 ))"
yes "${FUZZ}" | dd of=$DEV bs=$GD_SZ seek=$BLOCK count=$(( (BLOCKSIZE / GD_SZ) - 1)) > /dev/null 2> /dev/null
done
echo
set -x
# Try to create a file on our still-mounted fs...
set +x
echo + mkfiles
mkdir -p "${MNT}/x/"
for i in `seq 1 16384`; do touch "${MNT}/x/badfile.$i" || break; done
rm -rf $MNT/x/badfile*
set -x
sync
df $MNT; df -i $MNT
cat /proc/fs/ext4/*/mb_groups || true
set +x
echo + mkfiles2
for i in `seq 1 32`; do touch $MNT/badfile2.$i || break; done
set -x
sync
umount $MNT
# Repair fs
${fsck_cmd} -f -y $DEV || true
${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
ITER=0
find $MNT -type d | while read dir; do echo "${dir}/file2.$$"; echo test > "${dir}/file2.$$"; if [ $ITER -gt 20 ]; then break; fi; ITER=$((ITER + 1)); done
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_group_descr_at_runtime_itable_test {
msg "Deliberately corrupt group descriptor at runtime, only inode allocations"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
# Do it over again, but with nodelalloc
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum,debug,block_validity,nodelalloc
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
sync
#set +x
echo + corrupt_group_descr
BLOCKSIZE=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
FIRST_GROUP=0
GD_SZ=64
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Group descriptors at' | sed -e 's/^.*Group descriptors at //g' -e 's/-.*$//g' | while read f; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
continue
fi
echo -en " $f"
BLOCK="$(( f * (BLOCKSIZE / GD_SZ) + 1 ))"
yes "${FUZZ}" | dd of=$DEV bs=$GD_SZ seek=$BLOCK count=$(( (BLOCKSIZE / GD_SZ) - 1)) > /dev/null 2> /dev/null
done
echo
set -x
# Try to create a file on our still-mounted fs...
set +x
echo + mkfiles
for i in `seq 1 16384`; do touch $MNT/moo/badfile.$i || break; done
rm -rf $MNT/moo/badfile*
set -x
sync
df $MNT; df -i $MNT
cat /proc/fs/ext4/*/mb_groups || true
set +x
echo + mkfiles2
for i in `seq 1 32`; do touch $MNT/moo/badfile2.$i || break; done
set -x
sync
umount $MNT
# Repair fs
${fsck_cmd} -f -y $DEV || true
${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
ITER=0
find $MNT -type d | while read dir; do echo "${dir}/file2.$$"; echo test > "${dir}/file2.$$"; if [ $ITER -gt 20 ]; then break; fi; ITER=$((ITER + 1)); done
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function corrupt_bbitmap_test {
msg "Deliberately corrupt block bitmap"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
umount $MNT
set +x
echo + corrupt_block_bitmap
BLOCKSIZE=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
FIRST_GROUP=1
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Block bitmap at' | sed -e 's/^.*Block bitmap at //g' -e 's/ .*$//g' | while read f; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
continue
fi
echo -en " $f"
yes "${FUZZ}" | dd of=$DEV bs=$BLOCKSIZE seek=$f count=1 > /dev/null 2> /dev/null
done
echo
set -x
# Walk fs looking for errors
if ${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum; then
(find $MNT -type d | while read dir; do echo "${dir}/file1.$$"; echo test > "${dir}/file1.$$"; if [ ! -e "${dir}/file1.$$" ]; then break; fi; done) || true
cat /proc/fs/ext4/*/mb_groups || true
df -k $MNT
umount $MNT
fi
# Repair fs
${fsck_cmd} -f -y $DEV || true
${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
ITER=0
find $MNT -type d | while read dir; do echo "${dir}/file2.$$"; echo test > "${dir}/file2.$$"; if [ $ITER -gt 20 ]; then break; fi; ITER=$((ITER + 1)); done
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#################################
function zero_bbitmap_test {
msg "Deliberately zero block bitmap"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/
cp -pR /usr/share/doc/ $MNT/moo
umount $MNT
set +x
echo + zero_block_bitmap
BLOCKSIZE=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Block size:' | sed -e 's/^.* \([0-9]*\)$/\1/g')
FIRST_GROUP=1
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV | grep 'Block bitmap at' | sed -e 's/^.*Block bitmap at //g' -e 's/ .*$//g' | while read f; do
if [ $FIRST_GROUP -gt 0 ]; then
FIRST_GROUP=0
continue
fi
echo -en " $f"
dd if=/dev/zero of=$DEV bs=$BLOCKSIZE seek=$f count=1 > /dev/null 2> /dev/null
done
echo
set -x
# Walk fs looking for errors
if ${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum; then
(find $MNT -type d | while read dir; do echo "${dir}/file1.$$"; echo test > "${dir}/file1.$$"; if [ ! -e "${dir}/file1.$$" ]; then break; fi; done) || true
umount $MNT
fi
# Repair fs
${fsck_cmd} -f -y $DEV || true
${fsck_cmd} -f -y $DEV || true
# Walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
ITER=0
find $MNT -type d | while read dir; do echo "${dir}/file2.$$"; echo test > "${dir}/file2.$$"; if [ $ITER -gt 20 ]; then break; fi; ITER=$((ITER + 1)); done
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#######################
function corrupt_extent_head_test {
msg "Corrupt an extent header"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
SZ=$(df -k $MNT | awk '{print $4}' | tail -1)
SZ="$((SZ * 9 / 10))"
if [ "${SZ}" -gt 17179869176 ]; then
SZ=17179869176
fi
fallocate -l "${SZ}k" "${MNT}/ouch"
umount $MNT
set +x
echo + corrupt_extent_tree
${E2FSPROGS}/debugfs/debugfs -R 'ex -n /ouch' "${DEV}" | awk '{if ($8 * 1 == $8) {print $8}}' | while read block; do
yes "${FUZZ}" | dd of=$DEV bs=$BLK_SZ seek=$block count=1 > /dev/null 2> /dev/null
done
set -x
# Look for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo >> $MNT/ouch || true
umount $MNT
# Repair
${fsck_cmd} -f -y $DEV || true
# Look for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo oom >> $MNT/ouch
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#######################
function corrupt_extent_test {
msg "Destroy an extent entry"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
SZ=$(df -k $MNT | awk '{print $4}' | tail -1)
SZ="$((SZ * 9 / 10))"
if [ "${SZ}" -gt 17179869176 ]; then
SZ=17179869176
fi
fallocate -l "${SZ}k" "${MNT}/ouch"
umount $MNT
${E2FSPROGS}/debugfs/debugfs -R 'stat /ouch' "${DEV}" | cat -
set +x
echo + corrupt_extent_tree
${E2FSPROGS}/debugfs/debugfs -R 'ex -n /ouch' "${DEV}" | awk '{if ($8 * 1 == $8) {print $8}}' | while read block; do
real_block=$(((block * (BLK_SZ / 16)) + 1))
yes "${FUZZ}" | dd of=$DEV bs=16 seek=$real_block count=1 > /dev/null 2> /dev/null
done
set -x
${E2FSPROGS}/debugfs/debugfs -R 'stat /ouch' "${DEV}" | cat -
# Look for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo >> $MNT/ouch || true
umount $MNT
# Repair
${fsck_cmd} -f -y $DEV || true
${E2FSPROGS}/debugfs/debugfs -R 'stat /ouch' "${DEV}" | cat -
# Look for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo oom >> $MNT/ouch
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#######################
function corrupt_extent_csum_test {
msg "Destroy an extent block csum"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
SZ=$(df -k $MNT | awk '{print $4}' | tail -1)
SZ="$((SZ * 9 / 10))"
if [ "${SZ}" -gt 17179869176 ]; then
SZ=17179869176
fi
fallocate -l "${SZ}k" "${MNT}/ouch"
umount $MNT
${E2FSPROGS}/debugfs/debugfs -R 'ex /ouch' "${DEV}" | cat -
set +x
echo + corrupt_extent_block_csum
${E2FSPROGS}/debugfs/debugfs -R 'ex -n /ouch' "${DEV}" | awk '{if ($8 * 1 == $8) {print $8}}' | while read block junk; do
real_block=$(( ((block + 1) * (BLK_SZ / 16)) - 1 ))
yes "${FUZZ}" | dd of=$DEV bs=16 seek=$real_block count=1 > /dev/null 2> /dev/null
done
set -x
${E2FSPROGS}/debugfs/debugfs -R 'ex /ouch' "${DEV}" | cat -
# Look for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo >> $MNT/ouch || true
umount $MNT
# Repair
${fsck_cmd} -f -y $DEV || true
${E2FSPROGS}/debugfs/debugfs -R 'stat /ouch' "${DEV}" | cat -
# Look for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo oom >> $MNT/ouch
umount $MNT
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#######################
function htree_test {
msg "Simple htree test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
msg "htree1"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
set +x
echo + htree1
for i in 1; do
for j in 1 2 3 4; do
mkdir -p $MNT/$i/$j
for k in `seq 1 24`; do
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$k\" x 256);")
echo moo > "$MNT/$i/$j/$FNAME"
done
done
for k in `seq 1 32`; do
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$k\" x 256);")
echo moo > "$MNT/$i/$FNAME"
done
done
set -x
umount $MNT
${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -fn $DEV
msg "htree2"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/1 > /dev/null
set +x
echo + htree2
for i in 2; do
for j in 1 2 3 4; do
mkdir -p $MNT/$i/$j
for k in `seq 1 24`; do
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$k\" x 256);")
echo moo > "$MNT/$i/$j/$FNAME"
done
done
for k in `seq 1 32`; do
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$k\" x 256);")
echo moo > "$MNT/$i/$FNAME"
done
done
set -x
umount $MNT
${fsck_cmd} -fn $DEV
msg "htree_del"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
rm -rf $MNT/1 $MNT/2
umount $MNT
msg "multi level htree"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -fn $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/3
echo moo > $MNT/3/base.txt
set +x
echo + mltree
NUM_FILES="$(( (BLK_SZ / 250) * ((BLK_SZ - 18) / 8) * 2 ))"
seq 1 $NUM_FILES | while read f; do
if [ $((f % 71)) -eq 0 ]; then
echo -n "$f..."
fi
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$f\" x 256);")
ln $MNT/3/base.txt $MNT/3/$FNAME
done
echo
set -x
umount $MNT
${fsck_cmd} -fn $DEV
msg "mlhtree delete"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
rm -rf $MNT/3
umount $MNT
${fsck_cmd} -fn $DEV
}
#########################
function corrupt_htree_test {
msg "corrupt htree"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/3
echo moo > $MNT/3/base.txt
set +x
sync
num_files="$(( 5 + (BLK_SZ / 250) ))"
echo + htree ${num_files}
seq 1 $num_files | while read f; do
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$f\" x 256);")
ln $MNT/3/base.txt $MNT/3/$FNAME
done
set -x
umount $MNT
${fsck_cmd} -fn $DEV || true
# now blast the root block
ROOT_BLK="$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /3 1' "${DEV}" | tail -n 1)"
yes "${FUZZ}" | dd of=$DEV bs=8 seek=$(( ( (ROOT_BLK + 1) * (BLK_SZ / 8)) - 1 )) count=1 > /dev/null 2> /dev/null
${fsck_cmd} -fn $DEV || true
# walk looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/3 > /dev/null || true
umount $MNT
# WARNING: The htree flag is now off!
# fix
${fsck_cmd} -fDy $DEV || true
# rescan
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/3 > /dev/null || true
umount $MNT
# check once more
${fsck_cmd} -fn $DEV
# inflate directory some more
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir -p $MNT/3
echo moo > $MNT/3/base.txt
set +x
echo + mltree_fuzz
seq $((num_files + 1)) $(( (BLK_SZ / 250) * 500 )) | while read f; do
if [ $((f % 71)) -eq 0 ]; then
echo -n "$f..."
fi
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$f\" x 256);")
ln $MNT/3/base.txt $MNT/3/$FNAME
done
set -x
umount $MNT
# now corrupt the secondary blocks
${E2FSPROGS}/debugfs/debugfs -R 'htree /3' "${DEV}" | grep 'Number of entries' -B1 | grep block | sed -e 's/^.*block //g' | while read blocknr; do
PBLK=$(${E2FSPROGS}/debugfs/debugfs -R "bmap /3 ${blocknr}" "${DEV}" | grep '^[0-9]')
PBLK=$(( (PBLK * (BLK_SZ / 8)) + 2 ))
yes "${FUZZ}" | dd of=$DEV bs=8 seek=${PBLK} count=1 > /dev/null 2> /dev/null
done
${fsck_cmd} -fn $DEV || true
# walk looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/3 > /dev/null || true
umount $MNT
# fix
${fsck_cmd} -fn $DEV || true
${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -fDy $DEV || true
# rescan
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/3 > /dev/null || true
umount $MNT
# check once more
${fsck_cmd} -fn $DEV
}
#########################
function flat_dir_test {
msg "flat dir test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^dir_index -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/a
cp -pR $MNT/a $MNT/b
cp -pR $MNT/a $MNT/c
cp -pR $MNT/a $MNT/d
umount $MNT
${fsck_cmd} -fn $DEV
msg "cat files"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/b -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
${fsck_cmd} -fn $DEV
msg "enlarge direntry"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
set +x
echo + enbiggen dirents
# You need depth-first traversal here
find $MNT/b -depth | while read f; do
mv $f $f.longer
done
set -x
umount $MNT
${fsck_cmd} -fn $DEV
msg "rm file"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/b -type f -print0 | xargs -0 rm -rf
umount $MNT
${fsck_cmd} -fn $DEV
msg "rm dir"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
rm -rf $MNT/b
umount $MNT
${fsck_cmd} -fn $DEV
}
#########################
function corrupt_flat_dir_test {
msg "corrupt flat dir test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^dir_index -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/a/
cp -pR /usr/share/doc $MNT/a
umount $MNT
${fsck_cmd} -fn $DEV
# Destroy only the directory block's checksum
${E2FSPROGS}/debugfs/debugfs -R 'stat /a' "${DEV}" | cat -
${E2FSPROGS}/debugfs/debugfs -R 'ex /a' "${DEV}" | cat -
NUM_SECTORS="$(${E2FSPROGS}/debugfs/debugfs -R 'stat /a' "${DEV}" | grep Blockcount | awk '{print $4}')"
NUM_BLOCKS="$((NUM_SECTORS * (BLK_SZ / 512)))"
seq 0 "$((NUM_BLOCKS - 1))" | while read lblk; do
pblk="$(${E2FSPROGS}/debugfs/debugfs -R "bmap /a ${lblk}" "${DEV}")"
test "${pblk}" -eq 0 && break
offset="$(( (pblk + 1) * (BLK_SZ / 4) - 1 ))"
yes "${FUZZ}" | dd of=$DEV bs=4 count=1 seek=$offset
done
${fsck_cmd} -fn $DEV || true
msg "after-corrupt cat files (broken)"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/a -type f -print0 | xargs -0 cat > /dev/null
echo moo | tee $MNT/a/test0 || true
umount $MNT
${fsck_cmd} -fy $DEV || true
msg "after-corrupt-repair cat files again"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/a -type f -print0 | xargs -0 cat > /dev/null
echo moo | tee $MNT/a/test0
umount $MNT
${fsck_cmd} -fn $DEV
msg "blast flat dir test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^dir_index -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/a
umount $MNT
${fsck_cmd} -fn $DEV
# Totally destroy the directory blocks
NUM_SECTORS="$(${E2FSPROGS}/debugfs/debugfs -R 'stat /a' "${DEV}" | grep Blockcount | awk '{print $4}')"
NUM_BLOCKS="$((NUM_SECTORS * (BLK_SZ / 512)))"
seq 0 "$((NUM_BLOCKS - 1))" | while read lblk; do
pblk="$(${E2FSPROGS}/debugfs/debugfs -R "bmap /a ${lblk}" "${DEV}")"
test "${pblk}" -eq 0 && break
yes "${FUZZ}" | dd of=$DEV bs=$BLK_SZ count=1 seek=$pblk
done
${fsck_cmd} -fn $DEV || true
msg "after-blast cat files (brokeN)"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/a -type f -print0 | xargs -0 cat > /dev/null
echo moo | tee $MNT/a/test0 || true
umount $MNT
${fsck_cmd} -fy $DEV || true
${fsck_cmd} -fn $DEV
msg "after-blast-repair cat files"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/a -type f -print0 | xargs -0 cat > /dev/null
test -d $MNT/a/ && echo moo | tee $MNT/a/test1
umount $MNT
${fsck_cmd} -fn $DEV
}
####################
function ignore_fsck_d_test {
msg "ignore_fsck_d_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/
umount $MNT
$VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum "${DEV}"
echo "Find all possible damage."
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
echo "Actually repair damage. 0"
${fsck_cmd} -fy $DEV || true
echo "Test run 0."
${fsck_cmd} -fn $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
${fsck_cmd} -fn $DEV
# do it again, but wiht -D
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/
umount $MNT
$VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum "${DEV}"
echo "Actually repair damage. 1"
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
echo "Test run. 1"
${fsck_cmd} -fn $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
${fsck_cmd} -fn $DEV
}
############################
function xattr_test {
#############################
# create xattrs
msg "xattr_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
# create a bunch of xattrs
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo attrs | tee $MNT/attr1 $MNT/attr2 $MNT/noattr
#set +x
echo + set_xattrs
nr_attrs="$((BLK_SZ * 100 / 4096))"
for i in `seq -w 1 ${nr_attrs}`; do
attr -s $i -V $i $MNT/attr1 > /dev/null
done
attr -l /mnt/attr1
attrs_seen="$(attr -l "${MNT}/attr1" | wc -l)"
if [ "${attrs_seen}" -ne "${nr_attrs}" ]; then
echo "Not all attrs were created."
false
fi
attr -s XXX -V XXX $MNT/attr2 > /dev/null
set -x
umount $MNT
# reload and reread
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
attr -l $MNT/attr1
attr -l $MNT/attr2
attr -l $MNT/noattr
umount $MNT
${fsck_cmd} -f -n $DEV
# remove some attrs
${mount_cmd} ${MOUNT_OPTS} "${DEV}" "${MNT}" -t ext4 -o journal_checksum
for i in `seq -w 7 ${nr_attrs}`; do
attr -r $i "${MNT}/attr1" > /dev/null
done
umount "${MNT}"
${fsck_cmd} -f -n $DEV
# remove all attrs
${mount_cmd} ${MOUNT_OPTS} "${DEV}" "${MNT}" -t ext4 -o journal_checksum
for i in `seq -w 1 ${nr_attrs}`; do
attr -g $i "${MNT}/attr1" > /dev/null 2> /dev/null || break
attr -r $i "${MNT}/attr1" > /dev/null
done
umount "${MNT}"
# Check fs one last time
${fsck_cmd} -f -n $DEV
}
#############################
function corrupt_xattr_test {
msg "corrupt_xattr_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo attrs | tee $MNT/attr1 $MNT/attr2 $MNT/noattr
set +x
echo + set_xattrs
nr_attrs="$((BLK_SZ * 100 / 4096))"
for i in `seq -w 1 ${nr_attrs}`; do
attr -s $i -V $i $MNT/attr1 > /dev/null
done
attr -s XXX -V XXX $MNT/attr2 > /dev/null
set -x
umount $MNT
# gibberise the xattr block
XATTR_BLOCK="$(${E2FSPROGS}/debugfs/debugfs -R 'stat /attr1' "${DEV}" | grep 'File ACL' | awk '{print $3}')"
if [ -z "${XATTR_BLOCK}" -o "0${XATTR_BLOCK}" -lt 1 ]; then
echo "Uh... no ACL block?"
exit 50
fi
yes "${FUZZ}" | dd of=$DEV bs=$BLK_SZ seek=$XATTR_BLOCK count=1 > /dev/null 2> /dev/null
# reload and reread
${fsck_cmd} -f -n $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
attr -l $MNT/attr1 || true
attr -l $MNT/attr1 || true
attr -l $MNT/attr2
attr -l $MNT/noattr
umount $MNT
# fix
${fsck_cmd} -f -y $DEV || true
# reread, but this time fixed
${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
attr -l $MNT/attr1
attr -l $MNT/attr2
attr -l $MNT/noattr
umount $MNT
# once more
${fsck_cmd} -f -n $DEV
}
####################################
function simple_sb_test {
msg "simple_sb_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
# write stuff
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/moo
umount $MNT
${fsck_cmd} -f -n $DEV
# change label
$VALGRIND ${E2FSPROGS}/misc/tune2fs -L moocow $DEV
${fsck_cmd} -f -n $DEV
# quick check kernel
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/cow
umount $MNT
${fsck_cmd} -f -n $DEV
# change label again
$VALGRIND ${E2FSPROGS}/misc/tune2fs -L cowmoo $DEV
${fsck_cmd} -f -n $DEV
# quick check kernel
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/cow
umount $MNT
${fsck_cmd} -f -n $DEV
# change uuid
$VALGRIND ${E2FSPROGS}/misc/tune2fs -U random $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/post-uuid
umount $MNT
${fsck_cmd} -f -n $DEV
}
########################
function dir_rewrite_test {
msg "dir_rewrite_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/a
set +x
echo + htree1
for i in 1; do
for j in 1 2 3 4; do
mkdir -p $MNT/$i/$j
for k in `seq 1 24`; do
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$k\" x 256);")
echo moo > "$MNT/$i/$j/$FNAME"
done
done
for k in `seq 1 32`; do
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$k\" x 256);")
echo moo > "$MNT/$i/$FNAME"
done
done
mkdir -p $MNT/full
for k in `seq 1 32`; do
FNAME=$(perl -e "printf(\"%.248s\\n\", \"_$k\" x 256);")
echo moo > "$MNT/full/$FNAME"
done
set -x
umount $MNT
# enable checksums
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
# run it by the kernel
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
# one last check
${fsck_cmd} -f -n $DEV
}
##################
function uuid_change_test {
msg "uuid_change_test"
UUID1=deadbeef-cafe-babe-dead-beefcafebabe
UUID2=d15ea5ed-dead-beef-face-feeddefec8ed
# Try to change UUID w/o checksums
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^mmp,^metadata_csum -U $UUID1 -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/a
umount $MNT
UUID=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Filesystem UUID' | sed -e 's/^.*:[ ]*//g')
if [ "${UUID}" != "${UUID1}" ]; then
echo "Bad UUID ${UUID}"
exit 1
fi
${fsck_cmd} -f -n $DEV
msg "offline change nocsum"
$VALGRIND ${E2FSPROGS}/misc/tune2fs -U $UUID2 $DEV
UUID=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Filesystem UUID' | sed -e 's/^.*:[ ]*//g')
if [ "${UUID}" != "${UUID2}" -o "${UUID}" = "${UUID1}" ]; then
echo "UUID change fail?"
exit 2
fi
${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
msg "online change nocsum"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/badfile
$VALGRIND ${E2FSPROGS}/misc/tune2fs -U $UUID1 $DEV
sync
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
UUID=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Filesystem UUID' | sed -e 's/^.*:[ ]*//g')
if [ "${UUID}" != "${UUID1}" -o "${UUID}" = "${UUID2}" ]; then
echo "UUID should have changed"
exit 3
fi
${fsck_cmd} -f -n $DEV
# Try to change UUID with chekcsums
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -U $UUID1 -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/a
umount $MNT
UUID=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Filesystem UUID' | sed -e 's/^.*:[ ]*//g')
if [ "${UUID}" != "${UUID1}" ]; then
echo "Bad UUID ${UUID}"
exit 1
fi
${fsck_cmd} -f -n $DEV
msg "offline change"
$VALGRIND ${E2FSPROGS}/misc/tune2fs -U $UUID2 $DEV
UUID=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Filesystem UUID' | sed -e 's/^.*:[ ]*//g')
if [ "${UUID}" != "${UUID2}" -o "${UUID}" = "${UUID1}" ]; then
echo "UUID change fail?"
exit 2
fi
${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
msg "online nochange"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/badfile
$VALGRIND ${E2FSPROGS}/misc/tune2fs -U $UUID1 $DEV || true
sync
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
UUID=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Filesystem UUID' | sed -e 's/^.*:[ ]*//g')
if [ "${UUID}" != "${UUID2}" -o "${UUID}" = "${UUID1}" ]; then
echo "UUID should not have changed"
exit 3
fi
${fsck_cmd} -f -n $DEV
}
################################
function bg_meta_use_csum_test {
msg "bg_meta_use_csum_test"
# write junk into last error field
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^uninit_bg,^metadata_csum -F "${DEV}"
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/doc
umount $MNT
for bg_checksum in 0 1; do
for metadata_csum in 0 1; do
opts=""
if [ $metadata_csum -eq 1 ]; then
opts="metadata_csum,${opts}"
else
opts="^metadata_csum,${opts}"
fi
if [ $bg_checksum -eq 1 ]; then
opts="uninit_bg,${opts}"
else
opts="^uninit_bg,${opts}"
fi
$VALGRIND ${E2FSPROGS}/misc/tune2fs -O $opts $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Filesystem features:'
${mount_cmd} $DEV $MNT -t ext4
find $MNT -type f -print0 | xargs -0 cat > /dev/null
date > "${MNT}/${bg_checksum}_${metadata_csum}"
umount $MNT
${fsck_cmd} -f -n $DEV
done
done
}
############################
function mmp_test {
msg "mmp_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
$VALGRIND ${E2FSPROGS}/misc/tune2fs -O mmp $DEV
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum,mmp $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${fsck_cmd} -f -n $DEV
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/a
umount $MNT
${fsck_cmd} -f -n $DEV
# Can't fsck while mounted
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
set +e
${fsck_cmd} -f -y "${DEV}"
RET=$?
# what the hell is this?
#set +e
#yes | script -f /tmp/mmp.$$ -c "${fsck_cmd} -f -y $DEV; echo \"RETURN: \$?\""
#RET=$(grep 'RETURN:' /tmp/mmp.$$ | awk '{print $2}')
if [ $RET -eq 0 ]; then
echo "Should not be able to fsck while mounted"
exit 50
fi
set -e
umount $MNT
}
#####################
function corrupt_mmp_test {
msg "corrupt_mmp_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
$VALGRIND ${E2FSPROGS}/misc/tune2fs -O mmp $DEV
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/moofile
umount $MNT
${fsck_cmd} -f -n $DEV
MMP_BLOCK=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'MMP block number:' | awk '{print $4}')
MMP_SECTOR=$(((MMP_BLOCK * BLK_SZ / 512)))
yes "${FUZZ}" | dd of=$DEV bs=512 seek=${MMP_SECTOR} count=1 > /dev/null 2> /dev/null
${fsck_cmd} -f -n $DEV || true
set +e
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
if [ $? -eq 0 ]; then
echo "Should not be able to mount with corrupt MMP"
exit 50
fi
set -e
${fsck_cmd} -fy $DEV || true
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
echo $MNT/moofile > /dev/null
umount $MNT
${fsck_cmd} -f -n $DEV
}
##############################
function journal_sb_test {
msg "journal_sb_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
if [ "$(${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | grep -c "has_journal")" -eq 0 ]; then
msg "No journal."
else
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum,data=journal
cp -pR /usr/share/doc $MNT/doc
sync
rm -rf $MNT/doc/i*
umount $MNT
${fsck_cmd} -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
# Make the kernel run through again
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum,data=journal
cp -pR /usr/share/doc $MNT/blob
umount $MNT
${fsck_cmd} -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
# What happens if we don't specify any options?
${mount_cmd} $DEV $MNT -t ext4
set +x
mkdir $MNT/fragged/
for i in `seq 1 1000`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=${BLK_SZ} count=1 >> $MNT/fragged/fragfile 2> /dev/null > /dev/null
sync
done
set -x
truncate -s "-$((500 * BLK_SZ))" $MNT/fragged/fragfile
umount $MNT
${fsck_cmd} -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
fi
}
##############################
function corrupt_journal_sb_test {
msg "corrupt_journal_sb_test"
if [ "$(which mount)" != "/bin/mount" ]; then
msg "Ignoring journal test due to FUSE2FS."
else
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/doc
umount $MNT
${fsck_cmd} -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
# Fuzz part of the superblock
JSB_BLOCK="$(${E2FSPROGS}/debugfs/debugfs -n -R 'bmap <8> 0' "${DEV}")"
JSB_SECTOR=$(((JSB_BLOCK * (BLK_SZ/512)) + 1))
yes "${FUZZ}" | dd of=$DEV bs=512 seek=${JSB_SECTOR} count=1 > /dev/null 2> /dev/null
dd if=$DEV bs=$BLK_SZ skip=${JSB_BLOCK} count=1 | od -tx1 -Ad -c
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
# Make the kernel run through again
${fsck_cmd} -f -n $DEV || true
set +e
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
if [ $? -eq 0 ]; then
echo "Should not be able to mount with corrupt journal."
exit 50
fi
set -e
${fsck_cmd} -f -y $DEV || true
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
# Mount, copy more files
${mount_cmd} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc $MNT/next
umount $MNT
${fsck_cmd} -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
fi
}
#####################################
function mkfs_flag_collision_test_helper {
if [ ! -z "$1" ]; then
FEATURES="-O $1,^has_journal"
else
FEATURES="-O ^has_journal"
fi
FEATURE_STRING="$2"
if [ ! -z "$3" ]; then
ERROR_MSG="$3"
else
ERROR_MSG="$1"
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $FEATURES -F "${DEV}"
set +e
MCSUM=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep -c metadata_csum)
GCSUM=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep -c uninit_bg)
set -e
${fsck_cmd} -f -n $DEV
if [ "${MCSUM},${GCSUM}" != "${FEATURE_STRING}" ]; then
msg "FAIL mkfs ${ERROR_MSG}"
return 1
fi
msg "PASS mkfs ${ERROR_MSG}"
return 0
}
function mkfs_flag_collision_test {
msg "mkfs_flag_collision_test"
mkfs_flag_collision_test_helper "" "0,1" "no flags"
mkfs_flag_collision_test_helper "metadata_csum" "1,0"
# The following are actually tested in the tune2fs flag collision test
#mkfs_flag_collision_test_helper "metadata_csum,^uninit_bg" "1,0"
#mkfs_flag_collision_test_helper "^metadata_csum,uninit_bg" "0,1"
#mkfs_flag_collision_test_helper "metadata_csum,uninit_bg" "1,0"
#mkfs_flag_collision_test_helper "^metadata_csum,^uninit_bg" "0,0"
}
#####################################
function tune2fs_flag_collision_test_helper {
if [ ! -z "$1" ]; then
FEATURES="-O $1"
fi
FEATURE_STRING="$2"
ERROR_MSG="$1"
msg "TEST tune2fs ${ERROR_MSG}"
$VALGRIND ${E2FSPROGS}/misc/tune2fs $FEATURES "${DEV}"
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
if [ -z "${FEATURE_STRING}" ]; then
return 0
fi
set +e
MCSUM=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep -c metadata_csum)
GCSUM=$($VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep -c uninit_bg)
set -e
${fsck_cmd} -f -n $DEV
if [ "${MCSUM},${GCSUM}" != "${FEATURE_STRING}" ]; then
msg "FAIL tune2fs ${ERROR_MSG}"
return 1
fi
msg "PASS tune2fs ${ERROR_MSG}"
return 0
}
function tune2fs_flag_collision_test {
msg "tune2fs_flag_collision_test"
declare -A COMBOS
COMBOS[0]="^metadata_csum,^uninit_bg"
COMBOS[1]="metadata_csum,^uninit_bg"
COMBOS[2]="^metadata_csum,uninit_bg"
COMBOS[3]="metadata_csum,uninit_bg"
declare -A RESULTS
RESULTS[0]="0,0"
RESULTS[1]="1,0"
RESULTS[2]="0,1"
RESULTS[3]="1,0"
for i in ${!COMBOS[@]}; do
for j in ${!COMBOS[@]}; do
mkfs_flag_collision_test_helper "${COMBOS[$i]}" "${RESULTS[$i]}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/doc_a
umount $MNT
tune2fs_flag_collision_test_helper "${COMBOS[$j]}" "${RESULTS[$j]}"
done
done
}
#####################################
function remove_checksum_test {
msg "remove_checksum_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^has_journal,metadata_csum -F "${DEV}"
# Dump in some files
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/doc_a
umount $MNT
tune2fs_flag_collision_test_helper "^metadata_csum,uninit_bg" "0,1" "remove only metadata_csum"
tune2fs_flag_collision_test_helper "^uninit_bg" "0,0" "remove uninit_bg"
msg "fast disable"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^has_journal,metadata_csum -F "${DEV}"
# Dump in some files
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/doc_a
umount $MNT
tune2fs_flag_collision_test_helper "^metadata_csum,^uninit_bg" "0,0" "remove metadata_csum and uninit_bg"
}
#####################################
# Fill an FS with as big a file as we can allocate.
function fill_fs_with_file {
XDIR="$1"
FILE="$2"
FREE_KB="$(df -k "${XDIR}" | tail -n 1 | awk '{print $4}')"
SZ="$((FREE_KB - 65536))"
if [ "${SZ}" -lt 1 ]; then
SZ="${FREE_KB}"
fi
if [ "${SZ}" -eq 0 ]; then
return
fi
fallocate -l "${SZ}k" "${XDIR}/${FILE}"
dd if=/dev/zero of="${XDIR}/${FILE}" conv=notrunc oflag=append bs=65536k || true
}
function shrink_uninit_test {
msg "shrink_uninit_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -b $BLK_SZ -N 192 -F "${DEV}" 393216
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
mkdir -p $MNT/dirX/
j=0
touch $MNT/bigfile
set +x
echo '+ fill_fs'
while true; do
touch $MNT/dirX/file_${i}_${j} || break
j=$((j + 1))
done
set -x
fill_fs_with_file "${MNT}" "bigfile"
umount $MNT
sleep 1
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
rm -rf $MNT/dirX $MNT/bigfile
umount $MNT
for i in `seq 1 16`; do
${fsck_cmd} -fy $DEV || true
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/0
$VALGRIND ${E2FSPROGS}/resize/resize2fs -f $DEV $((393216 - ($i * 16384)))
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/1
${fsck_cmd} -f -n $DEV #|| true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
fill_fs_with_file "${MNT}" "bigfile"
sync
rm -rf $MNT/bigfile
umount $MNT
done
}
#####################################
# Nuke blockgroups at the start of a fresh FS
function nuke_blockgroups {
DEV="$1"
BAD_GROUPS="$2"
BLOCKS_PER_GROUP="$(${E2FSPROGS}/misc/dumpe2fs -h "${DEV}" | grep '^Blocks per group:' | awk '{print $4}')"
INODES_PER_GROUP="$(${E2FSPROGS}/misc/dumpe2fs -h "${DEV}" | grep '^Inodes per group:' | awk '{print $4}')"
FIRST_INODE="$(${E2FSPROGS}/misc/dumpe2fs -h "${DEV}" | grep '^First inode:' | awk '{print $3}')"
BAD_BLOCKS="$((BLOCKS_PER_GROUP * BAD_GROUPS))"
BAD_INODES="$((INODES_PER_GROUP * BAD_GROUPS))"
(
seq 0 "${BAD_GROUPS}" | sed -e 's/\(.*\)/set_bg \1 flags 0/g';
seq 0 "${BAD_GROUPS}" | sed -e 's/\(.*\)/set_bg \1 free_blocks_count 0/g';
seq 0 "${BAD_GROUPS}" | sed -e 's/\(.*\)/set_bg \1 free_inodes_count 0/g';
seq 0 "${BAD_GROUPS}" | sed -e 's/\(.*\)/set_bg \1 itable_unused 0/g';
# seq "$((FIRST_INODE + 1))" "${BAD_INODES}" | sed -e 's/\(.*\)/clri <\1>/g';
echo "setb 0 ${BAD_BLOCKS}";
echo "seti <1> ${BAD_INODES}"
) | ${E2FSPROGS}/debugfs/debugfs -w "${DEV}" > /dev/null 2>&1
}
function make_nuked_fs {
msg "make_nuked_fs"
BYTES="$(( $(blockdev --getsz "${DEV}") * 512 ))"
NR_FILES="$(( $(find /usr/share/doc | wc -l) * 4 * 23 / 10 ))"
NR_INODES="$((BYTES / 1048576))"
if [ "${NR_INODES}" -lt 40000 ]; then
NR_INODES=40000
fi
if [ "${NR_INODES}" -gt 1000000 ]; then
NR_INODES=1000000
fi
if [ "${NR_INODES}" -lt "${NR_FILES}" ]; then
NR_INODES="${NR_FILES}"
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^metadata_csum $MKFS_FEATURES -E lazy_itable_init=0 -N "${NR_INODES}" -F "${DEV}"
# Since the allocator is so effing smart, we have to manually cordon off the
# first 75% of the disk to force blocks to be allocated at the end of the disk.
BGROUPS="$(${E2FSPROGS}/misc/dumpe2fs "${DEV}" | grep "^Group" | tail -n -1 | sed -e 's/^Group \([0-9]*\):.*/\1/g')"
nuke_blockgroups "${DEV}" "$((BGROUPS * 3 / 4))"
${E2FSPROGS}/misc/dumpe2fs $DEV | egrep "(^Group|Free)"
}
function shrink_to_minimum_test {
msg "shrink_to_minimum_test"
BYTES="$(( $(blockdev --getsz "${DEV}") * 512 ))"
NR_FILES="$(( $(find /usr/share/doc | wc -l) * 4 * 23 / 10 ))"
NR_INODES="$((BYTES / 1048576))"
if [ "${NR_INODES}" -lt 40000 ]; then
NR_INODES=40000
fi
if [ "${NR_INODES}" -gt 1000000 ]; then
NR_INODES=1000000
fi
if [ "${NR_INODES}" -lt "${NR_FILES}" ]; then
NR_INODES="${NR_FILES}"
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^metadata_csum $MKFS_FEATURES -E lazy_itable_init=0 -N "${NR_INODES}" -F "${DEV}"
# Since the allocator is so effing smart, we have to manually cordon off the
# first 75% of the disk to force blocks to be allocated at the end of the disk.
BGROUPS="$(${E2FSPROGS}/misc/dumpe2fs "${DEV}" | grep "^Group" | tail -n -1 | sed -e 's/^Group \([0-9]*\):.*/\1/g')"
nuke_blockgroups "${DEV}" "$((BGROUPS * 3 / 4))"
${E2FSPROGS}/misc/dumpe2fs $DEV | egrep "(^Group|Free)"
# Now fill the fs
${mount_cmd} ${MOUNT_OPTS} "${DEV}" "${MNT}" -t ext4
set +x
echo '+ fillfs'
for i in `seq 1 64`; do
dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "${MNT}/frag1" 2> /dev/null
sync
dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "${MNT}/frag2" 2> /dev/null
sync
done
cp -pR /usr/share/doc/ $MNT/doc_a
cp -pR /usr/share/doc/ $MNT/doc_b
set -x
umount "${MNT}"
${fsck_cmd} -fy "${DEV}" > /dev/null 2>&1 || true
${fsck_cmd} -fn "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/0
$VALGRIND ${E2FSPROGS}/resize/resize2fs -M -f $DEV #-d28
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/1
${fsck_cmd} -f -n "${DEV}"
# Look for errors?
${mount_cmd} ${MOUNT_OPTS} "${DEV}" "${MNT}" -t ext4
find "${MNT}" -type f -print0 | xargs -0 cat > /dev/null
sync
umount "${MNT}"
}
#####################################
function shrink_init_test {
msg "shrink_init_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^uninit_bg $MKFS_FEATURES -b $BLK_SZ -N 192 -F "${DEV}" 393216
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
mkdir -p $MNT/dirX/
j=0
touch $MNT/bigfile
while true; do
touch $MNT/dirX/file_${i}_${j} || break
j=$((j + 1))
done
fill_fs_with_file "${MNT}" "bigfile"
umount $MNT
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
rm -rf $MNT/dirX $MNT/bigfile
umount $MNT
for i in `seq 1 16`; do
${fsck_cmd} -fy $DEV || true
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/0
$VALGRIND ${E2FSPROGS}/resize/resize2fs -f $DEV $((393216 - ($i * 16384)))
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/1
${fsck_cmd} -f -n $DEV #|| true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
fill_fs_with_file "${MNT}" "bigfile"
sync
rm -rf $MNT/bigfile
umount $MNT
done
}
#####################################
function grow_uninit_test {
msg "resize_test: uninit_bg"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -N 64 -F "${DEV}" 131072
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
for i in `seq 1 16`; do
${fsck_cmd} -fy $DEV || true
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/0
$VALGRIND ${E2FSPROGS}/resize/resize2fs -f $DEV $((131072 + ($i * 16384)))
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/1
${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
mkdir -p $MNT/dirX/
j=0
touch $MNT/bigfile
while true; do
touch $MNT/dirX/file_${i}_${j} || break
j=$((j + 1))
done
fill_fs_with_file "${MNT}" "bigfile"
umount $MNT
${fsck_cmd} -f -n $DEV
done
}
######################################
function grow_init_test {
msg "resize_init_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^has_journal,^uninit_bg -N 64 -F "${DEV}" 131072
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
for i in `seq 1 16`; do
${fsck_cmd} -fy $DEV || true
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/0
$VALGRIND ${E2FSPROGS}/resize/resize2fs -f $DEV $((131072 + ($i * 16384)))
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/1
${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
mkdir -p $MNT/dirY/
j=0
touch $MNT/bigfile
while true; do
touch $MNT/dirY/file_${i}_${j} || break
j=$((j+1))
done
fill_fs_with_file "${MNT}" "bigfile"
umount $MNT
${fsck_cmd} -f -n $DEV
done
}
#####################################
function online_grow_uninit_helper {
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
for i in `seq 1 16`; do
${fsck_cmd} -fy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV
$VALGRIND ${E2FSPROGS}/resize/resize2fs -f $DEV $((131072 + ($i * 16384)))
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV
${fsck_cmd} -f -n $DEV
mkdir -p $MNT/dirX/
j=0
touch $MNT/bigfile
while true; do
touch $MNT/dirX/file_${i}_${j} || break
j=$((j + 1))
done
fill_fs_with_file "${MNT}" "bigfile"
umount $MNT
# XXX: this is broken, even before metadata_csum came about
${fsck_cmd} -f -n $DEV
done
}
function online_grow_uninit_test {
msg "online_resize_test: uninit_bg"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^has_journal -N 64 -F "${DEV}" 131072
# bigalloc doesn't do online resize
if [ "$(${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | grep -c "bigalloc")" -gt 0 ]; then
msg "There is no online resize with bigalloc."
elif [ "$(which mount)" != "/bin/mount" ]; then
msg "There is no online resize with fuse2fs."
else
online_grow_uninit_helper
fi
}
######################################
function online_grow_init_helper {
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
for i in `seq 1 16`; do
${fsck_cmd} -fy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
$VALGRIND ${E2FSPROGS}/resize/resize2fs -f $DEV $((131072 + ($i * 16384)))
mkdir -p $MNT/dirY/
j=0
touch $MNT/bigfile
while true; do
touch $MNT/dirY/file_${i}_${j} || break
j=$((j+1))
done
fill_fs_with_file "${MNT}" "bigfile"
umount $MNT
${fsck_cmd} -f -n $DEV
done
}
function online_grow_init_test {
msg "online_resize_init_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^has_journal,^uninit_bg -N 64 -F "${DEV}" 131072
# bigalloc doesn't do online resize
if [ "$(${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | grep -c "bigalloc")" -gt 0 ]; then
msg "There is no online resize with bigalloc."
elif [ "$(which mount)" != "/bin/mount" ]; then
msg "There is no online resize with fuse2fs."
else
online_grow_init_helper
fi
}
#####################################
function simple_prep_fs {
msg "Create fs with files, dirs, EAs, htree dirs, etc."
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
# Dump in some files
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/doc_a
mkdir -p $MNT/fragged
dd if=/dev/zero bs=4k count=1 of=$MNT/fragged/fragfile
sync
set +x
echo + frag
for i in `seq 1 8`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
echo moo > $MNT/ea_file
set +x
echo + set_ea
nr_attrs="$((BLK_SZ * 100 / 4096))"
for i in `seq -w 1 ${nr_attrs}`; do
attr -s $i -V $i $MNT/ea_file
done
# add some random files
cp -pR /usr/share/doc/ $MNT/doc_b
# create htree
mkdir -p $MNT/bigdir2
set +x
echo + htree2
for i in `seq 1 256`; do
echo moo > "$MNT/bigdir2/$(echo "$(date)_$i" | md5sum)"
done
set -x
# Fragment a file
set +x
echo + frag
for i in `seq 9 18`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
# Rewrite extent tree
set +x
echo + frag
for i in `seq 19 28`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
# Truncate
truncate -s -64k $MNT/fragged/fragfile
# More rewrites
set +x
echo + frag
for i in `seq 29 38`; do
echo moo > $MNT/fragged/a$i
sync
dd if=/dev/zero bs=4k count=1 >> $MNT/fragged/fragfile
sync
done
set -x
# multi-level htree
mkdir $MNT/3
echo moo > $MNT/3/base.txt
set +x
echo + mltree
NUM_FILES="$(( (BLK_SZ / 250) * ((BLK_SZ - 18) / 8) * 2 ))"
seq 1 $NUM_FILES | while read f; do
if [ $((f % 71)) -eq 0 ]; then
echo -n "$f..."
fi
FNAME=$(perl -e "printf(\"%.250s\\n\", \"_$f\" x 256);")
ln $MNT/3/base.txt $MNT/3/$FNAME
done
echo
set -x
umount $MNT
# Re-walk fs looking for errors
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
attr -l $MNT/ea_file > /dev/null
umount $MNT/
# Check fs again
${fsck_cmd} -f -n $DEV
echo 'Filesystem created; please mount with -o journal_checksum'
}
################################
function disable_64bit_helper {
msg "turn off 64bit; flags=\"$1\""
if [ -n "$1" ]; then
FLAGS="64bit,$1"
else
FLAGS="64bit"
fi
BLKS="$(( $(blockdev --getsz "${DEV}") * 512 / BLK_SZ ))"
if [ "${BLKS}" -gt 4000000000 ]; then
BLKS=4000000000
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum_noresize $MKFS_OPTS $MKFS_FEATURES -O "${FLAGS}" -b "${BLK_SZ}" -F "${DEV}" "${BLKS}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/doc_a
sz="$(( $(df -k "${MNT}" | awk '{print $4}' | tail -n1) * 8 / 10))"
fallocate -l "${sz}k" "${MNT}/big"
stat "${MNT}/big"
umount $MNT
# Convert from 64bit to 32bit.
${fsck_cmd} -f -y $DEV || true
${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/0
${E2FSPROGS}/debugfs/debugfs -R 'stat <12>' "${DEV}" > /tmp/a
#dd if="${DEV}" bs="${BLK_SZ}" skip=34 count=1 | od -tx1 -Ad -c > /tmp/a
${VALGRIND} ${E2FSPROGS}/resize/resize2fs -f -d28 -p -s $DEV
${E2FSPROGS}/debugfs/debugfs -R 'stat <12>' "${DEV}" > /tmp/b
#dd if="${DEV}" bs="${BLK_SZ}" skip=34 count=1 | od -tx1 -Ad -c > /tmp/b
${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/1
${fsck_cmd} -f -n $DEV
}
function disable_64bit_noflags_test {
disable_64bit_helper ""
}
function disable_64bit_no_resize_inode_test {
disable_64bit_helper "^resize_inode"
}
function disable_64bit_meta_bg_test {
disable_64bit_helper "meta_bg,^resize_inode"
}
################################
function enable_64bit_helper {
msg "turn on 64bit, flags=\"$1\""
if [ -n "$1" ]; then
FLAGS="^64bit,$1"
else
FLAGS="^64bit"
fi
BLKS="$(( $(blockdev --getsz "${DEV}") * 512 / BLK_SZ ))"
if [ "${BLKS}" -gt 4000000000 ]; then
BLKS=4000000000
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum_noresize $MKFS_OPTS $MKFS_FEATURES -O "${FLAGS}" -b "${BLK_SZ}" -F "${DEV}" "${BLKS}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pR /usr/share/doc/ $MNT/doc_a
sz="$(( $(df -k "${MNT}" | awk '{print $4}' | tail -n1) * 8 / 10))"
fallocate -l "${sz}k" "${MNT}/big"
stat "${MNT}/big"
umount $MNT
# Convert from 32bit to 64bit.
${fsck_cmd} -f -y $DEV || true
${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/0
#gdb --args ${VALGRIND} ${E2FSPROGS}/resize/resize2fs -d28 -p $DEV
${VALGRIND} ${E2FSPROGS}/resize/resize2fs -f -d28 -p -b $DEV
${E2FSPROGS}/misc/dumpe2fs $DEV > /tmp/1 || true
${fsck_cmd} -f -n $DEV
}
function enable_64bit_noflags_test {
enable_64bit_helper ""
}
function enable_64bit_no_resize_inode_test {
enable_64bit_helper "^resize_inode"
}
function enable_64bit_meta_bg_test {
enable_64bit_helper "^resize_inode,meta_bg"
}
# Leave this at the end
################################
function corrupt_sb_test {
msg "corrupt_sb_test"
# write junk into last error field
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -i 524288 -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
BACKUP_SB="$(${E2FSPROGS}/misc/dumpe2fs $DEV 2> /dev/null | grep "Backup superblock at " | sed -e 's/Backup superblock at \([0-9]*\).*/\1/g' | head -n 1)"
${fsck_cmd} -f -n $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep UUID
yes "${FUZZ}" | dd of=$DEV bs=32 seek=47 count=1 > /dev/null 2> /dev/null
# fsck -n will modify the fs due to backup sb being used ! DO NOT RUN THIS: ${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum && echo should not get here && exit 50
${fsck_cmd} -f -y -D $DEV || ${fsck_cmd} -f -y -D -b ${BACKUP_SB} "${DEV}" || true
${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/file
umount $MNT
${fsck_cmd} -f -n $DEV
# totally destroy sb
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -i 524288 -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
BACKUP_SB="$(${E2FSPROGS}/misc/dumpe2fs $DEV 2> /dev/null | grep "Backup superblock at " | sed -e 's/Backup superblock at \([0-9]*\).*/\1/g' | head -n 1)"
${fsck_cmd} -f -n $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep UUID
blk=0
if [ "${BLK_SZ}" -eq "1024" ]; then
blk=1
fi
yes "${FUZZ}" | dd of=$DEV bs=$BLK_SZ seek=${blk} count=1 > /dev/null 2> /dev/null
# fsck -n will modify the fs due to backup sb being used ! DO NOT RUN THIS: ${fsck_cmd} -f -n $DEV
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum && echo should not get here && exit 50
${fsck_cmd} -f -y -D $DEV || ${fsck_cmd} -f -y -D -b ${BACKUP_SB} "${DEV}" || true
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/file
umount $MNT
${fsck_cmd} -f -n $DEV
}
############################
function hugefs_offline_grow_test {
msg "hugefs_offline_grow_test"
if [ -z "${HUGE_DEV}" ]; then
msg "Device is not large enough to host a hugedev."
else
MUST_DELETE=0
if [ ! -b "${HUGE_DEV}" ]; then
MUST_DELETE=1
${DIR}/hugedisk.sh "${HUGE_DEV_NAME}" "${DEV}" 20t
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES 18t -F "${HUGE_DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum "${HUGE_DEV}"
${E2FSPROGS}/misc/dumpe2fs -h "${HUGE_DEV}" 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy "${HUGE_DEV}" || true
${mount_cmd} ${MOUNT_OPTS} "${HUGE_DEV}" "${MNT}" -t ext4 -o journal_checksum
fallocate -l 8t "${MNT}/bigfile1"
fallocate -l 8t "${MNT}/bigfile2"
fallocate -l 1t "${MNT}/bigfile3"
cp -pR /usr/share/doc "${MNT}/doc"
umount "${MNT}"
${fsck_cmd} -C0 -f -y "${HUGE_DEV}"
${E2FSPROGS}/resize/resize2fs -d28 -f "${HUGE_DEV}" 20t
${fsck_cmd} -C0 -f -n "${HUGE_DEV}"
set +e
test "${MUST_DELETE}" -gt 1 && ${DIR}/hugedisk.sh "${HUGE_DEV_NAME}" "${DEV}" 0
set -e
fi
}
############################
function hugefs_online_grow_test {
msg "hugefs_online_grow_test"
if [ -z "${HUGE_DEV}" ]; then
msg "Device is not large enough to host a hugedev."
elif [ "$(which mount)" != "/bin/mount" ]; then
msg "There is no online resize with fuse2fs."
else
MUST_DELETE=0
if [ ! -b "${HUGE_DEV}" ]; then
MUST_DELETE=1
${DIR}/hugedisk.sh "${HUGE_DEV_NAME}" "${DEV}" 20t
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES 18t -F "${HUGE_DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum "${HUGE_DEV}"
${E2FSPROGS}/misc/dumpe2fs -h "${HUGE_DEV}" 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy "${HUGE_DEV}" || true
${mount_cmd} ${MOUNT_OPTS} "${HUGE_DEV}" "${MNT}" -t ext4 -o journal_checksum
fallocate -l 8t "${MNT}/bigfile1"
fallocate -l 8t "${MNT}/bigfile2"
fallocate -l 1t "${MNT}/bigfile3"
cp -pR /usr/share/doc "${MNT}/doc"
${E2FSPROGS}/resize/resize2fs -d28 -f "${HUGE_DEV}" 20t
umount "${MNT}"
${fsck_cmd} -C0 -f -n "${HUGE_DEV}"
set +e
test "${MUST_DELETE}" -gt 0 && ${DIR}/hugedisk.sh "${HUGE_DEV_NAME}" "${DEV}" 0
set -e
fi
}
##########################
function hugefs_shrink_test {
msg "hugefs_shrink_test"
if [ -z "${HUGE_DEV}" ]; then
msg "Device is not large enough to host a hugedev."
else
MUST_DELETE=0
if [ ! -b "${HUGE_DEV}" ]; then
MUST_DELETE=1
${DIR}/hugedisk.sh "${HUGE_DEV_NAME}" "${DEV}" 20t
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS $MKFS_FEATURES -F "${HUGE_DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum "${HUGE_DEV}"
${E2FSPROGS}/misc/dumpe2fs -h "${HUGE_DEV}" 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy "${HUGE_DEV}" || true
${mount_cmd} ${MOUNT_OPTS} "${HUGE_DEV}" "${MNT}" -t ext4 -o journal_checksum
fallocate -l 8t "${MNT}/bigfile1"
fallocate -l 8t "${MNT}/bigfile2"
fallocate -l 1t "${MNT}/bigfile3"
cp -pR /usr/share/doc "${MNT}/doc"
umount "${MNT}"
${fsck_cmd} -C0 -f -y "${HUGE_DEV}"
${E2FSPROGS}/resize/resize2fs -d28 -f "${HUGE_DEV}" 18t
${fsck_cmd} -C0 -f -n "${HUGE_DEV}"
set +e
test "${MUST_DELETE}" -gt 0 && ${DIR}/hugedisk.sh "${HUGE_DEV_NAME}" "${DEV}" 0
set -e
fi
}
################################
function prep_punch_util {
# Utility to punch holes
if [ ! -x /tmp/punch ]; then
cat > /tmp/punch.c << ENDL
/* Punch hole in file */
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <linux/falloc.h>
uint64_t get_number(const char *string)
{
int sz = strlen(string);
double result = atof(string);
char last = string[sz - 1];
switch (last) {
case 'k':
case 'K':
result *= 1024;
break;
case 'm':
case 'M':
result *= 1048576;
break;
case 'g':
case 'G':
result *= 1073741824;
break;
}
return result;
}
int main(int argc, char *argv[])
{
int fd, ret;
off_t start, len;
if (argc != 4) {
printf("Usage: %s filename start len\n", argv[0]);
return 1;
}
errno = 0;
start = get_number(argv[2]);
len = get_number(argv[3]);
if (errno) {
perror("start/len");
return 1;
}
fd = open(argv[1], O_RDWR);
if (fd < 0) {
perror(argv[1]);
return 1;
}
ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, start, len);
if (ret) {
perror(argv[1]);
return 1;
}
ret = fsync(fd);
if (ret) {
perror(argv[1]);
return 1;
}
close(fd);
return 0;
}
ENDL
gcc -O2 -Wall -g -o /tmp/punch /tmp/punch.c
fi
}
function punch_extent_test {
msg "punch_extent_test"
# We can't punch bigalloc with the in-kernel driver...
set +e
IS_BIGALLOC="$(grep -c bigalloc /tmp/mke2fs.conf)"
MOUNTER="$(which mount)"
set -e
if [ "${IS_BIGALLOC}" -gt 0 -a "${MOUNTER}" = "/bin/mount" ]; then
msg "In-kernel driver unable to punch with bigalloc"
else
prep_punch_util
# Make sure we have a big enough cluster
if [ "${IS_BIGALLOC}" -gt 0 ]; then
BIGALLOC_ARGS="-C $((BLK_SZ * 16))"
fi
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS -O extent ${BIGALLOC_ARGS} -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
# Create some sparse files
${mount_cmd} ${MOUNT_OPTS} "${DEV}" "${MNT}" -t ext4 -o journal_checksum
for i in beg mid end all; do
dd if=/dev/zero of="${MNT}/${i}" bs=1 conv=notrunc count=1 seek=0
dd if=/dev/zero of="${MNT}/${i}" bs=1 conv=notrunc count=1 seek=$((BLK_SZ * 2))
dd if=/dev/zero of="${MNT}/${i}" bs=1 conv=notrunc count=1 seek=$(((BLK_SZ * 16) - 1))
dd if=/dev/zero of="${MNT}/${i}" bs=1 conv=notrunc count=1 seek=$((BLK_SZ * 16))
done
for i in 0 12 $(( (BLK_SZ / 4) + 12 )) $(( ((BLK_SZ / 4) ** 2) + (BLK_SZ / 4) + 12)); do
dd if=/dev/zero of="${MNT}/bigfile" bs="${BLK_SZ}" count=8 seek="$((i + 2))"
done
umount "${MNT}"
${fsck_cmd} -C0 -f -n "${DEV}"
# Now punch holes in the files
echo -en 'stat /beg\nstat /mid\nstat /end\nstat /all\nstat /bigfile' | ${E2FSPROGS}/debugfs/debugfs "${DEV}" > /tmp/stat0
${mount_cmd} ${MOUNT_OPTS} "${DEV}" "${MNT}" -t ext4 -o journal_checksum
/tmp/punch "${MNT}/beg" 0 "${BLK_SZ}"
/tmp/punch "${MNT}/mid" "$((BLK_SZ * 2))" "${BLK_SZ}"
/tmp/punch "${MNT}/end" "$((BLK_SZ * 15))" "${BLK_SZ}"
/tmp/punch "${MNT}/all" 0 "$((BLK_SZ * 64))"
for i in 0 12 $(( (BLK_SZ / 4) + 12 )) $(( ((BLK_SZ / 4) ** 2) + (BLK_SZ / 4) + 12)); do
for j in 2 5 8; do
/tmp/punch "${MNT}/bigfile" "$(( BLK_SZ * (i + j) ))" "$((BLK_SZ * 2))"
done
done
umount "${MNT}"
echo -en 'stat /beg\nstat /mid\nstat /end\nstat /all\nstat /bigfile' | ${E2FSPROGS}/debugfs/debugfs "${DEV}" > /tmp/stat1
diff -u /tmp/stat0 /tmp/stat1 || true
${fsck_cmd} -C0 -f -n "${DEV}"
# Do we still have the parts of the files that we expected?
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /beg 0' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /beg 2' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /beg 15' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /beg 16' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /mid 0' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /mid 2' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /mid 15' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /mid 16' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /end 0' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /end 2' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /end 15' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /end 16' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /all 0' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /all 2' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /all 15' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /all 16' "${DEV}")" -eq 0
for i in 0 12 $(( (BLK_SZ / 4) + 12 )) $(( ((BLK_SZ / 4) ** 2) + (BLK_SZ / 4) + 12)); do
for j in 1 2 3 5 6 8 9 10; do
test "$(${E2FSPROGS}/debugfs/debugfs -R "bmap /bigfile $((i + j))" "${DEV}")" -eq 0
done
for j in 4 7; do
test "$(${E2FSPROGS}/debugfs/debugfs -R "bmap /bigfile $((i + j))" "${DEV}")" -gt 0
done
done
fi
}
function punch_ind_test {
msg "punch_ind_test"
prep_punch_util
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum $MKFS_OPTS -O ^extent,^bigalloc,^64bit -F "${DEV}"
test -z "$NO_CSUM" && $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || ${fsck_cmd} -fDy $DEV || true
# Create some sparse files
${mount_cmd} ${MOUNT_OPTS} "${DEV}" "${MNT}" -t ext4 -o journal_checksum
for i in beg mid end all; do
dd if=/dev/zero of="${MNT}/${i}" bs=1 conv=notrunc count=1 seek=0
dd if=/dev/zero of="${MNT}/${i}" bs=1 conv=notrunc count=1 seek=$((BLK_SZ * 2))
dd if=/dev/zero of="${MNT}/${i}" bs=1 conv=notrunc count=1 seek=$(((BLK_SZ * 16) - 1))
dd if=/dev/zero of="${MNT}/${i}" bs=1 conv=notrunc count=1 seek=$((BLK_SZ * 16))
done
for i in 0 12 $(( (BLK_SZ / 4) + 12 )) $(( ((BLK_SZ / 4) ** 2) + (BLK_SZ / 4) + 12)); do
dd if=/dev/zero of="${MNT}/bigfile" bs="${BLK_SZ}" count=8 seek="$((i + 2))"
done
umount "${MNT}"
${fsck_cmd} -C0 -f -n "${DEV}"
# Now punch holes in the files
echo -en 'stat /beg\nstat /mid\nstat /end\nstat /all\nstat /bigfile' | ${E2FSPROGS}/debugfs/debugfs "${DEV}" > /tmp/stat0
${mount_cmd} ${MOUNT_OPTS} "${DEV}" "${MNT}" -t ext4 -o journal_checksum
/tmp/punch "${MNT}/beg" 0 "${BLK_SZ}"
/tmp/punch "${MNT}/mid" "$((BLK_SZ * 2))" "${BLK_SZ}"
/tmp/punch "${MNT}/end" "$((BLK_SZ * 15))" "${BLK_SZ}"
/tmp/punch "${MNT}/all" 0 "$((BLK_SZ * 64))"
for i in 0 12 $(( (BLK_SZ / 4) + 12 )) $(( ((BLK_SZ / 4) ** 2) + (BLK_SZ / 4) + 12)); do
for j in 2 5 8; do
/tmp/punch "${MNT}/bigfile" "$(( BLK_SZ * (i + j) ))" "$((BLK_SZ * 2))"
done
done
umount "${MNT}"
echo -en 'stat /beg\nstat /mid\nstat /end\nstat /all\nstat /bigfile' | ${E2FSPROGS}/debugfs/debugfs "${DEV}" > /tmp/stat1
diff -u /tmp/stat0 /tmp/stat1 || true
${fsck_cmd} -C0 -f -n "${DEV}"
# Do we still have the parts of the files that we expected?
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /beg 0' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /beg 2' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /beg 15' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /beg 16' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /mid 0' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /mid 2' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /mid 15' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /mid 16' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /end 0' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /end 2' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /end 15' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /end 16' "${DEV}")" -gt 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /all 0' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /all 2' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /all 15' "${DEV}")" -eq 0
test "$(${E2FSPROGS}/debugfs/debugfs -R 'bmap /all 16' "${DEV}")" -eq 0
for i in 0 12 $(( (BLK_SZ / 4) + 12 )) $(( ((BLK_SZ / 4) ** 2) + (BLK_SZ / 4) + 12)); do
for j in 1 2 3 5 6 8 9 10; do
test "$(${E2FSPROGS}/debugfs/debugfs -R "bmap /bigfile $((i + j))" "${DEV}")" -eq 0
done
for j in 4 7; do
test "$(${E2FSPROGS}/debugfs/debugfs -R "bmap /bigfile $((i + j))" "${DEV}")" -gt 0
done
done
}
##########################
function mke2fs_options_helper {
BLOCKSIZE="$1"
CLUSTER_RATIO="$2"
SIZE="$3"
FEATURES="$4"
BITNESS="$5"
IMAGE="/tmp/moo.img"
for sz_verb in cmdline devsize; do
for bs_verb in env cmdline cfgfile none; do
rm -rf "${IMAGE}"
if [ "${sz_verb}" = "devsize" ]; then
dd if=/dev/zero of="${IMAGE}" bs=1024 count=1 seek="$(( SIZE - 1))"
CMDLINE_SZ=
else
dd if=/dev/zero of="${IMAGE}" bs=1024 count=1 seek="$(( (SIZE * 2) - 1))"
if [ "${bs_verb}" = "cmdline" ]; then
CMDLINE_SZ="$((SIZE / (BLOCKSIZE / 1024) ))"
else
CMDLINE_SZ="${SIZE}"
fi
fi
case "${bs_verb}" in
"env")
MKE2FS_DEVICE_SECTSIZE="${BLOCKSIZE}"
export MKE2FS_DEVICE_SECTSIZE
CFGFILE_BS="blocksize = 1024"
CMDLINE_BS=
;;
"cfgfile")
unset MKE2FS_DEVICE_SECTSIZE
CFGFILE_BS="blocksize = ${BLOCKSIZE}"
CMDLINE_BS=
;;
"cmdline")
unset MKE2FS_DEVICE_SECTSIZE
CFGFILE_BS="blocksize = 1024"
CMDLINE_BS="-b ${BLOCKSIZE}"
;;
"none")
unset MKE2FS_DEVICE_SECTSIZE
CFGFILE_BS=
CMDLINE_BS=
;;
esac
case "${BITNESS}" in
"32")
BITNESS_FEATURE=
BITNESS_CLAUSE=
;;
"64")
BITNESS_FEATURE=",64bit"
BITNESS_CLAUSE=
;;
"auto")
BITNESS_FEATURE=
BITNESS_CLAUSE="auto_64-bit_support=1"
;;
esac
if [ "${CLUSTER_RATIO}" -gt 1 ]; then
BIGALLOC_FEATURE=",bigalloc"
else
BIGALLOC_FEATURE=
fi
if [ "${bs_verb}" = "none" ]; then
EXPECTED_BLOCKSIZE=4096
else
EXPECTED_BLOCKSIZE="${BLOCKSIZE}"
fi
EXPECTED_BLOCKS="$(( SIZE / (EXPECTED_BLOCKSIZE / 1024) ))"
MKE2FS_CONFIG=/tmp/mke2fs2.conf
export MKE2FS_CONFIG
cat > "${MKE2FS_CONFIG}" << ENDL
[defaults]
base_features = ${FEATURES}${BITNESS_FEATURE}${BIGALLOC_FEATURE}
default_mntopts = acl,user_xattr,block_validity
enable_periodic_fsck = 0
${CFGFILE_BS}
cluster_size = $((CLUSTER_RATIO * EXPECTED_BLOCKSIZE))
inode_size = 256
inode_ratio = 16384
${BITNESS_CLAUSE}
ENDL
FAIL=0
${VALGRIND} ${E2FSPROGS}/misc/mke2fs -n ${CMDLINE_BS} ${CMDLINE_SZ} -F "${IMAGE}" > "/tmp/icsum.$$" 2>&1 || FAIL=1
if [ "${EXPECTED_BLOCKS}" -gt "$((2**32))" -a "${BITNESS}" = "32" ]; then
EXPECTED_BLOCKS=0
EXPECTED_BLOCKSIZE=0
fi
if [ "${FAIL}" -gt 0 ]; then
EXPECTED_BLOCKS=0
EXPECTED_BLOCKSIZE=0
fi
OUT_BS="$(grep 'Block size=' "/tmp/icsum.$$" | sed -e 's/^.*=\([0-9]*\) .*$/\1/g')"
OUT_BLOCKS="$(grep '^[0-9]* inodes, [0-9]* blocks$' "/tmp/icsum.$$" | awk '{print $3}')"
if [ -z "${OUT_BS}" ]; then
OUT_BS=0
fi
if [ -z "${OUT_BLOCKS}" ]; then
OUT_BLOCKS=0
fi
if [ "${OUT_BS}" -ne "${EXPECTED_BLOCKSIZE}" -o \
"${OUT_BLOCKS}" -lt "$(( EXPECTED_BLOCKS * 95 / 100))" -o \
"${OUT_BLOCKS}" -gt "$(( EXPECTED_BLOCKS * 105 / 100))" ]; then
res="FAIL:"
cat "/tmp/icsum.$$"
else
res="OK: "
fi
echo "${res} size=${SIZE}k,${sz_verb} bs=${BLOCKSIZE}, ebs=${EXPECTED_BLOCKSIZE},${bs_verb},${CLUSTER_RATIO} bit=${BITNESS} blocks=${EXPECTED_BLOCKS}; fs_bs=${OUT_BS} fs_blocks=${OUT_BLOCKS}"
done
done
rm -rf "/tmp/icsum.$$" "${IMAGE}"
}
function mke2fs_options_test {
msg "mke2fs_options_test"
FEATURES="sparse_super,filetype,resize_inode,dir_index,ext_attr,has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize"
LOGFILE="/tmp/icsum.mkfsopts.log"
rm -rf "${LOGFILE}"
for fs_size in 1440 102400 1048576 $((20 * 1073741824)); do
for bs in 1024 4096 8192 65536; do
for cluster_sizes in 1 2 16; do
for bitness in 32 64 auto; do
echo "--------------" >> "${LOGFILE}"
mke2fs_options_helper "${bs}" "${cluster_sizes}" "${fs_size}" "${FEATURES}" "${bitness}" >> "${LOGFILE}"
done
done
done
done
if [ "$(grep FAIL "${LOGFILE}" | wc -l)" -gt 0 ]; then
cat "${LOGFILE}"
return 1
fi
}
# This test should be the last one (before speed tests, anyway)
#### ALL SPEED TESTS GO AT THE END
##########################
function prep_speed_test {
test "${SKIP_SPEED_TESTS}" -gt 0 && return
VER=3.9.1
if [ ! -r /tmp/linux-${VER}.tar.xz ]; then
cp "${DIR}/linux-${VER}.tar.xz" /tmp/
fi
if [ ! -r /tmp/tarfiles ]; then
tar tvf /tmp/linux-${VER}.tar.xz > /tmp/tarfiles
fi
if [ ! -r /tmp/dirs -o ! -r /tmp/files -o ! -r /tmp/topdirs ]; then
rm -rf /tmp/dirs /tmp/files /tmp/topdirs
for i in a1 a2 a3 a4 a5 a6 a7 a8 a9 aA aB aC aD aE aF; do
cat /tmp/tarfiles | grep ^d | awk "{printf(\"$i/%s\n\", \$6);}" >> /tmp/dirs
cat /tmp/tarfiles | grep -v ^d | awk "{printf(\"%s $i/%s\n\", \$3, \$6);}" >> /tmp/files
echo "$i" >> /tmp/topdirs
done
fi
if [ ! -x /tmp/fab ]; then
cat > /tmp/fab.c << ENDL
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc, char *argv[])
{
FILE *fp;
int fd, ret;
size_t size;
char *space;
char buf[1024];
if (argc < 2) {
printf("Usage: %s file_containing_sz_name_pairs\n", argv[0]);
return 4;
}
fp = fopen(argv[1], "r");
if (!fp) {
perror(argv[1]);
return 5;
}
while (fgets(buf, 1024, fp)) {
buf[strlen(buf) - 1] = 0;
space = strchr(buf, ' ');
if (!space) {
fprintf(stderr, "space not found at line \"%s\"!\n", buf);
break;
}
*space = 0;
space++;
fd = open(space, O_WRONLY | O_CREAT, 0644);
if (fd < 0) {
perror(space);
break;
}
size = strtoul(buf, NULL, 0);
if (size) {
ret = posix_fallocate(fd, 0, size);
if (ret) {
errno = ret;
perror(space);
close(fd);
break;
}
}
close(fd);
}
fclose(fp);
return 0;
}
ENDL
gcc -o /tmp/fab /tmp/fab.c
fi
}
function tune2fs_speed_test {
test "${SKIP_SPEED_TESTS}" -gt 0 && return
msg "tune2fs_speed_test"
prep_speed_test
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^metadata_csum -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cd $MNT
set +x
echo + mkdirs
mkdir -p $(cat /tmp/dirs)
set -x
/tmp/fab /tmp/files
cd -
umount $MNT
/usr/bin/time $VALGRIND ${E2FSPROGS}/misc/tune2fs -O metadata_csum $DEV
/usr/bin/time ${fsck_cmd} -f -y -D $DEV || true
}
function all_speed_test {
test "${SKIP_SPEED_TESTS}" -gt 0 && return
msg "all_speed_test"
prep_speed_test
msg "All checksums including journal and data=journal"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O metadata_csum -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum,data=journal
cd $MNT
/usr/bin/time bash -c "mkdir -p \$(cat /tmp/dirs); /tmp/fab /tmp/files; sync"
/usr/bin/time bash -c "rm -rf \$(cat /tmp/topdirs); sync"
cd -
umount $MNT
}
function most_speed_test {
test "${SKIP_SPEED_TESTS}" -gt 0 && return
msg "most_speed_test"
prep_speed_test
msg "All checksums including journal and data=ordered"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O metadata_csum -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cd $MNT
/usr/bin/time bash -c "mkdir -p \$(cat /tmp/dirs); /tmp/fab /tmp/files; sync"
/usr/bin/time bash -c "rm -rf \$(cat /tmp/topdirs); sync"
cd -
umount $MNT
}
function none_speed_test {
test "${SKIP_SPEED_TESTS}" -gt 0 && return
msg "none_speed_test"
prep_speed_test
msg "No checksums at all"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^metadata_csum -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
cd $MNT
/usr/bin/time bash -c "mkdir -p \$(cat /tmp/dirs); /tmp/fab /tmp/files; sync"
/usr/bin/time bash -c "rm -rf \$(cat /tmp/topdirs); sync"
cd -
umount $MNT
}
######################
function ext_speed_test {
test "${SKIP_SPEED_TESTS}" -gt 0 && return
msg "ext_speed_test"
prep_speed_test
msg "All ext4 checksums, no journal checksum"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O metadata_csum -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
cd $MNT
/usr/bin/time bash -c "mkdir -p \$(cat /tmp/dirs); /tmp/fab /tmp/files; sync"
/usr/bin/time bash -c "rm -rf \$(cat /tmp/topdirs); sync"
cd -
umount $MNT
msg "All ext4 checksums except use old bg method, no journal checksum"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -T ext4icsum -O ^uninit_bg,metadata_csum -F "${DEV}"
${mount_cmd} ${MOUNT_OPTS} $DEV $MNT -t ext4
cd $MNT
/usr/bin/time bash -c "mkdir -p \$(cat /tmp/dirs); /tmp/fab /tmp/files; sync"
/usr/bin/time bash -c "rm -rf \$(cat /tmp/topdirs); sync"
cd -
umount $MNT
}
#####################
# Allow restarting of a test run by giving the test name and a plus sign.
VERBS_LEN="${#VERBS}"
if [ "${VERBS:VERBS_LEN - 1}" = "+" ]; then
VERB_STEM="${VERBS:0:VERBS_LEN-1}"
VERBS="$(grep "^function ${VERB_STEM}" -A 99999 $0 | grep '^function.*_test ' | awk '{print $2}')"
fi
orig_dev="${DEV}"
for verb in $(echo "${VERBS}" | tr ':,' ' '); do
curr_test="${verb}"
if [ "${FUZZ_DEV}" -gt 0 ]; then
${DIR}/hugedisk.sh "fuzzy" "${orig_dev}" "$(blockdev --getsz "${orig_dev}")"
DEV="/dev/mapper/fuzzy"
fi
$verb
done
####################################
trap 'msg "Finished successfully, ENJOY."; exit 0' EXIT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment