lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20120313004117.GV15164@tux1.beaverton.ibm.com>
Date:	Mon, 12 Mar 2012 17:41:17 -0700
From:	"Darrick J. Wong" <djwong@...ibm.com>
To:	"Ted Ts'o" <tytso@....edu>
Cc:	Andreas Dilger <adilger.kernel@...ger.ca>,
	Sunil Mushran <sunil.mushran@...cle.com>,
	Amir Goldstein <amir73il@...il.com>,
	Andi Kleen <andi@...stfloor.org>,
	Mingming Cao <cmm@...ibm.com>,
	Joel Becker <jlbec@...lplan.org>, linux-ext4@...r.kernel.org,
	Coly Li <colyli@...il.com>
Subject: Re: [PATCH v3 00/54] e2fsprogs: Add metadata checksumming

On Fri, Mar 09, 2012 at 05:37:28PM -0500, Ted Ts'o wrote:
> I've imported this patch set into a guilt patch series, which makes it
> easier for me to work on the patch series and make minor tweaks so
> that I can get interim e2fsprogs support up and going (and at least
> building and passing the regression test suite) so I can test and play
> with the kernel side patches.
> 
> People who want to follow along can look here:
> 
> 	https://github.com/tytso/e2fsprogs-cksum-patch-queue
> 
> ... or at the read-only git tree which you can find here:
> 
> 	git://github.com/tytso/e2fsprogs-cksum-patch-queue.git
> 
> With these large patch series it's easier for me to make blanket
> changes to fix minor annoyances (such as commit descriptions which are
> too wide and make "git log" displays hard to follow) or to merge
> patches that are too fine grained[1] together.
> 
> Open source project management theory says that it's better to ask the
> submitter to do all of this work, but given certain special
> circumstances in this particular case, I decided to make the cleanup
> work that I do publicly visible, as a compromise.  I'll also make some
> comments about some of the issues I find (and fix) by replying to the
> emails on this mail thread.
> 
> This patch series will be maintained so that it can be applied to the
> top-most "maint" branch of e2fsprogs.
> 
> Darrick, if you have time and would like to make further changes, ping
> me off-line and I would be happy to give you write access to the
> github tree.

Here's a copy of my testing script....

--D

#!/bin/bash -e

# ext4 metadata checksum test script
# licensed under gplv2
# copyright (c) 2011 ibm corporation.  all rights reserved.

function print_help {
	echo "Usage: $0 [-d device] [-m mountpoint] [-v verbs] [-o mkfs_opts] [-e mkfs_features] [-l] [-n] [-p e2fsprogs_path] [-z mount_opts] [-q]"
	echo "-l	Use valgrind"
	echo "-n	No checksumming"
	echo "-q	Enable MMP"
	echo "verbs is any combination of:"
	echo "${VERBS}"
	exit 1
}

type attr || (echo "Must install attr program."; exit 5)
type /usr/bin/time || (echo "Must install time program."; exit 5)

DEV=/dev/vda
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?"
VERBS="$(grep ^function $0 | grep '_test ' | awk '{print $2}')"
E2FSPROGS=/djwong/e2fsprogs-csum

while getopts "p:d:m:v:z:o:e:l" OPTION; do
	case "$OPTION" in
	"z")
		MOUNT_OPTS="${OPTARG}"
		;;
	"d")
		DEV="${OPTARG}"
		;;
	"m")
		MNT="${OPTARG}"
		;;
	"v")
		VERBS="${OPTARG}"
		;;
	"o")
		MKFS_OPTS="${OPTARG}"
		;;
	"q")
		MKFS_OPTS="${MKFS_OPTS},mmp"
		;;
	"e")
		MKFS_FEATURES="${OPTARG}"
		;;
	"l")
		VALGRIND=valgrind
		;;
	"n")
		NO_CSUM=1
		;;
	"p")
		E2FSPROGS="${OPTARG}"
		;;
	*)
		print_help
		exit 1
		;;
	esac
