mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
xfstests: introduce 286 for SEEK_DATA/SEEK_HOLE copy test
Introduce 286 for SEEK_DATA/SEEK_HOLE copy tests. Signed-off-by: Jie Liu <jeff.liu@oracle.com> Reviewed-by: Rich Johnston <rjohnston@sgi.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
This commit is contained in:
@@ -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
|
||||
@@ -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 ***
|
||||
|
||||
@@ -404,3 +404,4 @@ deprecated
|
||||
283 dump ioctl auto quick
|
||||
284 auto
|
||||
285 auto rw
|
||||
286 other
|
||||
|
||||
+2
-1
@@ -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 seek_sanity_test
|
||||
stale_handle pwrite_mmap_blocked fstrim t_dir_offset2 seek_sanity_test \
|
||||
seek_copy_test
|
||||
|
||||
SUBDIRS =
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user