Merge branch 'master' of git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev
authorBen Myers <bpm@sgi.com>
Thu, 13 Sep 2012 20:01:58 +0000 (15:01 -0500)
committerBen Myers <bpm@sgi.com>
Thu, 13 Sep 2012 20:01:58 +0000 (15:01 -0500)
Conflicts:
285
285.out
group

Moved '285: Test xfs projid32bit functionality a bit more extensively' to 287.

26 files changed:
049
073
078
110
216
217
227
250
285
285.full [new file with mode: 0644]
285.out
286 [new file with mode: 0644]
286.full [new file with mode: 0644]
286.out [new file with mode: 0644]
287 [new file with mode: 0644]
287.out [new file with mode: 0644]
common.quota
group
ltp/Makefile
m4/package_acldev.m4
m4/package_attrdev.m4
m4/package_dmapidev.m4
m4/package_xfslibs.m4
src/Makefile
src/seek_copy_test.c [new file with mode: 0644]
src/seek_sanity_test.c [new file with mode: 0644]

diff --git a/049 b/049
index c6c4faa3817b9ce14426dd6f4af8ed13ccb8b8e6..c3065ad5839d76f2551b598330fce5eeb4217973 100755 (executable)
--- a/049
+++ b/049
@@ -30,8 +30,8 @@ echo "QA output created by $seq"
 _cleanup()
 {
     cd /
-    umount $SCRATCH_MNT/test2 > /dev/null 2>&1
-    umount $SCRATCH_MNT/test > /dev/null 2>&1
+    umount -d $SCRATCH_MNT/test2 > /dev/null 2>&1
+    umount -d $SCRATCH_MNT/test > /dev/null 2>&1
     rm -f $tmp.*
 
     if [ -w $seq.full ]
@@ -124,11 +124,11 @@ rm -rf $SCRATCH_MNT/test/* >> $seq.full 2>&1 \
     || _fail "!!! clean failed"
 
 _log "umount ext2 on xfs"
-umount $SCRATCH_MNT/test2 >> $seq.full 2>&1 \
+umount -d $SCRATCH_MNT/test2 >> $seq.full 2>&1 \
     || _fail "!!! umount ext2 failed"
 
 _log "umount xfs"
-umount $SCRATCH_MNT/test >> $seq.full 2>&1 \
+umount -d $SCRATCH_MNT/test >> $seq.full 2>&1 \
     || _fail "!!! umount xfs failed"
 
 echo "--- mounts at end (before cleanup)" >> $seq.full
diff --git a/073 b/073
index 18257d4fb3c97031fa17f2022d5ad46d1b89be47..96056626bf9fe7bd9cb4946fa0830dd0b1bebb79 100755 (executable)
--- a/073
+++ b/073
@@ -120,7 +120,7 @@ _verify_copy()
 
        echo unmounting and removing new image
        umount $source_dir
-       umount -d $target_dir
+       umount -d $target_dir > /dev/null 2>&1
        rm -f $target
 }
 
diff --git a/078 b/078
index 5cb66dfa11b5b2764c330d014796719186961b69..7af552e97ea8109eca20220dd9b254f1961f0001 100755 (executable)
--- a/078
+++ b/078
@@ -37,7 +37,7 @@ _cleanup()
 {
     cd /
     rm -f $tmp.*
-    umount $LOOP_MNT 2>/dev/null
+    umount -d $LOOP_MNT 2>/dev/null
     rmdir $LOOP_MNT
     _cleanup_testdir
 }
@@ -98,7 +98,7 @@ _grow_loop()
        $XFS_GROWFS_PROG $LOOP_MNT 2>&1 |  _filter_growfs 2>&1
 
        echo "*** unmount"
-       umount $LOOP_MNT
+       umount -d $LOOP_MNT > /dev/null 2>&1
 
        # Large grows takes forever to check..
        if [ "$check" -gt "0" ]
diff --git a/110 b/110
index aad58353a87b8cd69f03ccac5a3b11ffcf387a78..c58e6c9d4736d88dd644236cb7a5eec25141c0e2 100755 (executable)
--- a/110
+++ b/110
@@ -69,6 +69,7 @@ do
     let I=$I+1
     [ $[$I % 1000] -eq 0 ] && echo "Created $I/$E"
 done
+wait
 
 sync
 
diff --git a/216 b/216
index 7c046f5af1484b8844cf80b5711f8c9fc76f5604..71e6dd7d00a0f53e48e8901fb4e1d89c3294abf2 100755 (executable)
--- a/216
+++ b/216
@@ -63,7 +63,7 @@ _do_mkfs()
                        -d name=$LOOP_DEV,size=${i}g |grep log
                mount -o loop -t xfs $LOOP_DEV $LOOP_MNT
                echo "test write" > $LOOP_MNT/test
-               umount $LOOP_MNT
+               umount -d $LOOP_MNT > /dev/null 2>&1
        done
 }
 # make large holey file
diff --git a/217 b/217
index 19540ad496645e950074126e89f776c1497b47ef..ef0761e8ec7fcfacce300916e295f3ebb2aeb048 100755 (executable)
--- a/217
+++ b/217
@@ -65,7 +65,7 @@ _do_mkfs()
                        -d name=$LOOP_DEV,size=${i}g |grep log
                mount -o loop -t xfs $LOOP_DEV $LOOP_MNT
                echo "test write" > $LOOP_MNT/test
-               umount $LOOP_MNT
+               umount -d $LOOP_MNT > /dev/null 2>&1
        done
 }
 # make large holey file
diff --git a/227 b/227
index cb7fa70546ac91c4939b5351d8a55c3b96685817..dfcb1a5c5e4df24e54b2790ada96d155b7cae4bc 100755 (executable)
--- a/227
+++ b/227
@@ -52,6 +52,8 @@ _supported_fs xfs
 _supported_os Linux
 _require_scratch
 
+rm -f $seq.full
+
 [ "$XFS_FSR_PROG" = "" ] && _notrun "xfs_fsr not found"
 
 # create freespace holes of 1-3 blocks in length
@@ -62,26 +64,41 @@ _require_scratch
 # (say 5 extents) and lots of variations around that dependent on the
 # number of attributes in the files being defragmented.
 #
+# We have to make sure there are enough free inodes for the test to
+# pass without needing to allocate new clusters during the test.
+# With such fragemented free space, that will fail.
+#
 fragment_freespace()
 {
        _file="$SCRATCH_MNT/not_free"
+       _dir="$SCRATCH_MNT/saved"
 
-       for i in `seq 0 1 10000`; do
-               echo foo > $_file.$i
+       # allocate inode space
+       mkdir -p $_dir
+       for i in `seq 0 1 1000`; do
+               touch $_file.$i
        done
-       sync
-
-       for i in `seq 0 2 10000`; do
-               rm -f $_file.$i
+       for i in `seq 0 63 1000`; do
+               mv $_file.$i $_dir
        done
-       for i in `seq 0 7 10000`; do
+       for i in `seq 0 1 1000`; do
                rm -f $_file.$i
        done
+
+       $XFS_IO_PROG -fs -c "resvsp 0 40000k" $_file > /dev/null 2>&1
+
+       for i in `seq 0 8 40000`; do
+               $XFS_IO_PROG -f -c "unresvsp ${i}k 4k" $_file \
+                                       > /dev/null 2>&1
+       done
+       for i in `seq 0 28 40000`; do
+               $XFS_IO_PROG -f -c "unresvsp ${i}k 4k" $_file \
+                                       > /dev/null 2>&1
+       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
+       $XFS_IO_PROG -fs -c "resvsp 0 4m" $_file.large > /dev/null 2>&1
 }
 
 create_attrs()
@@ -93,11 +110,12 @@ create_attrs()
 
 create_data()
 {
+       size=`expr \( $1 + 1 \) \* 4096`
+       $XFS_IO_PROG -f -c "truncate $size" $2 > /dev/null 2>&1
        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
+               $XFS_IO_PROG -f -c "resvsp $offset 4096" $2 > /dev/null 2>&1
        done
-       xfs_bmap -vp $2
 }
 
 # create the designated file with a certain number of attributes and a certain
@@ -113,7 +131,7 @@ create_target_attr_first()
        target=$3
 
        rm -f $target
-       echo > $target
+       touch $target
        create_attrs $nattrs $target
        create_data $file_blocks $target
 }
@@ -131,7 +149,7 @@ create_target_attr_last()
        target=$3
 
        rm -f $target
-       echo > $target
+       touch $target
        create_data $file_blocks $target
        create_attrs $nattrs $target
 }
@@ -176,11 +194,13 @@ for n in `seq 4 1 12`; do
                for j in `seq 5 1 20`; do
                        create_target_attr_first $i $j $targ.$i.$j >> $seq.full 2>&1
                done
+               xfs_bmap -vp $targ.$i.* >> $seq.full 2>&1
                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
+               xfs_bmap -vp $targ.$i.* >> $seq.full 2>&1
                FSRXFSTEST=true xfs_fsr -d -v -C $n $targ.$i.* >> $seq.full 2>&1
                xfs_bmap -vp $targ.$i.* >> $seq.full 2>&1
        done
diff --git a/250 b/250
index 92e3cc5f21de27c414ee43b2c29237a7c7617e6b..9eca2b6dac1f39adf7563094e0660bf13a5b7efc 100755 (executable)
--- a/250
+++ b/250
@@ -34,7 +34,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _cleanup()
 {
        cd /
-       umount $LOOP_MNT 2>/dev/null
+       umount -d $LOOP_MNT 2>/dev/null
        rm -f $LOOP_DEV
        rmdir $LOOP_MNT
        _cleanup_testdir
@@ -85,7 +85,7 @@ _test_loop()
        xfs_io -f -c "resvsp 0 $fsize" $LOOP_MNT/foo | _filter_io
 
        echo "*** unmount loop filesystem"
-       umount $LOOP_MNT
+       umount -d $LOOP_MNT > /dev/null 2>&1
 
        echo "*** check loop filesystem"
         _check_xfs_filesystem $LOOP_DEV none none
diff --git a/285 b/285
index beb22348f3521407ffcc94893c20122030b458ea..a18fc7117461fe33d3404fd2d4d9505cac62749e 100644 (file)
--- a/285
+++ b/285
@@ -1,11 +1,14 @@
 #! /bin/bash
 # FS QA Test No. 285
 #
-# Test to verify project quota xfs_admin, xfsdump/xfsrestore and
-# xfs_db functionality
+# SEEK_DATA/SEEK_HOLE sanity tests.
+#
+# Improved by Jeff.liu@oracle.com
+# Creater: josef@redhat.com
 #
 #-----------------------------------------------------------------------
-# Copyright (c) 2012 Red Hat, Inc. All Rights Reserved.
+# Copyright (c) 2011 Oracle Inc.  All Rights Reserved.
+# Copyright (c) 2011 Red Hat.  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
 # 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=ranto.boris@gmail.com
+owner=jeff.liu@oracle.com
 
 seq=`basename $0`
 echo "QA output created by $seq"
-tmp=/tmp/$$
+
 here=`pwd`
 status=1       # failure is the default!
 trap "_cleanup; exit \$status" 0 1 2 3 15
-rm -f $seq.full
 
 # get standard environment, filters and checks
 . ./common.rc
-. ./common.quota
-
-_cleanup()
-{
-       cd /
-       umount $SCRATCH_MNT 2>/dev/null
-       rm -rf $tmp.*
-}
-
-_print_projid()
-{
-       $XFS_DB_PROG -c "inode $1" \
-               -c "print core.projid_lo" \
-               -c "print core.projid_hi" \
-               $SCRATCH_DEV
-}
-
-# real QA test starts here
-_supported_fs xfs
-_require_xfs_quota
-_require_scratch
-_require_projid32bit
-
-# create xfs fs without projid32bit ability, will be gained by xfs_admin
-_scratch_mkfs_xfs -i projid32bit=0 -d size=200m >> $seq.full \
-               || _fail "mkfs failed"
-_qmount_option "pquota"
-_qmount
-# require project quotas
-_require_prjquota $SCRATCH_DEV
-
-dir=$SCRATCH_MNT/pquota
-
-status=1
+. ./common.filter
 
-mkdir -p $dir
-touch $dir/{16,32}bit
-inode16a=$(ls -i $dir/16bit | cut -d ' ' -f 1)
-inode32a=$(ls -i $dir/32bit | cut -d ' ' -f 1)
-$XFS_QUOTA_PROG -x -c "project -s -p $dir/16bit 1234" $SCRATCH_DEV \
-               >> $seq.full
-$XFS_QUOTA_PROG -x -c "project -s -p $dir/32bit 2123456789" $SCRATCH_DEV \
-               >> $seq.full 2>&1
+_supported_fs generic
+_supported_os Linux
 
-echo "No 32bit project quotas:"
-$XFS_IO_PROG -r -c "lsproj" $dir/16bit
-$XFS_IO_PROG -r -c "lsproj" $dir/32bit
+BASE_TEST_FILE=$TEST_DIR/seek_sanity_testfile
 
-umount $SCRATCH_MNT
+[ -x $here/src/seek_sanity_test ] || _notrun "seek_sanitfy_tester not built"
 
-# Now, enable projid32bit support by xfs_admin
-xfs_admin -p $SCRATCH_DEV >> $seq.full 2>&1 || _fail "xfs_admin failed"
-
-# Now mount the fs, 32bit project quotas shall be supported, now
-_qmount_option "pquota"
-_qmount
-$XFS_QUOTA_PROG -x -c "project -s -p $dir/32bit 2123456789" $SCRATCH_DEV \
-               >> $seq.full
-
-# These will be checked by $seq.out
-echo "With 32bit project quota support:"
-$XFS_IO_PROG -r -c "lsproj" $dir/16bit
-$XFS_IO_PROG -r -c "lsproj" $dir/32bit
-
-# Dump the fs to a temporary file
-rm -f $tmp.dump.img
-$XFSDUMP_PROG -f $tmp.dump -L label -M media -l 0 $SCRATCH_MNT >> $seq.full \
-               || _fail "dump failed"
-
-# Prepare the device to restore the dumped file system
-restore_dir=$SCRATCH_MNT/restore/pquota
-
-# Just make the restore dir, the pquota dir will be created by xfsrestore
-mkdir -p $SCRATCH_MNT/restore
-
-# Restore
-$XFSRESTORE_PROG -f $tmp.dump $SCRATCH_MNT/restore >> $seq.full 2>&1 \
-               || _fail "xfsrestore failed"
-
-# Check that they are the same
-diff -urpN $SCRATCH_MNT/{,restore}/pquota || _fail "diff failed"
-
-touch $restore_dir/32bitv2
-inode16b=$(ls -i $restore_dir/16bit | cut -d ' ' -f 1)
-inode32b=$(ls -i $restore_dir/32bit | cut -d ' ' -f 1)
-inode32v2=$(ls -i $restore_dir/32bitv2 | cut -d ' ' -f 1)
-$XFS_QUOTA_PROG -x -c "project -s -p $restore_dir/32bitv2 2123456789" \
-               $SCRATCH_MNT >> $seq.full
-echo "The restored file system + one additional file:"
-$XFS_IO_PROG -r -c "lsproj" $restore_dir/16bit
-$XFS_IO_PROG -r -c "lsproj" $restore_dir/32bit
-$XFS_IO_PROG -r -c "lsproj" $restore_dir/32bitv2
-
-umount $SCRATCH_MNT
-
-# Now, we can examine the file systems with xfs_db
-echo "These two values of 16bit project quota ids shall be the same"
-_print_projid $inode16a
-_print_projid $inode16b
+_cleanup()
+{
+       eval "rm -f $BASE_TEST_FILE.*"
+}
 
-echo "These three values of 32bit project quota ids shall be the same"
-_print_projid $inode32b
-_print_projid $inode32a
-_print_projid $inode32v2
+$here/src/seek_sanity_test $BASE_TEST_FILE > $seq.full 2>&1 ||
+       _fail "seek sanity check failed!"
 
+# success, all done
 status=0
 exit
diff --git a/285.full b/285.full
new file mode 100644 (file)
index 0000000..f384aab
--- /dev/null
+++ b/285.full
@@ -0,0 +1,116 @@
+File system supports the default behavior.
+File system magic#: 0x58465342
+Allocation size: 4096
+
+01. Test empty file                                   
+01.01 SEEK_DATA expected -1 with errno -6, got -6.                succ
+01.02 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+01.03 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+
+02. Test a tiny full file                             
+02.01 SEEK_HOLE expected 8 or 8, got 8.                           succ
+02.02 SEEK_DATA expected 0 or 0, got 0.                           succ
+02.03 SEEK_DATA expected 1 or 1, got 1.                           succ
+02.04 SEEK_HOLE expected 8 or 8, got 8.                           succ
+02.05 SEEK_DATA expected 7 or 7, got 7.                           succ
+02.06 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+02.07 SEEK_DATA expected -1 with errno -6, got -6.                succ
+02.08 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+02.09 SEEK_DATA expected -1 with errno -6, got -6.                succ
+
+03. Test a larger full file                           
+03.01 SEEK_HOLE expected 8292 or 8292, got 8292.                  succ
+03.02 SEEK_HOLE expected 8292 or 8292, got 8292.                  succ
+03.03 SEEK_DATA expected 0 or 0, got 0.                           succ
+03.04 SEEK_DATA expected 1 or 1, got 1.                           succ
+03.05 SEEK_HOLE expected 8292 or 8292, got 8292.                  succ
+03.06 SEEK_DATA expected 8291 or 8291, got 8291.                  succ
+03.07 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+03.08 SEEK_DATA expected -1 with errno -6, got -6.                succ
+03.09 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+03.10 SEEK_DATA expected -1 with errno -6, got -6.                succ
+
+04. Test file hole at beg, data at end                
+04.01 SEEK_HOLE expected 0 or 8200, got 0.                        succ
+04.02 SEEK_HOLE expected 1 or 8200, got 1.                        succ
+04.03 SEEK_DATA expected 8192 or 0, got 8192.                     succ
+04.04 SEEK_DATA expected 8192 or 1, got 8192.                     succ
+04.05 SEEK_HOLE expected 8191 or 8200, got 8191.                  succ
+04.06 SEEK_DATA expected 8192 or 8191, got 8192.                  succ
+04.07 SEEK_HOLE expected 8200 or 8200, got 8200.                  succ
+04.08 SEEK_DATA expected 8192 or 8192, got 8192.                  succ
+04.09 SEEK_HOLE expected 8200 or 8200, got 8200.                  succ
+04.10 SEEK_DATA expected 8193 or 8193, got 8193.                  succ
+04.11 SEEK_HOLE expected 8200 or 8200, got 8200.                  succ
+04.12 SEEK_DATA expected 8199 or 8199, got 8199.                  succ
+04.13 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+04.14 SEEK_DATA expected -1 with errno -6, got -6.                succ
+04.15 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+04.16 SEEK_DATA expected -1 with errno -6, got -6.                succ
+
+05. Test file data at beg, hole at end                
+05.01 SEEK_HOLE expected 4096 or 16384, got 4096.                 succ
+05.02 SEEK_HOLE expected 4096 or 16384, got 4096.                 succ
+05.03 SEEK_DATA expected 0 or 0, got 0.                           succ
+05.04 SEEK_DATA expected 1 or 1, got 1.                           succ
+05.05 SEEK_HOLE expected 4096 or 16384, got 4096.                 succ
+05.06 SEEK_DATA expected 4095 or 4095, got 4095.                  succ
+05.07 SEEK_HOLE expected 4096 or 16384, got 4096.                 succ
+05.08 SEEK_DATA expected -1 with errno -6, got -6.                succ
+05.09 SEEK_HOLE expected 4097 or 16384, got 4097.                 succ
+05.10 SEEK_DATA expected -1 with errno -6, got -6.                succ
+05.11 SEEK_HOLE expected 16383 or 16384, got 16383.               succ
+05.12 SEEK_DATA expected -1 with errno -6, got -6.                succ
+05.13 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+05.14 SEEK_DATA expected -1 with errno -6, got -6.                succ
+05.15 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+05.16 SEEK_DATA expected -1 with errno -6, got -6.                succ
+
+06. Test file hole data hole data                     
+06.01 SEEK_HOLE expected 0 or 16384, got 0.                       succ
+06.02 SEEK_HOLE expected 1 or 16384, got 1.                       succ
+06.03 SEEK_DATA expected 4096 or 0, got 4096.                     succ
+06.04 SEEK_DATA expected 4096 or 1, got 4096.                     succ
+06.05 SEEK_HOLE expected 4095 or 16384, got 4095.                 succ
+06.06 SEEK_DATA expected 4096 or 4095, got 4096.                  succ
+06.07 SEEK_HOLE expected 8192 or 16384, got 16384.                succ
+06.08 SEEK_DATA expected 4096 or 4096, got 4096.                  succ
+06.09 SEEK_HOLE expected 8192 or 16384, got 16384.                succ
+06.10 SEEK_DATA expected 4097 or 4097, got 4097.                  succ
+06.11 SEEK_HOLE expected 8192 or 16384, got 16384.                succ
+06.12 SEEK_DATA expected 8191 or 8191, got 8191.                  succ
+06.13 SEEK_HOLE expected 8192 or 16384, got 16384.                succ
+06.14 SEEK_DATA expected 12288 or 8192, got 8192.                 succ
+06.15 SEEK_HOLE expected 8193 or 16384, got 16384.                succ
+06.16 SEEK_DATA expected 12288 or 8193, got 8193.                 succ
+06.17 SEEK_HOLE expected 12287 or 16384, got 16384.               succ
+06.18 SEEK_DATA expected 12288 or 12287, got 12287.               succ
+06.19 SEEK_HOLE expected 16384 or 16384, got 16384.               succ
+06.20 SEEK_DATA expected 12288 or 12288, got 12288.               succ
+06.21 SEEK_HOLE expected 16384 or 16384, got 16384.               succ
+06.22 SEEK_DATA expected 12289 or 12289, got 12289.               succ
+06.23 SEEK_HOLE expected 16384 or 16384, got 16384.               succ
+06.24 SEEK_DATA expected 16383 or 16383, got 16383.               succ
+06.25 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+06.26 SEEK_DATA expected -1 with errno -6, got -6.                succ
+06.27 SEEK_HOLE expected -1 with errno -6, got -6.                succ
+06.28 SEEK_DATA expected -1 with errno -6, got -6.                succ
+
+07. Test file with unwritten extents, only have dirty pages
+07.01 SEEK_HOLE expected 0 or 4194304, got 4194304.               succ
+07.02 SEEK_HOLE expected 1 or 4194304, got 4194304.               succ
+07.03 SEEK_DATA expected 40960 or 0, got 0.                       succ
+07.04 SEEK_DATA expected 40960 or 1, got 1.                       succ
+
+08. Test file with unwritten extents, only have unwritten pages
+08.01 SEEK_HOLE expected 0 or 4194304, got 4194304.               succ
+08.02 SEEK_HOLE expected 1 or 4194304, got 4194304.               succ
+08.03 SEEK_DATA expected 40960 or 0, got 0.                       succ
+08.04 SEEK_DATA expected 40960 or 1, got 1.                       succ
+
+09. Test file with unwritten extents, have both dirty && unwritten pages
+09.01 SEEK_HOLE expected 0 or 8388608, got 8388608.               succ
+09.02 SEEK_HOLE expected 1 or 8388608, got 8388608.               succ
+09.03 SEEK_DATA expected 40960 or 0, got 0.                       succ
+09.04 SEEK_DATA expected 40960 or 1, got 1.                       succ
+
diff --git a/285.out b/285.out
index e5cc325213066274f223fbfeb33f46932b575fe8..58759aa5814c29764006e346fb9346573ceafae0 100644 (file)
--- a/285.out
+++ b/285.out
@@ -1,23 +1 @@
 QA output created by 285
-No 32bit project quotas:
-projid = 1234
-projid = 0
-With 32bit project quota support:
-projid = 1234
-projid = 2123456789
-The restored file system + one additional file:
-projid = 1234
-projid = 2123456789
-projid = 2123456789
-These two values of 16bit project quota ids shall be the same
-core.projid_lo = 1234
-core.projid_hi = 0
-core.projid_lo = 1234
-core.projid_hi = 0
-These three values of 32bit project quota ids shall be the same
-core.projid_lo = 24853
-core.projid_hi = 32401
-core.projid_lo = 24853
-core.projid_hi = 32401
-core.projid_lo = 24853
-core.projid_hi = 32401
diff --git a/286 b/286
new file mode 100644 (file)
index 0000000..03c343f
--- /dev/null
+++ b/286
@@ -0,0 +1,114 @@
+#! /bin/bash
+# FS QA Test No. 286
+#
+# SEEK_DATA/SEEK_HOLE copy tests.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2011 Oracle Inc.  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=jeff.liu@oracle.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1       # failure is the default!
+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 generic
+_supported_os Linux
+
+src=$TEST_DIR/seek_copy_testfile
+dest=$TEST_DIR/seek_copy_testfile.dest
+
+[ -x $here/src/seek_copy_test ] || _notrun "seek_copy_test not built"
+
+_cleanup()
+{
+       rm -f $src $dest
+}
+
+# seek_copy_test_01: tests file with holes and written data extents.
+# verify results:
+# 1. file size is identical.
+# 2. perform cmp(1) to compare SRC and DEST file byte by byte.
+test01()
+{
+       rm -f $src $dest
+
+       write_cmd="-c \"truncate 100m\""
+       for i in $(seq 0 5 100); do
+               offset=$(($i * $((1 << 20))))
+               write_cmd="$write_cmd -c \"pwrite $offset 1m\""
+       done
+
+       echo "*** test01() create sparse file ***" >>$seq.full
+       eval ${XFS_IO_PROG} -F -f "${write_cmd}" $src >>$seq.full 2>&1 ||
+               _fail "create sparse file failed!"
+       echo "*** test01() create sparse file done ***" >>$seq.full
+       echo >>$seq.full
+
+       $here/src/seek_copy_test $src $dest
+       
+       test $(stat --printf "%s" $src) = $(stat --printf "%s" $dest) ||
+               _fail "TEST01: file size check failed"
+
+       cmp $src $dest || _fail "TEST01: file bytes check failed"
+}
+
+# seek_copy_test_02 - tests file with holes, written and unwritten extents.
+# verify results:
+# 1. file size is identical.
+# 2. perform cmp(1) to compare SRC and DEST file byte by byte.
+test02()
+{
+       rm -rf $src $dest
+
+       write_cmd="-c \"truncate 200m\""
+       for i in $(seq 0 10 100); do
+               offset=$(($((6 << 20)) + $i * $((1 << 20))))
+               write_cmd="$write_cmd -c \"falloc $offset 3m\" -c \"pwrite $offset 1m\""
+       done
+
+       echo "*** test02() create sparse file ***" >>$seq.full
+       eval ${XFS_IO_PROG} -F -f "${write_cmd}" $src >>$seq.full 2>&1 ||
+               _fail "create sparse file failed!"
+       echo "*** test02() create sparse file done ***" >>$seq.full
+       echo >>$seq.full
+
+       $here/src/seek_copy_test $src $dest
+
+       test $(stat --printf "%s" $src) = $(stat --printf "%s" $dest) ||
+               _fail "TEST02: file size check failed"
+
+       cmp $src $dest || _fail "TEST02: file bytes check failed"
+}
+
+rm -f $seq.full
+
+test01
+test02
+
+status=0
+exit
diff --git a/286.full b/286.full
new file mode 100644 (file)
index 0000000..b4e4f08
--- /dev/null
+++ b/286.full
@@ -0,0 +1,70 @@
+*** test01() create sparse file ***
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, 256 ops; 0.0000 sec (1.242 GiB/sec and 325699.7455 ops/sec)
+wrote 1048576/1048576 bytes at offset 5242880
+1 MiB, 256 ops; 0.0000 sec (1.160 GiB/sec and 304038.0048 ops/sec)
+wrote 1048576/1048576 bytes at offset 10485760
+1 MiB, 256 ops; 0.0000 sec (1.112 GiB/sec and 291571.7540 ops/sec)
+wrote 1048576/1048576 bytes at offset 15728640
+1 MiB, 256 ops; 0.0000 sec (1.095 GiB/sec and 286995.5157 ops/sec)
+wrote 1048576/1048576 bytes at offset 20971520
+1 MiB, 256 ops; 0.0000 sec (1.094 GiB/sec and 286674.1321 ops/sec)
+wrote 1048576/1048576 bytes at offset 26214400
+1 MiB, 256 ops; 0.0000 sec (1.085 GiB/sec and 284444.4444 ops/sec)
+wrote 1048576/1048576 bytes at offset 31457280
+1 MiB, 256 ops; 0.0000 sec (1.065 GiB/sec and 279171.2105 ops/sec)
+wrote 1048576/1048576 bytes at offset 36700160
+1 MiB, 256 ops; 0.0000 sec (1.064 GiB/sec and 278867.1024 ops/sec)
+wrote 1048576/1048576 bytes at offset 41943040
+1 MiB, 256 ops; 0.0000 sec (1.068 GiB/sec and 280087.5274 ops/sec)
+wrote 1048576/1048576 bytes at offset 47185920
+1 MiB, 256 ops; 0.0000 sec (1.058 GiB/sec and 277356.4464 ops/sec)
+wrote 1048576/1048576 bytes at offset 52428800
+1 MiB, 256 ops; 0.0000 sec (1.067 GiB/sec and 279781.4208 ops/sec)
+wrote 1048576/1048576 bytes at offset 57671680
+1 MiB, 256 ops; 0.0000 sec (1.071 GiB/sec and 280701.7544 ops/sec)
+wrote 1048576/1048576 bytes at offset 62914560
+1 MiB, 256 ops; 0.0000 sec (1.071 GiB/sec and 280701.7544 ops/sec)
+wrote 1048576/1048576 bytes at offset 68157440
+1 MiB, 256 ops; 0.0000 sec (1.074 GiB/sec and 281628.1628 ops/sec)
+wrote 1048576/1048576 bytes at offset 73400320
+1 MiB, 256 ops; 0.0000 sec (1.071 GiB/sec and 280701.7544 ops/sec)
+wrote 1048576/1048576 bytes at offset 78643200
+1 MiB, 256 ops; 0.0000 sec (1.068 GiB/sec and 280087.5274 ops/sec)
+wrote 1048576/1048576 bytes at offset 83886080
+1 MiB, 256 ops; 0.0000 sec (1.073 GiB/sec and 281318.6813 ops/sec)
+wrote 1048576/1048576 bytes at offset 89128960
+1 MiB, 256 ops; 0.0000 sec (1.068 GiB/sec and 280087.5274 ops/sec)
+wrote 1048576/1048576 bytes at offset 94371840
+1 MiB, 256 ops; 0.0000 sec (1.085 GiB/sec and 284444.4444 ops/sec)
+wrote 1048576/1048576 bytes at offset 99614720
+1 MiB, 256 ops; 0.0000 sec (1.055 GiB/sec and 276457.8834 ops/sec)
+wrote 1048576/1048576 bytes at offset 104857600
+1 MiB, 256 ops; 0.0000 sec (1.140 GiB/sec and 298716.4527 ops/sec)
+*** test01() create sparse file done ***
+
+*** test02() create sparse file ***
+wrote 1048576/1048576 bytes at offset 6291456
+1 MiB, 256 ops; 0.0000 sec (1.360 GiB/sec and 356545.9610 ops/sec)
+wrote 1048576/1048576 bytes at offset 16777216
+1 MiB, 256 ops; 0.0000 sec (1.385 GiB/sec and 363120.5674 ops/sec)
+wrote 1048576/1048576 bytes at offset 27262976
+1 MiB, 256 ops; 0.0000 sec (1.340 GiB/sec and 351165.9808 ops/sec)
+wrote 1048576/1048576 bytes at offset 37748736
+1 MiB, 256 ops; 0.0000 sec (1.309 GiB/sec and 343163.5389 ops/sec)
+wrote 1048576/1048576 bytes at offset 48234496
+1 MiB, 256 ops; 0.0000 sec (1.267 GiB/sec and 332036.3165 ops/sec)
+wrote 1048576/1048576 bytes at offset 58720256
+1 MiB, 256 ops; 0.0000 sec (1.285 GiB/sec and 336842.1053 ops/sec)
+wrote 1048576/1048576 bytes at offset 69206016
+1 MiB, 256 ops; 0.0000 sec (1.288 GiB/sec and 337730.8707 ops/sec)
+wrote 1048576/1048576 bytes at offset 79691776
+1 MiB, 256 ops; 0.0000 sec (1.278 GiB/sec and 335078.5340 ops/sec)
+wrote 1048576/1048576 bytes at offset 90177536
+1 MiB, 256 ops; 0.0000 sec (1.293 GiB/sec and 339072.8477 ops/sec)
+wrote 1048576/1048576 bytes at offset 100663296
+1 MiB, 256 ops; 0.0000 sec (1.280 GiB/sec and 335517.6933 ops/sec)
+wrote 1048576/1048576 bytes at offset 111149056
+1 MiB, 256 ops; 0.0000 sec (1.285 GiB/sec and 336842.1053 ops/sec)
+*** test02() create sparse file done ***
+
diff --git a/286.out b/286.out
new file mode 100644 (file)
index 0000000..6415ad8
--- /dev/null
+++ b/286.out
@@ -0,0 +1 @@
+QA output created by 286
diff --git a/287 b/287
new file mode 100644 (file)
index 0000000..beb2234
--- /dev/null
+++ b/287
@@ -0,0 +1,144 @@
+#! /bin/bash
+# FS QA Test No. 285
+#
+# Test to verify project quota xfs_admin, xfsdump/xfsrestore and
+# xfs_db functionality
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2012 Red Hat, Inc. 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=ranto.boris@gmail.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+tmp=/tmp/$$
+here=`pwd`
+status=1       # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+rm -f $seq.full
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.quota
+
+_cleanup()
+{
+       cd /
+       umount $SCRATCH_MNT 2>/dev/null
+       rm -rf $tmp.*
+}
+
+_print_projid()
+{
+       $XFS_DB_PROG -c "inode $1" \
+               -c "print core.projid_lo" \
+               -c "print core.projid_hi" \
+               $SCRATCH_DEV
+}
+
+# real QA test starts here
+_supported_fs xfs
+_require_xfs_quota
+_require_scratch
+_require_projid32bit
+
+# create xfs fs without projid32bit ability, will be gained by xfs_admin
+_scratch_mkfs_xfs -i projid32bit=0 -d size=200m >> $seq.full \
+               || _fail "mkfs failed"
+_qmount_option "pquota"
+_qmount
+# require project quotas
+_require_prjquota $SCRATCH_DEV
+
+dir=$SCRATCH_MNT/pquota
+
+status=1
+
+mkdir -p $dir
+touch $dir/{16,32}bit
+inode16a=$(ls -i $dir/16bit | cut -d ' ' -f 1)
+inode32a=$(ls -i $dir/32bit | cut -d ' ' -f 1)
+$XFS_QUOTA_PROG -x -c "project -s -p $dir/16bit 1234" $SCRATCH_DEV \
+               >> $seq.full
+$XFS_QUOTA_PROG -x -c "project -s -p $dir/32bit 2123456789" $SCRATCH_DEV \
+               >> $seq.full 2>&1
+
+echo "No 32bit project quotas:"
+$XFS_IO_PROG -r -c "lsproj" $dir/16bit
+$XFS_IO_PROG -r -c "lsproj" $dir/32bit
+
+umount $SCRATCH_MNT
+
+# Now, enable projid32bit support by xfs_admin
+xfs_admin -p $SCRATCH_DEV >> $seq.full 2>&1 || _fail "xfs_admin failed"
+
+# Now mount the fs, 32bit project quotas shall be supported, now
+_qmount_option "pquota"
+_qmount
+$XFS_QUOTA_PROG -x -c "project -s -p $dir/32bit 2123456789" $SCRATCH_DEV \
+               >> $seq.full
+
+# These will be checked by $seq.out
+echo "With 32bit project quota support:"
+$XFS_IO_PROG -r -c "lsproj" $dir/16bit
+$XFS_IO_PROG -r -c "lsproj" $dir/32bit
+
+# Dump the fs to a temporary file
+rm -f $tmp.dump.img
+$XFSDUMP_PROG -f $tmp.dump -L label -M media -l 0 $SCRATCH_MNT >> $seq.full \
+               || _fail "dump failed"
+
+# Prepare the device to restore the dumped file system
+restore_dir=$SCRATCH_MNT/restore/pquota
+
+# Just make the restore dir, the pquota dir will be created by xfsrestore
+mkdir -p $SCRATCH_MNT/restore
+
+# Restore
+$XFSRESTORE_PROG -f $tmp.dump $SCRATCH_MNT/restore >> $seq.full 2>&1 \
+               || _fail "xfsrestore failed"
+
+# Check that they are the same
+diff -urpN $SCRATCH_MNT/{,restore}/pquota || _fail "diff failed"
+
+touch $restore_dir/32bitv2
+inode16b=$(ls -i $restore_dir/16bit | cut -d ' ' -f 1)
+inode32b=$(ls -i $restore_dir/32bit | cut -d ' ' -f 1)
+inode32v2=$(ls -i $restore_dir/32bitv2 | cut -d ' ' -f 1)
+$XFS_QUOTA_PROG -x -c "project -s -p $restore_dir/32bitv2 2123456789" \
+               $SCRATCH_MNT >> $seq.full
+echo "The restored file system + one additional file:"
+$XFS_IO_PROG -r -c "lsproj" $restore_dir/16bit
+$XFS_IO_PROG -r -c "lsproj" $restore_dir/32bit
+$XFS_IO_PROG -r -c "lsproj" $restore_dir/32bitv2
+
+umount $SCRATCH_MNT
+
+# Now, we can examine the file systems with xfs_db
+echo "These two values of 16bit project quota ids shall be the same"
+_print_projid $inode16a
+_print_projid $inode16b
+
+echo "These three values of 32bit project quota ids shall be the same"
+_print_projid $inode32b
+_print_projid $inode32a
+_print_projid $inode32v2
+
+status=0
+exit
diff --git a/287.out b/287.out
new file mode 100644 (file)
index 0000000..1a8d05a
--- /dev/null
+++ b/287.out
@@ -0,0 +1,23 @@
+QA output created by 287
+No 32bit project quotas:
+projid = 1234
+projid = 0
+With 32bit project quota support:
+projid = 1234
+projid = 2123456789
+The restored file system + one additional file:
+projid = 1234
+projid = 2123456789
+projid = 2123456789
+These two values of 16bit project quota ids shall be the same
+core.projid_lo = 1234
+core.projid_hi = 0
+core.projid_lo = 1234
+core.projid_hi = 0
+These three values of 32bit project quota ids shall be the same
+core.projid_lo = 24853
+core.projid_hi = 32401
+core.projid_lo = 24853
+core.projid_hi = 32401
+core.projid_lo = 24853
+core.projid_hi = 32401
index 97363063299b2f83873ac311a717ce5854ef3f6b..2fa784b83f3c950affe1c763d7934790fdc8fd03 100644 (file)
@@ -236,6 +236,11 @@ _check_quota_usage()
 {
        # Sync to get delalloc to disk
        sync
+
+       # kill caches to guarantee removal speculative delalloc
+       # XXX: really need an ioctl instead of this big hammer
+       echo 3 > /proc/sys/vm/drop_caches
+
        VFS_QUOTA=0
        case $FSTYP in
        ext2|ext3|ext4|ext4dev|reiserfs)
@@ -253,8 +258,9 @@ _check_quota_usage()
                quotacheck -u -g $SCRATCH_MNT 2>/dev/null
        else
                # use XFS method to force quotacheck
-               mount -o remount,noquota $SCRATCH_DEV
-               mount -o remount,usrquota,grpquota $SCRATCH_DEV
+               xfs_quota -x -c "off -ug" $SCRATCH_MNT
+               _scratch_unmount
+               _scratch_mount "-o usrquota,grpquota"
        fi
        repquota -u -n $SCRATCH_MNT  | grep -v "^#0" | _filter_scratch |
                sort >$tmp.user.checked
diff --git a/group b/group
index 697269bdb1b17a775c3a16874f8369e56e592aaa..f52c5d5746ac8d8297164c754917d2f7651feb0a 100644 (file)
--- a/group
+++ b/group
@@ -403,4 +403,6 @@ deprecated
 282 dump ioctl auto quick
 283 dump ioctl auto quick
 284 auto
-285 auto dump quota quick
+285 auto rw
+286 other
+287 auto dump quota quick
index d47247bc808bf3c4d8df4a6c1df0cfcbc9555411..5bea492789f3f92a88a21b76808e284f5a7a4e85 100644 (file)
@@ -44,7 +44,7 @@ $(TARGETS): $(LIBTEST)
 
 install: default
        $(INSTALL) -m 755 -d $(PKG_LIB_DIR)/ltp
-       $(INSTALL) -m 755 $(TARGETS) $(PKG_LIB_DIR)/ltp
+       $(LTINSTALL) -m 755 $(TARGETS) $(PKG_LIB_DIR)/ltp
        $(INSTALL) -m 755 $(SCRIPTS) $(PKG_LIB_DIR)/ltp
 
 -include .dep
index 0cbd19f53bdb3a5bd9a80eae4f3bf08d3a863a96..25d601944f3f4c11d238b87617473992829a229f 100644 (file)
@@ -30,8 +30,6 @@ AC_DEFUN([AC_PACKAGE_NEED_ACLINIT_LIBACL],
         exit 1
     ])
     libacl="-lacl"
-    test -f `pwd`/../acl/libacl/libacl.la && \
-        libacl="`pwd`/../acl/libacl/libacl.la"
     test -f ${libexecdir}${libdirsuffix}/libacl.la && \
        libacl="${libexecdir}${libdirsuffix}/libacl.la"
     AC_SUBST(libacl)
index 461ddffb902f2fae8df660665c3506da50881738..12251ceb63c3e489338c1686be28c84fc2552662 100644 (file)
@@ -46,8 +46,6 @@ AC_DEFUN([AC_PACKAGE_NEED_GETXATTR_LIBATTR],
         exit 1
     ])
     libattr="-lattr"
-    test -f `pwd`/../attr/libattr/libattr.la && \
-        libattr="`pwd`/../attr/libattr/libattr.la"
     test -f ${libexecdir}${libdirsuffix}/libattr.la && \
        libattr="${libexecdir}${libdirsuffix}/libattr.la"
     AC_SUBST(libattr)
@@ -62,8 +60,6 @@ AC_DEFUN([AC_PACKAGE_NEED_ATTRGET_LIBATTR],
         exit 1
     ])
     libattr="-lattr"
-    test -f `pwd`/../attr/libattr/libattr.la && \
-        libattr="`pwd`/../attr/libattr/libattr.la"
     test -f ${libexecdir}${libdirsuffix}/libattr.la && \
        libattr="${libexecdir}${libdirsuffix}/libattr.la"
     AC_SUBST(libattr)
index 652db306aa2ed2fe02d7e87fb8344a620504d146..6a7257eebf7aaef042f7cf8dec0798ffbb8efff3 100644 (file)
@@ -20,8 +20,6 @@ AC_DEFUN([AC_PACKAGE_WANT_DMAPI],
        echo
     ])
     libdm="-ldm"
-    test -f `pwd`/../dmapi/libdm/libdm.la && \
-        libdm="`pwd`/../dmapi/libdm/libdm.la"
     test -f ${libexecdir}${libdirsuffix}/libdm.la && \
        libdm="${libexecdir}${libdirsuffix}/libdm.la"
     AC_SUBST(libdm)
index f5167a2b0bc2bff2bf0fa28d866f333ed52405e0..78a3dc473ea0420d23511eef52f229262808b363 100644 (file)
@@ -51,8 +51,6 @@ AC_DEFUN([AC_PACKAGE_NEED_LIBXFSINIT_LIBXFS],
         exit 1
     ])
     libxfs="-lxfs"
-    test -f `pwd`/../xfsprogs/libxfs/libxfs.la && \
-        libxfs="`pwd`/../xfsprogs/libxfs/libxfs.la"
     test -f ${libexecdir}${libdirsuffix}/libxfs.la && \
        libxfs="${libexecdir}${libdirsuffix}/libxfs.la"
     AC_SUBST(libxfs)
@@ -67,8 +65,6 @@ AC_DEFUN([AC_PACKAGE_NEED_OPEN_BY_FSHANDLE],
         exit 1
     ])
     libhdl="-lhandle"
-    test -f `pwd`/../xfsprogs/libhandle/libhandle.la && \
-        libhdl="`pwd`/../xfsprogs/libhandle/libhandle.la"
     test -f ${libexecdir}${libdirsuffix}/libhandle.la && \
        libhdl="${libexecdir}${libdirsuffix}/libhandle.la"
     AC_SUBST(libhdl)
@@ -83,8 +79,6 @@ AC_DEFUN([AC_PACKAGE_NEED_ATTRLIST_LIBHANDLE],
         exit 1
     ])
     libhdl="-lhandle"
-    test -f `pwd`/../xfsprogs/libhandle/libhandle.la && \
-        libhdl="`pwd`/../xfsprogs/libhandle/libhandle.la"
     test -f ${libexecdir}${libdirsuffix}/libhandle.la && \
        libhdl="${libexecdir}${libdirsuffix}/libhandle.la"
     AC_SUBST(libhdl)
index 67250ee53062314214ac90279b2c50cfcb284dff..c773b5c2ac365d879b85479f587f59fc4e65fa4f 100644 (file)
@@ -17,7 +17,8 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
        preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
        locktest unwritten_mmap bulkstat_unlink_test t_stripealign \
        bulkstat_unlink_test_modified t_dir_offset t_futimens t_immutable \
-       stale_handle pwrite_mmap_blocked fstrim t_dir_offset2
+       stale_handle pwrite_mmap_blocked fstrim t_dir_offset2 seek_sanity_test \
+       seek_copy_test
 
 SUBDIRS =
 
@@ -73,9 +74,9 @@ LINKTEST = $(LTLINK) $@.c -o $@ $(CFLAGS) $(LDFLAGS)
 
 install: default $(addsuffix -install,$(SUBDIRS))
        $(INSTALL) -m 755 -d $(PKG_LIB_DIR)/src
-       $(INSTALL) -m 755 $(TARGETS) $(PKG_LIB_DIR)/src
-       $(INSTALL) -m 755 fill2attr fill2fs fill2fs_check scaleread.sh $(PKG_LIB_DIR)/src
-       $(INSTALL) -m 644 dumpfile $(PKG_LIB_DIR)/src
+       $(LTINSTALL) -m 755 $(TARGETS) $(PKG_LIB_DIR)/src
+       $(LTINSTALL) -m 755 fill2attr fill2fs fill2fs_check scaleread.sh $(PKG_LIB_DIR)/src
+       $(LTINSTALL) -m 644 dumpfile $(PKG_LIB_DIR)/src
 
 %-install:
        $(MAKE) -C $* install
diff --git a/src/seek_copy_test.c b/src/seek_copy_test.c
new file mode 100644 (file)
index 0000000..ee5e434
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2011 Oracle.  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 v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will 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 to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+#define _XOPEN_SOURCE 500
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifndef SEEK_DATA
+#define SEEK_DATA      3
+#define SEEK_HOLE      4
+#endif
+
+#define BUF_SIZE       4096
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+static void
+error(const char *fmt, ...)
+{
+       char buf[256];
+       va_list args;
+       va_start(args, fmt);
+       vsprintf(buf, fmt, args);
+       va_end(args);
+
+       fprintf(stderr, "ERROR: [%s:%d] %s:%s\n", __func__, __LINE__,
+               buf, strerror(errno));
+}
+
+static size_t
+full_write(int fd, const void *buf, size_t count)
+{
+       size_t total = 0;
+       const char *ptr = (const char *) buf;
+
+       while (count > 0) {
+               ssize_t n = write(fd, ptr, count);
+               if (n < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       error("failed as %s", strerror(errno));
+                       break;
+               }
+
+               if (n == 0) {
+                       error("%zu bytes transferred. Aborting.",
+                              total);
+                       break;
+               }
+
+               total += n;
+               ptr += n;
+               count -= n;
+       }
+
+       return total;
+}
+
+/*
+ * Copy a data extent from source file to dest file.
+ * @data_off: data offset
+ * @hole_off: hole offset
+ * The length of this extent is (hole_off - data_off).
+ */
+static int
+do_extent_copy(int src_fd, int dest_fd, off_t data_off, off_t hole_off)
+{
+       uint64_t len = (uint64_t)(hole_off - data_off);
+       char buf[BUF_SIZE];
+       int ret;
+
+       /* Seek to data_off for data reading */
+       ret = lseek(src_fd, data_off, SEEK_SET);
+       if (ret < 0) {
+               error("seek source file to %llu failed as %s",
+                      (uint64_t)data_off, strerror(errno));
+               return ret;
+       }
+
+       /* Seek to data_off for data writing, make holes as well */
+       ret = lseek(dest_fd, data_off, SEEK_SET);
+       if (ret < 0) {
+               error("seek dest file to %llu failed as %s",
+                      (uint64_t)data_off, strerror(errno));
+               return ret;
+       }
+
+       while (len > 0) {
+               ssize_t nr_read = read(src_fd, buf, BUF_SIZE);
+               if (nr_read < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       error("read source file extent failed as %s",
+                             strerror(errno));
+                       ret = -1;
+                       break;
+               }
+
+               if (nr_read == 0) {
+                       error("reached EOF");
+                       break;
+               }
+
+               if (full_write(dest_fd, buf, nr_read) != nr_read) {
+                       error("write data to dest file failed as %s",
+                              strerror(errno));
+                       ret = -1;
+                       break;
+               }
+
+               len -= nr_read;
+       }
+
+       return ret;
+}
+
+/*
+ * If lseek(2) failed and the errno is set to ENXIO, for
+ * SEEK_DATA there are no more data regions past the supplied
+ * offset.  For SEEK_HOLE, there are no more holes past the
+ * supplied offset.  Set scan->hit_final_extent to true for
+ * either case.
+ */
+static int
+copy_extents(int src_fd, int dest_fd, off_t src_total_size)
+{
+       int ret = 0;
+       off_t seek_start = 0;
+       off_t dest_pos = 0;
+       off_t data_pos, hole_pos;
+
+       do {
+               data_pos = lseek(src_fd, seek_start, SEEK_DATA);
+               if (data_pos < 0) {
+                       if (errno == ENXIO)
+                               ret = 0;
+                       else {
+                               error("SEEK_DATA failed due to %s",
+                                      strerror(errno));
+                               ret = -1;
+                       }
+                       break;
+               }
+
+               hole_pos = lseek(src_fd, data_pos, SEEK_HOLE);
+               if (hole_pos < 0) {
+                       if (errno == ENXIO)
+                               ret = 0;
+                       else {
+                               error("SEEK_HOLE failed due to %s\n",
+                                      strerror(errno));
+                               ret = -1;
+                       }
+                       break;
+               }
+
+               /* do extent copy */
+               ret = do_extent_copy(src_fd, dest_fd, data_pos, hole_pos);
+               if (ret < 0) {
+                       error("copy extent failed");
+                       break;
+               }
+
+               dest_pos += (hole_pos - data_pos);
+               seek_start = hole_pos;
+       } while (seek_start < src_total_size);
+
+       if (dest_pos < src_total_size) {
+               ret = ftruncate(dest_fd, src_total_size);
+               if (ret < 0) {
+                       error("truncate dest file to %lld bytes failed as %s",
+                             (long long)src_total_size, strerror(errno));
+               }
+       }
+
+       return ret;
+}
+
+int
+main(int argc, char **argv)
+{
+       int ret = 0;
+       int src_fd;
+       int dest_fd;
+       struct stat st;
+       size_t src_total_size;
+
+       if (argc != 3) {
+               fprintf(stdout, "Usage: %s source dest\n", argv[0]);
+               return 1;
+       }
+
+       src_fd = open(argv[1], O_RDONLY, 0644);
+       if (src_fd < 0) {
+               error("create %s failed", argv[1]);
+               return -1;
+       }
+
+       dest_fd = open(argv[2], O_RDWR|O_CREAT|O_EXCL, 0644);
+       if (dest_fd < 0) {
+               error("create %s failed", argv[2]);
+               ret = -errno;
+               goto close_src_fd;
+       }
+
+       ret = fstat(src_fd, &st);
+       if (ret < 0) {
+               error("get file %s staticis failed", argv[1]);
+               ret = -errno;
+               goto close_dest_fd;
+       }
+
+       src_total_size = st.st_size;
+       ret = copy_extents(src_fd, dest_fd, src_total_size);
+       if (ret < 0)
+               error("extents copy failed");
+
+close_dest_fd:
+       close(dest_fd);
+close_src_fd:
+       close(src_fd);
+
+       return ret;
+}
diff --git a/src/seek_sanity_test.c b/src/seek_sanity_test.c
new file mode 100644 (file)
index 0000000..a185e54
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * Copyright (C) 2011 Oracle.  All rights reserved.
+ * Copyright (C) 2011 Red Hat.  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 v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will 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 to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#define _XOPEN_SOURCE 500
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#ifndef SEEK_DATA
+#define SEEK_DATA      3
+#define SEEK_HOLE      4
+#endif
+
+static blksize_t alloc_size;
+int default_behavior = 0;
+char *base_file_path;
+
+static void get_file_system(int fd)
+{
+       struct statfs buf;
+
+       if (!fstatfs(fd, &buf))
+               fprintf(stdout, "File system magic#: 0x%lx\n", buf.f_type);
+}
+
+static int get_io_sizes(int fd)
+{
+       struct stat buf;
+       int ret;
+
+       ret = fstat(fd, &buf);
+       if (ret)
+               fprintf(stderr, "  ERROR %d: Failed to find io blocksize\n",
+                       errno);
+
+       /* st_blksize is typically also the allocation size */
+       alloc_size = buf.st_blksize;
+       fprintf(stdout, "Allocation size: %ld\n", alloc_size);
+
+       return ret;
+}
+
+#define do_free(x)     do { if(x) free(x); } while(0);
+
+static void *do_malloc(size_t size)
+{
+       void *buf;
+
+       buf = malloc(size);
+       if (!buf)
+               fprintf(stderr, "  ERROR: Unable to allocate %ld bytes\n",
+                       (long)size);
+
+       return buf;
+}
+
+static int do_truncate(int fd, off_t length)
+{
+       int ret;
+
+       ret = ftruncate(fd, length);
+       if (ret)
+               fprintf(stderr, "  ERROR %d: Failed to extend file "
+                       "to %ld bytes\n", errno, (long)length);
+       return ret;
+}
+
+static int do_fallocate(int fd, off_t offset, off_t length, int mode)
+{
+       int ret;
+
+       ret = fallocate(fd, mode, offset, length);
+       if (ret)
+               fprintf(stderr, "  ERROR %d: Failed to preallocate "
+                       "space to %ld bytes\n", errno, (long) length);
+
+       return ret;
+}
+
+/*
+ * Synchnorize all dirty pages in the file range starting from
+ * offset to nbytes length.
+ */
+static int do_sync_dirty_pages(int fd, off64_t offset, off64_t nbytes)
+{
+       int ret;
+
+       ret = sync_file_range(fd, offset, nbytes, SYNC_FILE_RANGE_WRITE);
+       if (ret)
+               fprintf(stderr, "  ERROR %d: Failed to sync out dirty "
+                       "pages\n", errno);
+
+       return ret;
+}
+
+static ssize_t do_pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+       ssize_t ret, written = 0;
+
+       while (count > written) {
+               ret = pwrite(fd, buf + written, count - written, offset + written);
+               if (ret < 0) {
+                       fprintf(stderr, "  ERROR %d: Failed to write %ld "
+                               "bytes\n", errno, (long)count);
+                       return ret;
+               }
+               written += ret;
+       }
+
+       return 0;
+}
+
+#define do_close(x)    do { if ((x) > -1) close(x); } while(0);
+
+static int do_create(const char *filename)
+{
+       int fd;
+
+       fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0644);
+       if (fd < 0)
+               fprintf(stderr, " ERROR %d: Failed to create file '%s'\n",
+                       errno, filename);
+
+       return fd;
+}
+
+static int do_lseek(int testnum, int subtest, int fd, int filsz, int origin,
+                   off_t set, off_t exp)
+{
+       off_t pos, exp2;
+       int x, ret;
+
+       assert(!(origin != SEEK_HOLE && origin != SEEK_DATA));
+
+       /*
+        * The file pointer can be set to different values depending
+        * on the implementation. For SEEK_HOLE, EOF could be a valid
+        * value. For SEEK_DATA, supplied offset could be the valid
+        * value.
+        */
+       exp2 = exp;
+       if (origin == SEEK_HOLE && exp2 != -1)
+               exp2 = filsz;
+       if (origin == SEEK_DATA && default_behavior && set < filsz)
+               exp2 = set;
+
+       pos = lseek(fd, set, origin);
+
+       if (pos == -1 && exp == -1) {
+               x = fprintf(stdout, "%02d.%02d %s expected -1 with errno %d, got %d. ",
+                           testnum, subtest,
+                           (origin == SEEK_HOLE) ? "SEEK_HOLE" : "SEEK_DATA",
+                           -ENXIO, -errno);
+               ret = !(errno == ENXIO);
+       } else {
+
+               x = fprintf(stdout, "%02d.%02d %s expected %ld or %ld, got %ld. ",
+                           testnum, subtest,
+                           (origin == SEEK_HOLE) ? "SEEK_HOLE" : "SEEK_DATA",
+                           (long)exp, (long)exp2, (long)pos);
+               ret = !(pos == exp || pos == exp2);
+       }
+
+       fprintf(stdout, "%*s\n", (70 - x), ret ? "FAIL" : "succ");
+
+       return ret;
+}
+
+/*
+ * test file with unwritten extents, have both dirty and
+ * writeback pages in page cache.
+ */
+static int test09(int fd, int testnum)
+{
+       int ret = 0;
+       char *buf = NULL;
+       int bufsz = alloc_size;
+       int filsz = 8 << 20;
+
+       /*
+        * HOLE - unwritten DATA in dirty page - HOLE -
+        * unwritten DATA in writeback page
+        */
+
+       /* Each unit is bufsz */
+       buf = do_malloc(bufsz);
+       if (!buf)
+               goto out;
+       memset(buf, 'a', bufsz);
+
+       /* preallocate 8M space to file */
+       ret = do_fallocate(fd, 0, filsz, 0);
+       if (ret < 0)
+               goto out;
+
+       ret = do_pwrite(fd, buf, bufsz, bufsz * 10);
+       if (!ret) {
+               ret = do_pwrite(fd, buf, bufsz, bufsz * 100);
+               if (ret)
+                       goto out;
+       }
+
+       /*
+        * Sync out dirty pages from bufsz * 100, this will convert
+        * the dirty page to writeback.
+        */
+       ret = do_sync_dirty_pages(fd, bufsz * 100, 0);
+       if (ret)
+               goto out;
+
+       /* offset at the beginning */
+       ret += do_lseek(testnum,  1, fd, filsz, SEEK_HOLE, 0, 0);
+       ret += do_lseek(testnum,  2, fd, filsz, SEEK_HOLE, 1, 1);
+       ret += do_lseek(testnum,  3, fd, filsz, SEEK_DATA, 0, bufsz * 10);
+       ret += do_lseek(testnum,  4, fd, filsz, SEEK_DATA, 1, bufsz * 10);
+
+out:
+       do_free(buf);
+       return ret;
+}
+
+/* test file with unwritten extent, only have writeback page */
+static int test08(int fd, int testnum)
+{
+       int ret = 0;
+       char *buf = NULL;
+       int bufsz = alloc_size;
+       int filsz = 4 << 20;
+
+       /* HOLE - unwritten DATA in writeback page */
+       /* Each unit is bufsz */
+       buf = do_malloc(bufsz);
+       if (!buf)
+               goto out;
+       memset(buf, 'a', bufsz);
+
+       /* preallocate 4M space to file */
+       ret = do_fallocate(fd, 0, filsz, 0);
+       if (ret < 0)
+               goto out;
+
+       ret = do_pwrite(fd, buf, bufsz, bufsz * 10);
+       if (ret)
+               goto out;
+
+       /* Sync out all file */
+       ret = do_sync_dirty_pages(fd, 0, 0);
+       if (ret)
+               goto out;
+
+       /* offset at the beginning */
+       ret += do_lseek(testnum,  1, fd, filsz, SEEK_HOLE, 0, 0);
+       ret += do_lseek(testnum,  2, fd, filsz, SEEK_HOLE, 1, 1);
+       ret += do_lseek(testnum,  3, fd, filsz, SEEK_DATA, 0, bufsz * 10);
+       ret += do_lseek(testnum,  4, fd, filsz, SEEK_DATA, 1, bufsz * 10);
+
+out:
+       do_free(buf);
+       return ret;
+}
+
+/*
+ * test file with unwritten extents, only have dirty pages
+ * in page cache.
+ */
+static int test07(int fd, int testnum)
+{
+       int ret = 0;
+       char *buf = NULL;
+       int bufsz = alloc_size;
+       int filsz = 4 << 20;
+
+       /* HOLE - unwritten DATA in dirty page */
+       /* Each unit is bufsz */
+       buf = do_malloc(bufsz);
+       if (!buf)
+               goto out;
+       memset(buf, 'a', bufsz);
+
+       /* preallocate 4M space to file */
+       ret = do_fallocate(fd, 0, filsz, 0);
+       if (ret < 0)
+               goto out;
+
+       ret = do_pwrite(fd, buf, bufsz, bufsz * 10);
+       if (ret)
+               goto out;
+
+       /* offset at the beginning */
+       ret += do_lseek(testnum,  1, fd, filsz, SEEK_HOLE, 0, 0);
+       ret += do_lseek(testnum,  2, fd, filsz, SEEK_HOLE, 1, 1);
+       ret += do_lseek(testnum,  3, fd, filsz, SEEK_DATA, 0, bufsz * 10);
+       ret += do_lseek(testnum,  4, fd, filsz, SEEK_DATA, 1, bufsz * 10);
+
+out:
+       do_free(buf);
+       return ret;
+}
+
+/* test hole data hole data */
+static int test06(int fd, int testnum)
+{
+       int ret = -1;
+       char *buf = NULL;
+       int bufsz = alloc_size;
+       int filsz = bufsz * 4;
+       int off;
+
+       /* HOLE - DATA - HOLE - DATA */
+       /* Each unit is bufsz */
+
+       buf = do_malloc(bufsz);
+       if (!buf)
+               goto out;
+
+       memset(buf, 'a', bufsz);
+
+       ret = do_pwrite(fd, buf, bufsz, bufsz);
+       if (!ret)
+               do_pwrite(fd, buf, bufsz, bufsz * 3);
+       if (ret)
+               goto out;
+
+       /* offset at the beginning */
+       ret += do_lseek(testnum,  1, fd, filsz, SEEK_HOLE, 0, 0);
+       ret += do_lseek(testnum,  2, fd, filsz, SEEK_HOLE, 1, 1);
+       ret += do_lseek(testnum,  3, fd, filsz, SEEK_DATA, 0, bufsz);
+       ret += do_lseek(testnum,  4, fd, filsz, SEEK_DATA, 1, bufsz);
+
+       /* offset around first hole-data boundary */
+       off = bufsz;
+       ret += do_lseek(testnum,  5, fd, filsz, SEEK_HOLE, off - 1, off - 1);
+       ret += do_lseek(testnum,  6, fd, filsz, SEEK_DATA, off - 1, off);
+       ret += do_lseek(testnum,  7, fd, filsz, SEEK_HOLE, off,     bufsz * 2);
+       ret += do_lseek(testnum,  8, fd, filsz, SEEK_DATA, off,     off);
+       ret += do_lseek(testnum,  9, fd, filsz, SEEK_HOLE, off + 1, bufsz * 2);
+       ret += do_lseek(testnum, 10, fd, filsz, SEEK_DATA, off + 1, off + 1);
+
+       /* offset around data-hole boundary */
+       off = bufsz * 2;
+       ret += do_lseek(testnum, 11, fd, filsz, SEEK_HOLE, off - 1, off);
+       ret += do_lseek(testnum, 12, fd, filsz, SEEK_DATA, off - 1, off - 1);
+       ret += do_lseek(testnum, 13, fd, filsz, SEEK_HOLE, off,     off);
+       ret += do_lseek(testnum, 14, fd, filsz, SEEK_DATA, off,     bufsz * 3);
+       ret += do_lseek(testnum, 15, fd, filsz, SEEK_HOLE, off + 1, off + 1);
+       ret += do_lseek(testnum, 16, fd, filsz, SEEK_DATA, off + 1, bufsz * 3);
+
+       /* offset around second hole-data boundary */
+       off = bufsz * 3;
+       ret += do_lseek(testnum, 17, fd, filsz, SEEK_HOLE, off - 1, off - 1);
+       ret += do_lseek(testnum, 18, fd, filsz, SEEK_DATA, off - 1, off);
+       ret += do_lseek(testnum, 19, fd, filsz, SEEK_HOLE, off,     filsz);
+       ret += do_lseek(testnum, 20, fd, filsz, SEEK_DATA, off,     off);
+       ret += do_lseek(testnum, 21, fd, filsz, SEEK_HOLE, off + 1, filsz);
+       ret += do_lseek(testnum, 22, fd, filsz, SEEK_DATA, off + 1, off + 1);
+
+       /* offset around the end of file */
+       off = filsz;
+       ret += do_lseek(testnum, 23, fd, filsz, SEEK_HOLE, off - 1, filsz);
+       ret += do_lseek(testnum, 24, fd, filsz, SEEK_DATA, off - 1, filsz - 1);
+       ret += do_lseek(testnum, 25, fd, filsz, SEEK_HOLE, off, -1);
+       ret += do_lseek(testnum, 26, fd, filsz, SEEK_DATA, off, -1);
+       ret += do_lseek(testnum, 27, fd, filsz, SEEK_HOLE, off + 1, -1);
+       ret += do_lseek(testnum, 28, fd, filsz, SEEK_DATA, off + 1, -1);
+
+out:
+       do_free(buf);
+       return ret;
+}
+
+/* test file with data at the beginning and a hole at the end */
+static int test05(int fd, int testnum)
+{
+       int ret = -1;
+       char *buf = NULL;
+       int bufsz = alloc_size;
+       int filsz = bufsz * 4;
+
+       /* |- DATA -|- HOLE -|- HOLE -|- HOLE -| */
+
+       buf = do_malloc(bufsz);
+       if (!buf)
+               goto out;
+       memset(buf, 'a', bufsz);
+
+       ret = do_truncate(fd, filsz);
+       if (!ret)
+               ret = do_pwrite(fd, buf, bufsz, 0);
+       if (ret)
+               goto out;
+
+       /* offset at the beginning */
+
+       ret += do_lseek(testnum,  1, fd, filsz, SEEK_HOLE, 0, bufsz);
+       ret += do_lseek(testnum,  2, fd, filsz, SEEK_HOLE, 1, bufsz);
+
+       ret += do_lseek(testnum,  3, fd, filsz, SEEK_DATA, 0, 0);
+       ret += do_lseek(testnum,  4, fd, filsz, SEEK_DATA, 1, 1);
+
+       /* offset around data-hole boundary */
+       ret += do_lseek(testnum,  5, fd, filsz, SEEK_HOLE, bufsz - 1, bufsz);
+       ret += do_lseek(testnum,  6, fd, filsz, SEEK_DATA, bufsz - 1, bufsz - 1);
+
+       ret += do_lseek(testnum,  7, fd, filsz, SEEK_HOLE, bufsz,     bufsz);
+       ret += do_lseek(testnum,  8, fd, filsz, SEEK_DATA, bufsz,     -1);
+       ret += do_lseek(testnum,  9, fd, filsz, SEEK_HOLE, bufsz + 1, bufsz + 1);
+       ret += do_lseek(testnum, 10, fd, filsz, SEEK_DATA, bufsz + 1, -1);
+
+       /* offset around eof */
+       ret += do_lseek(testnum, 11, fd, filsz, SEEK_HOLE, filsz - 1, filsz - 1);
+       ret += do_lseek(testnum, 12, fd, filsz, SEEK_DATA, filsz - 1, -1);
+       ret += do_lseek(testnum, 13, fd, filsz, SEEK_HOLE, filsz,     -1);
+       ret += do_lseek(testnum, 14, fd, filsz, SEEK_DATA, filsz,     -1);
+       ret += do_lseek(testnum, 15, fd, filsz, SEEK_HOLE, filsz + 1, -1);
+       ret += do_lseek(testnum, 16, fd, filsz, SEEK_DATA, filsz + 1, -1);
+out:
+       do_free(buf);
+       return ret;
+}
+/* test hole begin and data end */
+static int test04(int fd, int testnum)
+{
+       int ret;
+       char *buf = "ABCDEFGH";
+       int bufsz, holsz, filsz;
+
+       bufsz = strlen(buf);
+       holsz = alloc_size * 2;
+       filsz = holsz + bufsz;
+
+       /* |- HOLE -|- HOLE -|- DATA -| */
+
+       ret = do_pwrite(fd, buf, bufsz, holsz);
+       if (ret)
+               goto out;
+
+       /* offset at the beginning */
+       ret += do_lseek(testnum,  1, fd, filsz, SEEK_HOLE, 0, 0);
+       ret += do_lseek(testnum,  2, fd, filsz, SEEK_HOLE, 1, 1);
+       ret += do_lseek(testnum,  3, fd, filsz, SEEK_DATA, 0, holsz);
+       ret += do_lseek(testnum,  4, fd, filsz, SEEK_DATA, 1, holsz);
+       /* offset around hole-data boundary */
+       ret += do_lseek(testnum,  5, fd, filsz, SEEK_HOLE, holsz - 1, holsz - 1);
+       ret += do_lseek(testnum,  6, fd, filsz, SEEK_DATA, holsz - 1, holsz);
+       ret += do_lseek(testnum,  7, fd, filsz, SEEK_HOLE, holsz,     filsz);
+       ret += do_lseek(testnum,  8, fd, filsz, SEEK_DATA, holsz,     holsz);
+       ret += do_lseek(testnum,  9, fd, filsz, SEEK_HOLE, holsz + 1, filsz);
+       ret += do_lseek(testnum, 10, fd, filsz, SEEK_DATA, holsz + 1, holsz + 1);
+
+       /* offset around eof */
+       ret += do_lseek(testnum, 11, fd, filsz, SEEK_HOLE, filsz - 1, filsz);
+       ret += do_lseek(testnum, 12, fd, filsz, SEEK_DATA, filsz - 1, filsz - 1);
+       ret += do_lseek(testnum, 13, fd, filsz, SEEK_HOLE, filsz,     -1);
+       ret += do_lseek(testnum, 14, fd, filsz, SEEK_DATA, filsz,     -1);
+       ret += do_lseek(testnum, 15, fd, filsz, SEEK_HOLE, filsz + 1, -1);
+       ret += do_lseek(testnum, 16, fd, filsz, SEEK_DATA, filsz + 1, -1);
+out:
+       return ret;
+}
+
+/* test a larger full file */
+static int test03(int fd, int testnum)
+{
+       char *buf = NULL;
+       int bufsz = alloc_size * 2 + 100;
+       int filsz = bufsz;
+       int ret = -1;
+
+       buf = do_malloc(bufsz);
+       if (!buf)
+               goto out;
+       memset(buf, 'a', bufsz);
+
+       ret = do_pwrite(fd, buf, bufsz, 0);
+       if (ret)
+               goto out;
+
+       /* offset at the beginning */
+       ret += do_lseek(testnum,  1, fd, filsz, SEEK_HOLE, 0, bufsz);
+       ret += do_lseek(testnum,  2, fd, filsz, SEEK_HOLE, 1, bufsz);
+       ret += do_lseek(testnum,  3, fd, filsz, SEEK_DATA, 0, 0);
+       ret += do_lseek(testnum,  4, fd, filsz, SEEK_DATA, 1, 1);
+
+       /* offset around eof */
+       ret += do_lseek(testnum,  5, fd, filsz, SEEK_HOLE, bufsz - 1, bufsz);
+       ret += do_lseek(testnum,  6, fd, filsz, SEEK_DATA, bufsz - 1, bufsz - 1);
+       ret += do_lseek(testnum,  7, fd, filsz, SEEK_HOLE, bufsz,     -1);
+       ret += do_lseek(testnum,  8, fd, filsz, SEEK_DATA, bufsz,     -1);
+       ret += do_lseek(testnum,  9, fd, filsz, SEEK_HOLE, bufsz + 1, -1);
+       ret += do_lseek(testnum, 10, fd, filsz, SEEK_DATA, bufsz + 1, -1);
+
+out:
+       do_free(buf);
+       return ret;
+}
+
+/* test tiny full file */
+static int test02(int fd, int testnum)
+{
+       int ret;
+       char buf[] = "ABCDEFGH";
+       int bufsz, filsz;
+
+       bufsz = strlen(buf);
+       filsz = bufsz;
+
+       /* |- DATA -| */
+
+       ret = do_pwrite(fd, buf, bufsz, 0);
+       if (ret)
+               goto out;
+
+       ret += do_lseek(testnum, 1, fd, filsz, SEEK_HOLE, 0, filsz);
+       ret += do_lseek(testnum, 2, fd, filsz, SEEK_DATA, 0, 0);
+       ret += do_lseek(testnum, 3, fd, filsz, SEEK_DATA, 1, 1);
+       ret += do_lseek(testnum, 4, fd, filsz, SEEK_HOLE, bufsz - 1, filsz);
+       ret += do_lseek(testnum, 5, fd, filsz, SEEK_DATA, bufsz - 1, bufsz - 1);
+       ret += do_lseek(testnum, 6, fd, filsz, SEEK_HOLE, bufsz,     -1);
+       ret += do_lseek(testnum, 7, fd, filsz, SEEK_DATA, bufsz,     -1);
+       ret += do_lseek(testnum, 8, fd, filsz, SEEK_HOLE, bufsz + 1, -1);
+       ret += do_lseek(testnum, 9, fd, filsz, SEEK_DATA, bufsz + 1, -1);
+
+out:
+       return ret;
+}
+
+/* test empty file */
+static int test01(int fd, int testnum)
+{
+       int ret = 0;
+
+       ret += do_lseek(testnum, 1, fd, 0, SEEK_DATA, 0, -1);
+       ret += do_lseek(testnum, 2, fd, 0, SEEK_HOLE, 0, -1);
+       ret += do_lseek(testnum, 3, fd, 0, SEEK_HOLE, 1, -1);
+
+       return ret;
+}
+
+struct testrec {
+       int     test_num;
+       int     (*test_func)(int fd, int testnum);
+       char    *test_desc;
+};
+
+struct testrec seek_tests[] = {
+       {  1, test01, "Test empty file" },
+       {  2, test02, "Test a tiny full file" },
+       {  3, test03, "Test a larger full file" },
+       {  4, test04, "Test file hole at beg, data at end" },
+       {  5, test05, "Test file data at beg, hole at end" },
+       {  6, test06, "Test file hole data hole data" },
+       {  7, test07, "Test file with unwritten extents, only have dirty pages" },
+       {  8, test08, "Test file with unwritten extents, only have unwritten pages" },
+       {  9, test09, "Test file with unwritten extents, have both dirty && unwritten pages" },
+};
+
+static int run_test(struct testrec *tr)
+{
+       int ret = 0, fd = -1;
+       char filename[255];
+
+       snprintf(filename, sizeof(filename), "%s%02d", base_file_path, tr->test_num);
+
+       fd = do_create(filename);
+       if (fd > -1) {
+               printf("%02d. %-50s\n", tr->test_num, tr->test_desc);
+               ret = tr->test_func(fd, tr->test_num);
+               printf("\n");
+       }
+
+       do_close(fd);
+       return ret;
+}
+
+static int test_basic_support(void)
+{
+       int ret = -1, fd;
+       off_t pos;
+       char *buf = NULL;
+       int bufsz, filsz;
+
+       fd = do_create(base_file_path);
+       if (fd == -1)
+               goto out;
+
+       get_file_system(fd);
+
+       ret = get_io_sizes(fd);
+       if (ret)
+               goto out;
+
+       bufsz = alloc_size * 2;
+       filsz = bufsz * 2;
+
+       buf = do_malloc(bufsz);
+       if (!buf)
+               goto out;
+       memset(buf, 'a', bufsz);
+
+       /* File with 2 allocated blocks.... */
+       ret = do_pwrite(fd, buf, bufsz, 0);
+       if (ret)
+               goto out;
+
+       /* followed by a hole... */
+       ret = do_truncate(fd, filsz);
+       if (ret)
+               goto out;
+
+       /* Is SEEK_DATA and SEEK_HOLE supported in the kernel? */
+       pos = lseek(fd, 0, SEEK_DATA);
+       if (pos != -1)
+               pos = lseek(fd, 0, SEEK_HOLE);
+       if (pos == -1) {
+               fprintf(stderr, "Kernel does not support llseek(2) extensions "
+                       "SEEK_HOLE and/or SEEK_DATA. Aborting.\n");
+               ret = -1;
+               goto out;
+       }
+
+       if (pos == filsz) {
+               default_behavior = 1;
+               fprintf(stderr, "File system supports the default behavior.\n");
+       }
+
+       printf("\n");
+
+out:
+       do_free(buf);
+       do_close(fd);
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int ret = -1;
+       int i = 0;
+       int numtests = sizeof(seek_tests) / sizeof(struct testrec);
+
+       if (argc != 2) {
+               fprintf(stdout, "Usage: %s base_file_path\n", argv[0]);
+               return ret;
+       }
+
+       base_file_path = (char *)strdup(argv[1]);
+
+       ret = test_basic_support();
+       if (ret)
+               goto out;
+
+       for (i = 0; i < numtests; ++i) {
+               if (ret)
+                       goto out;
+               run_test(&seek_tests[i]);
+       }
+
+out:
+       free(base_file_path);
+       return ret;
+}