Last active
December 21, 2015 22:09
-
-
Save djwong/6372995 to your computer and use it in GitHub Desktop.
ext4 metadata checksumming test script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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