done
if [ ! -z "${MKFS_OPTS}" ]; then
	MKFS_OPTS="-O ${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

function msg {
	if [ -x /usr/bin/figlet ]; then
		figlet -f mono9 -w 132 $*
		echo $* > /dev/ttyprintk
	else
		echo $* | tee /dev/ttyprintk
	fi
}

if [ ! -b "${DEV}" ]; then
	echo "${DEV} is not a block device?"
	exit 0
fi

umount $MNT || true
rmmod ext4 || true
rmmod jbd2 || true
rmmod crc32c || true
rmmod crc32c-intel || true

dmesg -c > /dev/null
trap 'echo "test ended" | tee /dev/ttyprintk; dmesg'  EXIT
msg "$0: Begin test @ $(date)"
set -x

#####################################
function simple_test {
msg "Create fs with files, no checksums"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 $MKFS_OPTS $MKFS_FEATURES

mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRd /etc/ $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
for i in `seq -w 1 100`; 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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# Walk fs looking for errors
mount ${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 ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/moo
cp -pRd /etc/ $MNT/moo/
umount $MNT

# Create htree dir
mount ${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

########################################
msg "Mess with extent tree"
mount ${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

# Keep rewriting the extent tree just to drive it crazy
mount ${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

# Truncate the file
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
truncate -s -64k $MNT/fragged/fragfile
umount $MNT

# Keep rewriting the extent tree just to drive it crazy
mount ${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

# Re-walk fs looking for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT/

# Check fs again
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

##################################################
msg "Disable checksums"
${E2FSPROGS}/misc/dumpe2fs $DEV > /root/before
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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
${E2FSPROGS}/misc/dumpe2fs $DEV > /root/after

# Walk fs looking for errors
mount ${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 ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/oom
cp -pRd /etc/ $MNT/oom/
umount $MNT

# Re-walk fs looking for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT/

# Check fs again
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

# Walk fs looking for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -o -type d -print0 | xargs -0 touch
umount $MNT

# Remove file
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
dd if=/dev/zero of=$MNT/bigfile bs=1024k count=16
umount $MNT
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
rm -rf $MNT/bigfile
umount $MNT

#############################
# create xattrs
msg "mess with xattrs"
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo attrs > $MNT/attrfile
set +x
echo + set_xattrs
for i in `seq -w 1 100`; do
	attr -s $i -V $i $MNT/attrfile
done
set -x
attr -l $MNT/attrfile
umount $MNT

# Check fs one last time
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#################################
function corrupt_inode_csum_test {
msg "Deliberately corrupt inode checksum"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 $MKFS_OPTS $MKFS_FEATURES -b 4096 -I 4096 -E lazy_itable_init=1
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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

mount ${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 -pRd /etc/ $MNT/
cp -pRd /etc/ $MNT/moo
umount $MNT

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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
		continue
	fi
	echo -en " $start"
	if [ $((end - start)) -gt 4 ]; then
		end=$((start + 4))
	fi
	seq $start $end | while read block; do
		offset=$(( (start * (4096 / 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 ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true

# Walk fs looking for errors
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#################################
function corrupt_inode_test {
msg "Deliberately corrupt inode table"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 $MKFS_OPTS $MKFS_FEATURES
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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

mount ${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 -pRd /etc/ $MNT/
cp -pRd /etc/ $MNT/moo
umount $MNT

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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
		continue
	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 ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true

# Walk fs looking for errors
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#################################
function corrupt_ibitmap_test {
msg "Deliberately corrupt inode bitmap"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 $MKFS_OPTS $MKFS_FEATURES
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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRd /etc/ $MNT/
cp -pRd /etc/ $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 ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
(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

# Repair fs
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true

# Walk fs looking for errors
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#################################
function corrupt_bbitmap_test {
msg "Deliberately corrupt block bitmap"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 $MKFS_OPTS $MKFS_FEATURES
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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRd /etc/ $MNT/
cp -pRd /etc/ $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
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
(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

# Repair fs
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true

# Walk fs looking for errors
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#######################
function corrupt_extent_head_test {
msg "Corrupt an extent header"
BLK_SZ=2048
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum -b $BLK_SZ
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
SZ=$(df -k $MNT | awk '{print $4}' | tail -1)
fallocate -l $((SZ * 9 / 10))k $MNT/ouch
umount $MNT

set +x
echo + corrupt_extent_tree
echo 'ex /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV | grep -v -- '-.*-' | grep "^[ 0-9]" | awk '{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 ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo >> $MNT/ouch || true
umount $MNT

# Repair
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true

# Look for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo oom >> $MNT/ouch
umount $MNT

# Check fs one last time
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#######################
function corrupt_extent_test {
msg "Destroy an extent entry"
BLK_SZ=2048
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum -b $BLK_SZ
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
SZ=$(df -k $MNT | awk '{print $4}' | tail -1)
fallocate -l $((SZ * 9 / 10))k $MNT/ouch
umount $MNT

echo 'stat /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV -n | cat -
set +x
echo + corrupt_extent_tree
echo 'ex /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV | grep -v -- '-.*-' | grep "^[ 0-9]" | awk '{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
echo 'stat /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV -n | cat -

# Look for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo >> $MNT/ouch || true
umount $MNT

# Repair
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true

echo 'stat /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV -n | cat -

# Look for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo oom >> $MNT/ouch
umount $MNT

# Check fs one last time
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#######################
function corrupt_extent_csum_test {
msg "Destroy an extent block csum"
BLK_SZ=2048
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum -b $BLK_SZ
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
SZ=$(df -k $MNT | awk '{print $4}' | tail -1)
fallocate -l $((SZ * 9 / 10))k $MNT/ouch
umount $MNT

echo 'ex /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV -n | cat -
set +x
echo + corrupt_extent_block_csum
echo 'ex /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV | grep -v -- '-.*-' | grep "^[ 0-9]" | awk '{print $8}' | while read block; 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
echo 'ex /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV -n | cat -

# Look for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo >> $MNT/ouch || true
umount $MNT

# Repair
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true

echo 'stat /ouch' | ${E2FSPROGS}/debugfs/debugfs $DEV -n | cat -

# Look for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo oom >> $MNT/ouch
umount $MNT

# Check fs one last time
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#######################
function htree_test {
msg "Simple htree test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum
msg "htree1"
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "htree2"
mount ${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

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "htree_del"
mount ${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 -F $DEV -T ext4 -O 64bit,mmp,metadata_csum -b 2048
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/3
echo moo > $MNT/3/base.txt
set +x
echo + mltree
seq 1 5000 | 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

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "mlhtree delete"
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
rm -rf $MNT/3
umount $MNT

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV
}

#########################
function corrupt_htree_test {
msg "corrupt htree"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum -b 2048
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/3
echo moo > $MNT/3/base.txt
set +x
echo + htree
seq 1 10 | 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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV || true

# now blast the root block
ROOT_BLK=$(echo 'stat /3' | ${E2FSPROGS}/debugfs/debugfs $DEV | grep EXTENTS -A1 | tail -1 | sed -e 's/^.*://g' -e 's/-.*$//g')
yes "${FUZZ}" | dd of=$DEV bs=8 seek=$(( ( (ROOT_BLK + 1) * 256) - 1 )) count=1 > /dev/null 2> /dev/null
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV || true

# walk looking for errors
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

# rescan
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/3 > /dev/null || true
umount $MNT

# check once more
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

# inflate directory some more
mount ${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 11 2000 | 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
echo 'htree /3' | ${E2FSPROGS}/debugfs/debugfs $DEV | grep 'Number of entries' -B1 | grep block | sed -e 's/^.*block //g' | while read blocknr; do
	PBLK=$(echo "bmap /3 ${blocknr}" | ${E2FSPROGS}/debugfs/debugfs $DEV -f - | grep '^[0-9]')
	PBLK=$(( ($PBLK * 256) + 2))
	yes "${FUZZ}" | dd of=$DEV bs=8 seek=${PBLK} count=1  > /dev/null 2> /dev/null
done
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV || true

# walk looking for errors
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/3 > /dev/null || true
umount $MNT

# fix
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

# rescan
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/3 > /dev/null || true
umount $MNT

# check once more
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV
}

#########################
function flat_dir_test {
msg "flat dir test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum,^dir_index -b 2048
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $MNT/a
cp -pRl $MNT/a $MNT/b
cp -pRl $MNT/a $MNT/c
cp -pRl $MNT/a $MNT/d
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "cat files"
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/b -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "enlarge direntry"
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "rm file"
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT/b -type f -print0 | xargs -0 rm -rf
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "rm dir"
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
rm -rf $MNT/b
umount $MNT

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV
}

#########################
function corrupt_flat_dir_test {
msg "corrupt flat dir test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum,^dir_index -b 2048
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
mkdir $MNT/a/
cp -pRdu /etc/init* $MNT/a/
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

echo 'ex /a' | ${E2FSPROGS}/debugfs/debugfs $DEV | awk '{if (($8 * 1) == $8) {print $8}}' | while read blk; do
	yes "${FUZZ}" | dd of=$DEV bs=4 count=1 seek=$(( (blk * 512) + 511 ))
done
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV || true

msg "cat files (brokeN)"
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true

msg "cat files again"
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "blast flat dir test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum,^dir_index -b 2048
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $MNT/a
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

echo 'ex /a' | ${E2FSPROGS}/debugfs/debugfs $DEV | awk '{if (($8 * 1) == $8) {print $8}}' | while read blk; do
	yes "${FUZZ}" | dd of=$DEV bs=2048 count=1 seek=$blk
done
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV || true

msg "cat files (brokeN)"
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

msg "cat files again"
mount ${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/test1
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV
}

####################
function ignore_fsck_d_test {
msg "ignore_fsck_d_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $MNT/
umount $MNT

$VALGRIND ${E2FSPROGS}/misc/tune2fs $DEV -O metadata_csum
echo "Find all possible damage."
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

echo "Actually repair damage. 0"
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true
echo "Test run 0."
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

# do it again, but wiht -D
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $MNT/
umount $MNT

$VALGRIND ${E2FSPROGS}/misc/tune2fs $DEV -O metadata_csum
echo "Actually repair damage. 1"
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

echo "Test run. 1"
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV

mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fn $DEV
}

############################
function xattr_test {
#############################
# create xattrs
msg "xattr_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 $MKFS_OPTS $MKFS_FEATURES
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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

# create a bunch of xattrs
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo attrs | tee $MNT/attr1 $MNT/attr2 $MNT/noattr
set +x
echo + set_xattrs
for i in `seq -w 1 100`; do
	attr -s $i -V $i $MNT/attr1 > /dev/null
done
attr -s XXX -V XXX $MNT/attr2 > /dev/null
set -x
umount $MNT

# reload and reread
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
attr -l $MNT/attr1
attr -l $MNT/attr2
attr -l $MNT/noattr
umount $MNT

# Check fs one last time
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#############################
function corrupt_xattr_test {
msg "corrupt_xattr_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum -b 4096

mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo attrs | tee $MNT/attr1 $MNT/attr2 $MNT/noattr
set +x
echo + set_xattrs
for i in `seq -w 1 100`; 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=$(echo 'stat /attr1' | ${E2FSPROGS}/debugfs/debugfs $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=4096 seek=$XATTR_BLOCK count=1 > /dev/null 2> /dev/null

# reload and reread
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV || true
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true

# reread, but this time fixed
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
mount ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

####################################
function simple_sb_test {
msg "simple_sb_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 $MKFS_OPTS $MKFS_FEATURES
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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep Checksum
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# write stuff
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/moo
umount $MNT
${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep Checksum
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# change label
$VALGRIND ${E2FSPROGS}/misc/tune2fs -L moocow $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep Checksum
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# quick check kernel
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/cow
umount $MNT
${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep Checksum
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# change label again
$VALGRIND ${E2FSPROGS}/misc/tune2fs -L cowmoo $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep Checksum
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# quick check kernel
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/cow
umount $MNT
${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep Checksum
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/post-uuid
umount $MNT

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

##########################
function prep_speed_test {
VER=3.2.8
if [ ! -r /tmp/linux-${VER}.tar.bz2 ]; then
	cp /home/djwong/linux-${VER}.tar.bz2 /tmp/
	#scp elm3c44:/home/djwong/kern*/linux-${VER}.tar.bz2 /tmp/
fi
if [ ! -r /tmp/tarfiles ]; then
	tar tvf /tmp/linux-${VER}.tar.bz2 > /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>

int main(int argc, char *argv[])
{
	FILE *fp;
	int fd;
	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);
		posix_fallocate(fd, 0, size);
		close(fd);
	}

	fclose(fp);
	return 0;
}
ENDL
	gcc -o /tmp/fab /tmp/fab.c
fi
}

function tune2fs_speed_test {
msg "tune2fs_speed_test"
prep_speed_test
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit
mount ${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 $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y -D $DEV || true
}

function all_speed_test {
msg "all_speed_test"
prep_speed_test

msg "All checksums including journal and data=journal"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,metadata_csum,mmp
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum,data=journal,nodelalloc
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 {
msg "most_speed_test"
prep_speed_test

msg "All checksums including journal and data=ordered"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,metadata_csum,mmp
mount ${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 {
msg "none_speed_test"
prep_speed_test

msg "No checksums at all"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit
mount ${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 {
msg "ext_speed_test"
prep_speed_test
msg "All ext4 checksums, no journal checksum"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum
mount ${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 -F $DEV -T ext4 -O 64bit,metadata_csum
mount ${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 dir_rewrite_test {
msg "dir_rewrite_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# run it by the kernel
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
find $MNT -type f -print0 | xargs -0 cat > /dev/null
umount $MNT

# one last check
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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 -F $DEV -T ext4 -U $UUID1
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
mount ${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 ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# Try to change UUID with chekcsums
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O mmp,metadata_csum -U $UUID1
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
mount ${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 ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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 -F $DEV -T ext4 -O 64bit,mmp,^uninit_bg,^metadata_csum -b 4096
mount $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $MNT/etc
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
		$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'Filesystem features:'
		mount $DEV $MNT -t ext4
		find $MNT -type f -print0 | xargs -0 cat > /dev/null
		date > "${MNT}/${bg_checksum}_${metadata_csum}"
		umount $MNT
		$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
	done
done
}

############################
function mmp_test {
msg "mmp_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,metadata_csum,mmp -E mmp_update_interval=5
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
mount $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $MNT/a
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# Can't fsck while mounted
mount $DEV $MNT -t ext4 -o journal_checksum
yes | script -f /tmp/mmp.$$ -c "$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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 -F $DEV -T ext4 -O 64bit,metadata_csum,mmp -E mmp_update_interval=5 -b 4096
mount $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/moofile
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

MMP_BLOCK=$(${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep 'MMP block number:' | awk '{print $4}')
MMP_SECTOR=$(((MMP_BLOCK * 8) + 1))
yes "${FUZZ}" | dd of=$DEV bs=512 seek=${MMP_SECTOR} count=1 > /dev/null 2> /dev/null
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV || true
set +e
mount $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

$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true
mount $DEV $MNT -t ext4 -o journal_checksum
echo $MNT/moofile > /dev/null
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

##############################
function journal_sb_test {
msg "journal_sb_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,metadata_csum
mount $DEV $MNT -t ext4 -o journal_checksum,data=journal,nodelalloc
cp -pRdu /etc $MNT/etc
sync
rm -rf $MNT/etc/init*
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal

# Make the kernel run through again
mount $DEV $MNT -t ext4 -o journal_checksum,data=journal,nodelalloc
cp -pRdu /etc $MNT/blob
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal

# What happens if we don't specify any options?
mount $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=4k count=1 >> $MNT/fragged/fragfile 2> /dev/null > /dev/null
#	sync
#done
#set -x
#truncate -s -2000k $MNT/fragged/fragfile
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
}

##############################
function corrupt_journal_sb_test {
msg "corrupt_journal_sb_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,metadata_csum -b 4096
mount $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $MNT/etc
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal

# Fuzz part of the superblock
JSB_BLOCK=$(echo 'ex <8>' | ${E2FSPROGS}/debugfs/debugfs -n $DEV | grep '0 - 3276' | awk '{print $8}')
JSB_SECTOR=$(((JSB_BLOCK * 8) + 1))
yes "${FUZZ}" | dd of=$DEV bs=512 seek=${JSB_SECTOR} count=1 > /dev/null 2> /dev/null
dd if=$DEV bs=4096 skip=${JSB_BLOCK} count=1 | od -tx1 -Ad -c
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal

# Make the kernel run through again
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV || true
set +e
mount $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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y $DEV || true
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal

# Mount, copy more files
mount $DEV $MNT -t ext4 -o journal_checksum
cp -pRdu /etc $MNT/next
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
$VALGRIND ${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep ^Journal
}

# Leave this at the end
################################
function corrupt_sb_test {
msg "corrupt_sb_test"
# write junk into last error field
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum -b 4096 -i 524288
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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: $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum && echo should not get here && exit 50
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y -D $DEV || true
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/file
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

# totally destroy sb
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O 64bit,mmp,metadata_csum -b 4096 -i 524288
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
${E2FSPROGS}/misc/dumpe2fs -h $DEV | grep UUID
yes "${FUZZ}" | dd of=$DEV bs=4096 seek=0 count=1 > /dev/null 2> /dev/null
# fsck -n will modify the fs due to backup sb being used !  DO NOT RUN THIS: $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum && echo should not get here && exit 50
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y -D $DEV || true
echo "beat on it a second time"
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -y -D $DEV || true
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
echo moo > $MNT/file
umount $MNT
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
}

#####################################
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 -F $DEV -T ext4 $FEATURES
	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
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
	if [ "${MCSUM},${GCSUM}" != "${FEATURE_STRING}" ]; then
		msg "FAIL ${ERROR_MSG}"
		return 1
	fi
	msg "PASS ${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"

	$VALGRIND ${E2FSPROGS}/misc/tune2fs $DEV $FEATURES
	${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
	if [ "${MCSUM},${GCSUM}" != "${FEATURE_STRING}" ]; then
		msg "FAIL ${ERROR_MSG}"
		return 1
	fi
	msg "PASS ${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 ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
		cp -pRd /etc/ $MNT/etc_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 -F $DEV -T ext4 -O ^has_journal,metadata_csum

# Dump in some files
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRd /etc/ $MNT/etc_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 -F $DEV -T ext4 -O ^has_journal,metadata_csum

# Dump in some files
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRd /etc/ $MNT/etc_a
umount $MNT

tune2fs_flag_collision_test_helper "^metadata_csum,^uninit_bg" "0,0" "remove metadata_csum and uninit_bg"
}

#####################################
function shrink_uninit_test {
msg "shrink_uninit_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O ^has_journal,metadata_csum,64bit -b 4096 -N 192 393216
mount ${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
dd if=/dev/zero of=$MNT/bigfile conv=notrunc oflag=append || true
umount $MNT
mount ${MOUNT_OPTS} $DEV $MNT -t ext4
rm -rf $MNT/dirX $MNT/bigfile
umount $MNT

for i in `seq 1 16`; do
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true
	$VALGRIND ${E2FSPROGS}/resize/resize2fs $DEV $((393216 - ($i * 16384)))
	$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
	mount ${MOUNT_OPTS} $DEV $MNT -t ext4
	dd if=/dev/zero of=$MNT/bigfile conv=notrunc oflag=append || true
	sync
	rm -rf $MNT/bigfile
	umount $MNT
done
}

#####################################
function resize_uninit_test {
msg "resize_test: uninit_bg"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O ^has_journal,metadata_csum,64bit -b 4096 -N 64 131072

for i in `seq 1 16`; do
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true
	$VALGRIND ${E2FSPROGS}/resize/resize2fs $DEV $((131072 + ($i * 16384)))
	$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
	mount ${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
	dd if=/dev/zero of=$MNT/bigfile conv=notrunc oflag=append || true
	umount $MNT
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
done
}

######################################
function resize_init_test {
msg "resize_init_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O ^has_journal,^uninit_bg,64bit -b 4096 -N 64 131072
$VALGRIND ${E2FSPROGS}/misc/tune2fs $DEV -O metadata_csum
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

for i in `seq 1 16`; do
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true
	$VALGRIND ${E2FSPROGS}/resize/resize2fs $DEV $((131072 + ($i * 16384)))
	$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
	mount ${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
	dd if=/dev/zero of=$MNT/bigfile conv=notrunc oflag=append || true
	umount $MNT
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
done
}

#####################################
function online_resize_uninit_test {
msg "online_resize_test: uninit_bg"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O ^has_journal,metadata_csum,64bit -b 4096 -N 64 131072

for i in `seq 1 16`; do
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true
	mount ${MOUNT_OPTS} $DEV $MNT -t ext4
	$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV
	$VALGRIND ${E2FSPROGS}/resize/resize2fs $DEV $((131072 + ($i * 16384)))
	$VALGRIND ${E2FSPROGS}/misc/dumpe2fs $DEV
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -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
	dd if=/dev/zero of=$MNT/bigfile conv=notrunc oflag=append || true
	umount $MNT
	# XXX: this is broken, even before metadata_csum came about
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
done
}

######################################
function online_resize_init_test {
msg "online_resize_init_test"
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 -O ^has_journal,^uninit_bg,64bit -b 4096 -N 64 131072
$VALGRIND ${E2FSPROGS}/misc/tune2fs $DEV -O metadata_csum
${E2FSPROGS}/misc/dumpe2fs -h $DEV 2> /dev/null | egrep -q "^Filesystem state:[ ]*clean$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

for i in `seq 1 16`; do
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fy $DEV || true
	mount ${MOUNT_OPTS} $DEV $MNT -t ext4
	$VALGRIND ${E2FSPROGS}/resize/resize2fs $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
	dd if=/dev/zero of=$MNT/bigfile conv=notrunc oflag=append || true
	umount $MNT
	$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV
done
}

#####################################
function simple_prep_fs {
msg "Create fs with files, dirs, EAs, htree dirs, etc."
$VALGRIND ${E2FSPROGS}/misc/mke2fs -F $DEV -T ext4 $MKFS_OPTS $MKFS_FEATURES
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$" || $VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -fDy $DEV || true

# Dump in some files
mount ${MOUNT_OPTS} $DEV $MNT -t ext4 -o journal_checksum
cp -pRd /etc/ $MNT/etc_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
for i in `seq -w 1 100`; do
	attr -s $i -V $i $MNT/ea_file
done

# add some random files
cp -pRd /etc/ $MNT/etc_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
seq 1 5000 | 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 ${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
$VALGRIND ${E2FSPROGS}/e2fsck/e2fsck -f -n $DEV

echo 'Filesystem created; please mount with -o journal_checksum'
}

#####################
for verb in $(echo "${VERBS}" | tr ':,' '  '); do
	$verb
done

####################################
msg "Finished successfully, ENJOY."

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