* [PATCH] xfsqa: new fsr defragmentation test
@ 2010-04-06 8:52 Dave Chinner
2010-04-06 15:29 ` Eric Sandeen
0 siblings, 1 reply; 3+ messages in thread
From: Dave Chinner @ 2010-04-06 8:52 UTC (permalink / raw)
To: xfs
From: Dave Chinner <dchinner@redhat.com>
This test aims to recreate the conditions that caused xfs_fsr to
corrupt inode forks. The problem was that the data forks between the
two inodes were in different formats due to different inode fork
offsets, so when they swapped the data forks the formats were
invalid.
This test generates a filesystem with a known fragmented freespace pattern and
then abuses known "behaviours" of the allocator to generate files
with a known number of extents. It creates attributes to generate a
known inode fork offset, then uses a debug feature of xfs_fsr to
attempt to defrag the inode to a known number of extents.
By using these features, we can pretty much cover the entire matrix of inode
fork configurations, hence reproducing the conditions that lead to corruptions.
This test has already uncovered one bug in the current kernel code, and the
current fsr (with it's naive attribute fork handling) is aborted on a couple of
hundred of the files created by this test.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
226 | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
226.out | 2 +
group | 3 +-
3 files changed, 196 insertions(+), 1 deletions(-)
create mode 100644 226
create mode 100644 226.out
diff --git a/226 b/226
new file mode 100644
index 0000000..b92292a
--- /dev/null
+++ b/226
@@ -0,0 +1,192 @@
+#! /bin/bash
+# FS QA Test No. 222
+#
+# xfs_fsr QA tests
+# run xfs_fsr over the test filesystem to give it a wide and varied set of
+# inodes to try to defragment. This is effectively a crash/assert failure
+# test looking for corruption induced by the kernel inadequately checking
+# the indoes to be swapped. It also is good for validating fsr's attribute fork
+# generation code.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2010 Dave Chinner. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+#-----------------------------------------------------------------------
+#
+# creator
+owner=david@fromorbit.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ rm -f $tmp.*
+}
+
+trap "_cleanup ; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+# real QA test starts here
+_supported_fs xfs
+_supported_os Linux
+
+[ "$XFS_FSR_PROG" = "" ] && _notrun "xfs_fsr not found"
+
+# create freespace holes of 1-3 blocks in length
+#
+# This is done to ensure that defragmented files have roughly 1/3 the
+# number of extents they started with. This will ensure we get
+# transistions from btree format (say 15 extents) to extent format
+# (say 5 extents) and lots of variations around that dependent on the
+# number of attributes in the files being defragmented.
+#
+fragment_freespace()
+{
+ _file="$SCRATCH_MNT/not_free"
+
+ for i in `seq 0 1 10000`; do
+ echo foo > $_file.$i
+ done
+ sync
+
+ for i in `seq 0 2 10000`; do
+ rm -f $_file.$i
+ done
+ for i in `seq 0 7 10000`; do
+ rm -f $_file.$i
+ done
+ sync
+
+ # and now use up all the remaining extents larger than 3 blocks
+ dd if=/dev/zero of=$_file.large bs=4k count=1024 > /dev/null 2>&1
+ sync
+}
+
+create_attrs()
+{
+ for foo in `seq 0 1 $1`; do
+ setfattr -n user.$foo -v 0xbabe $2
+ done
+}
+
+create_data()
+{
+ for foo in `seq $1 -1 0`; do
+ let offset=$foo*4096
+ $XFS_IO_PROG -f -c "pwrite $offset 4096" -c "fsync" $2 > /dev/null 2>&1
+ done
+ xfs_bmap -vp $2
+}
+
+# create the designated file with a certain number of attributes and a certain
+# number of data extents. Reverse order synchronous data writes are used to
+# create fragmented files, though with the way the filesystem freespace is
+# fragmented, this is probably not necessary. Create the attributes first so
+# that they cause the initial fork offset pressure to move it about.
+#
+create_target_attr_first()
+{
+ nattrs=$1
+ file_blocks=$2
+ target=$3
+
+ rm -f $target
+ echo > $target
+ create_attrs $nattrs $target
+ create_data $file_blocks $target
+}
+
+# Same as create_target_attr_first, but this time put the attributes on after
+# the data extents have been created. This puts different pressure on the
+# inode fork offset, so should exercise the kernel code differently and give us
+# a different pattern of fork offsets to work with compared to creating the
+# attrs first.
+#
+create_target_attr_last()
+{
+ nattrs=$1
+ file_blocks=$2
+ target=$3
+
+ rm -f $target
+ echo > $target
+ create_data $file_blocks $target
+ create_attrs $nattrs $target
+}
+
+rm -f $seq.full
+umount $SCRATCH_MNT
+
+# use a small filesystem so we can control freespace easily
+_scratch_mkfs_sized $((50 * 1024 * 1024)) >> $seq.full 2>&1
+_scratch_mount
+fragment_freespace
+
+# unmount and remount to reset all allocator indexes
+umount $SCRATCH_MNT
+_scratch_mount
+
+# create a range of source files, then fsr them to a known size
+#
+# This assumes 256 byte inodes.
+#
+# n = number of target fragments for xfs_fsr
+# - only a guideline, but forces multiple fragments via sync writes
+# - start at 4 as that typically covers all extent format situations
+# - end at 12 as that is beyond the maximum that canbe fit in extent
+# format
+# i = number of 2 byte attributes on the file
+# - it takes 6 attributes to change the fork offset from the start value
+# of 120 bytes to 112 bytes, so we start at 5.
+# - 15 is enough to push to btree format, so we stop there.
+# j = number of data extents on the file
+# - start in extent format, but we also want btree format as well, so
+# start at 5 so that the number of attributes determines the starting
+# format.
+# - need enough extents that if they are all 3 blocks in length the final
+# format will be dependent on the number of attributes on the inode. 20
+# initial single block extents gives us 6-8 extents after defrag which
+# puts us right on the threshold of what the extent format can hold.
+
+targ=$SCRATCH_MNT/fsr_test_file.$$
+for n in `seq 4 1 12`; do
+ echo "*** n == $n ***" >> $seq.full
+ for i in `seq 5 1 15`; do
+ for j in `seq 5 1 20`; do
+ create_target_attr_first $i $j $targ.$i.$j >> $seq.full 2>&1
+ done
+ FSRXFSTEST=true xfs_fsr -d -v -C $n $targ.$i.* >> $seq.full 2>&1
+ xfs_bmap -vp $targ.$i.* >> $seq.full 2>&1
+ for j in `seq 5 1 20`; do
+ create_target_attr_last $i $j $targ.$i.$j >> $seq.full 2>&1
+ done
+ FSRXFSTEST=true xfs_fsr -d -v -C $n $targ.$i.* >> $seq.full 2>&1
+ xfs_bmap -vp $targ.$i.* >> $seq.full 2>&1
+ done
+done
+
+umount $SCRATCH_MNT
+_check_scratch_fs
+echo "--- silence is golden ---"
+status=0 ; exit
diff --git a/226.out b/226.out
new file mode 100644
index 0000000..52c0c1f
--- /dev/null
+++ b/226.out
@@ -0,0 +1,2 @@
+QA output created by 226
+--- silence is golden ---
diff --git a/group b/group
index 3164c37..2386c41 100644
--- a/group
+++ b/group
@@ -339,4 +339,5 @@ deprecated
223 auto quick
224 auto
225 auto quick
-500 auto quota
\ No newline at end of file
+226 auto fsr
+500 auto quota
--
1.6.5
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] xfsqa: new fsr defragmentation test
2010-04-06 8:52 [PATCH] xfsqa: new fsr defragmentation test Dave Chinner
@ 2010-04-06 15:29 ` Eric Sandeen
2010-04-06 23:19 ` Dave Chinner
0 siblings, 1 reply; 3+ messages in thread
From: Eric Sandeen @ 2010-04-06 15:29 UTC (permalink / raw)
To: Dave Chinner; +Cc: xfs
On 04/06/2010 03:52 AM, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
>
> This test aims to recreate the conditions that caused xfs_fsr to
> corrupt inode forks. The problem was that the data forks between the
> two inodes were in different formats due to different inode fork
> offsets, so when they swapped the data forks the formats were
> invalid.
>
> This test generates a filesystem with a known fragmented freespace pattern and
> then abuses known "behaviours" of the allocator to generate files
> with a known number of extents. It creates attributes to generate a
> known inode fork offset, then uses a debug feature of xfs_fsr to
> attempt to defrag the inode to a known number of extents.
>
> By using these features, we can pretty much cover the entire matrix of inode
> fork configurations, hence reproducing the conditions that lead to corruptions.
> This test has already uncovered one bug in the current kernel code, and the
> current fsr (with it's naive attribute fork handling) is aborted on a couple of
> hundred of the files created by this test.
>
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
> 226 | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 226.out | 2 +
> group | 3 +-
> 3 files changed, 196 insertions(+), 1 deletions(-)
> create mode 100644 226
> create mode 100644 226.out
>
> diff --git a/226 b/226
> new file mode 100644
> index 0000000..b92292a
> --- /dev/null
> +++ b/226
> @@ -0,0 +1,192 @@
> +#! /bin/bash
> +# FS QA Test No. 222
s/b 226
Looks like a good test but how fragile will it be in the face of changes
to the known allocator behaviors? :)
-Eric
> +# xfs_fsr QA tests
> +# run xfs_fsr over the test filesystem to give it a wide and varied set of
> +# inodes to try to defragment. This is effectively a crash/assert failure
> +# test looking for corruption induced by the kernel inadequately checking
> +# the indoes to be swapped. It also is good for validating fsr's attribute fork
> +# generation code.
> +#
> +#-----------------------------------------------------------------------
> +# Copyright (c) 2010 Dave Chinner. All Rights Reserved.
> +#
> +# This program is free software; you can redistribute it and/or
> +# modify it under the terms of the GNU General Public License as
> +# published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it would be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write the Free Software Foundation,
> +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> +#
> +#-----------------------------------------------------------------------
> +#
> +# creator
> +owner=david@fromorbit.com
> +
> +seq=`basename $0`
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1 # failure is the default!
> +
> +_cleanup()
> +{
> + rm -f $tmp.*
> +}
> +
> +trap "_cleanup ; exit \$status" 0 1 2 3 15
> +
> +# get standard environment, filters and checks
> +. ./common.rc
> +. ./common.filter
> +
> +# real QA test starts here
> +_supported_fs xfs
> +_supported_os Linux
> +
> +[ "$XFS_FSR_PROG" = "" ] && _notrun "xfs_fsr not found"
> +
> +# create freespace holes of 1-3 blocks in length
> +#
> +# This is done to ensure that defragmented files have roughly 1/3 the
> +# number of extents they started with. This will ensure we get
> +# transistions from btree format (say 15 extents) to extent format
> +# (say 5 extents) and lots of variations around that dependent on the
> +# number of attributes in the files being defragmented.
> +#
> +fragment_freespace()
> +{
> + _file="$SCRATCH_MNT/not_free"
> +
> + for i in `seq 0 1 10000`; do
> + echo foo > $_file.$i
> + done
> + sync
> +
> + for i in `seq 0 2 10000`; do
> + rm -f $_file.$i
> + done
> + for i in `seq 0 7 10000`; do
> + rm -f $_file.$i
> + done
> + sync
> +
> + # and now use up all the remaining extents larger than 3 blocks
> + dd if=/dev/zero of=$_file.large bs=4k count=1024 > /dev/null 2>&1
> + sync
> +}
> +
> +create_attrs()
> +{
> + for foo in `seq 0 1 $1`; do
> + setfattr -n user.$foo -v 0xbabe $2
> + done
> +}
> +
> +create_data()
> +{
> + for foo in `seq $1 -1 0`; do
> + let offset=$foo*4096
> + $XFS_IO_PROG -f -c "pwrite $offset 4096" -c "fsync" $2 > /dev/null 2>&1
> + done
> + xfs_bmap -vp $2
> +}
> +
> +# create the designated file with a certain number of attributes and a certain
> +# number of data extents. Reverse order synchronous data writes are used to
> +# create fragmented files, though with the way the filesystem freespace is
> +# fragmented, this is probably not necessary. Create the attributes first so
> +# that they cause the initial fork offset pressure to move it about.
> +#
> +create_target_attr_first()
> +{
> + nattrs=$1
> + file_blocks=$2
> + target=$3
> +
> + rm -f $target
> + echo > $target
> + create_attrs $nattrs $target
> + create_data $file_blocks $target
> +}
> +
> +# Same as create_target_attr_first, but this time put the attributes on after
> +# the data extents have been created. This puts different pressure on the
> +# inode fork offset, so should exercise the kernel code differently and give us
> +# a different pattern of fork offsets to work with compared to creating the
> +# attrs first.
> +#
> +create_target_attr_last()
> +{
> + nattrs=$1
> + file_blocks=$2
> + target=$3
> +
> + rm -f $target
> + echo > $target
> + create_data $file_blocks $target
> + create_attrs $nattrs $target
> +}
> +
> +rm -f $seq.full
> +umount $SCRATCH_MNT
> +
> +# use a small filesystem so we can control freespace easily
> +_scratch_mkfs_sized $((50 * 1024 * 1024)) >> $seq.full 2>&1
> +_scratch_mount
> +fragment_freespace
> +
> +# unmount and remount to reset all allocator indexes
> +umount $SCRATCH_MNT
> +_scratch_mount
> +
> +# create a range of source files, then fsr them to a known size
> +#
> +# This assumes 256 byte inodes.
> +#
> +# n = number of target fragments for xfs_fsr
> +# - only a guideline, but forces multiple fragments via sync writes
> +# - start at 4 as that typically covers all extent format situations
> +# - end at 12 as that is beyond the maximum that canbe fit in extent
> +# format
> +# i = number of 2 byte attributes on the file
> +# - it takes 6 attributes to change the fork offset from the start value
> +# of 120 bytes to 112 bytes, so we start at 5.
> +# - 15 is enough to push to btree format, so we stop there.
> +# j = number of data extents on the file
> +# - start in extent format, but we also want btree format as well, so
> +# start at 5 so that the number of attributes determines the starting
> +# format.
> +# - need enough extents that if they are all 3 blocks in length the final
> +# format will be dependent on the number of attributes on the inode. 20
> +# initial single block extents gives us 6-8 extents after defrag which
> +# puts us right on the threshold of what the extent format can hold.
> +
> +targ=$SCRATCH_MNT/fsr_test_file.$$
> +for n in `seq 4 1 12`; do
> + echo "*** n == $n ***" >> $seq.full
> + for i in `seq 5 1 15`; do
> + for j in `seq 5 1 20`; do
> + create_target_attr_first $i $j $targ.$i.$j >> $seq.full 2>&1
> + done
> + FSRXFSTEST=true xfs_fsr -d -v -C $n $targ.$i.* >> $seq.full 2>&1
> + xfs_bmap -vp $targ.$i.* >> $seq.full 2>&1
> + for j in `seq 5 1 20`; do
> + create_target_attr_last $i $j $targ.$i.$j >> $seq.full 2>&1
> + done
> + FSRXFSTEST=true xfs_fsr -d -v -C $n $targ.$i.* >> $seq.full 2>&1
> + xfs_bmap -vp $targ.$i.* >> $seq.full 2>&1
> + done
> +done
> +
> +umount $SCRATCH_MNT
> +_check_scratch_fs
> +echo "--- silence is golden ---"
> +status=0 ; exit
> diff --git a/226.out b/226.out
> new file mode 100644
> index 0000000..52c0c1f
> --- /dev/null
> +++ b/226.out
> @@ -0,0 +1,2 @@
> +QA output created by 226
> +--- silence is golden ---
> diff --git a/group b/group
> index 3164c37..2386c41 100644
> --- a/group
> +++ b/group
> @@ -339,4 +339,5 @@ deprecated
> 223 auto quick
> 224 auto
> 225 auto quick
> -500 auto quota
> \ No newline at end of file
> +226 auto fsr
> +500 auto quota
> -- 1.6.5 _______________________________________________ xfs mailing
> list xfs@oss.sgi.com http://oss.sgi.com/mailman/listinfo/xfs
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] xfsqa: new fsr defragmentation test
2010-04-06 15:29 ` Eric Sandeen
@ 2010-04-06 23:19 ` Dave Chinner
0 siblings, 0 replies; 3+ messages in thread
From: Dave Chinner @ 2010-04-06 23:19 UTC (permalink / raw)
To: Eric Sandeen; +Cc: xfs
On Tue, Apr 06, 2010 at 10:29:31AM -0500, Eric Sandeen wrote:
> On 04/06/2010 03:52 AM, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> >
> > This test aims to recreate the conditions that caused xfs_fsr to
> > corrupt inode forks. The problem was that the data forks between the
> > two inodes were in different formats due to different inode fork
> > offsets, so when they swapped the data forks the formats were
> > invalid.
> >
> > This test generates a filesystem with a known fragmented freespace pattern and
> > then abuses known "behaviours" of the allocator to generate files
> > with a known number of extents. It creates attributes to generate a
> > known inode fork offset, then uses a debug feature of xfs_fsr to
> > attempt to defrag the inode to a known number of extents.
> >
> > By using these features, we can pretty much cover the entire matrix of inode
> > fork configurations, hence reproducing the conditions that lead to corruptions.
> > This test has already uncovered one bug in the current kernel code, and the
> > current fsr (with it's naive attribute fork handling) is aborted on a couple of
> > hundred of the files created by this test.
> >
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> > 226 | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 226.out | 2 +
> > group | 3 +-
> > 3 files changed, 196 insertions(+), 1 deletions(-)
> > create mode 100644 226
> > create mode 100644 226.out
> >
> > diff --git a/226 b/226
> > new file mode 100644
> > index 0000000..b92292a
> > --- /dev/null
> > +++ b/226
> > @@ -0,0 +1,192 @@
> > +#! /bin/bash
> > +# FS QA Test No. 222
>
> s/b 226
Ah, yeah, will fix.
> Looks like a good test but how fragile will it be in the face of changes
> to the known allocator behaviors? :)
It should be OK because the freespace is pretty robustly fragmented.
The allocator will always give fragemented files regardless of the
write patterns - it's just a question of how big the fragments will
be.
The only allocator behaviour being relied on is that it tries to
make the reverse sequential write block adjacent to the previous
block, but it can't find one because the previous block is always
carved from the first block of the free extent chosen by the
allocator. It'll take a pretty major shakeup of the allocator to
change that behaviour, and if we change it that much, tests all over
the place break....
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2010-04-06 23:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-06 8:52 [PATCH] xfsqa: new fsr defragmentation test Dave Chinner
2010-04-06 15:29 ` Eric Sandeen
2010-04-06 23:19 ` Dave Chinner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox