[v7,3/3] syscalls/copy_file_range02: increase coverage and remove EXDEV test
diff mbox series

Message ID 1564569629-2358-3-git-send-email-xuyang2018.jy@cn.fujitsu.com
State Accepted
Delegated to: Petr Vorel
Headers show
Series
  • [v7,1/3] lib: alter find_free_loopdev()
Related show

Commit Message

Yang Xu July 31, 2019, 10:40 a.m. UTC
Since Amir patch[1] for copy_file_range has been merged into upstream
kernel, we should add swapfile, immutable file, bounds tests in ltp.
Also, add block,char,pipe dev tests and remove EXDEV test(the cross-device
constraint has been relaxed since[2]). I follow xfstests code[3].

[1]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=96e6e8f4a
[2]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5dae222a5
[3]https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/tree/tests/generic/(553,554,564,565}

Signed-off-by: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>

----
v5->v6:
   1)directly use the tst_find_free_loopdev filling dev_path
   2)use TST_ABI64 instead of __WORDSIZE == 64
v6->v7:
    fix undefined PAGE_SHIFT build error
---
---
 include/lapi/fs.h                             |   9 ++
 .../copy_file_range/copy_file_range.h         |  13 +-
 .../copy_file_range/copy_file_range02.c       | 145 +++++++++++++++---
 3 files changed, 146 insertions(+), 21 deletions(-)

Comments

Petr Vorel July 31, 2019, 12:28 p.m. UTC | #1
Hi,

> Since Amir patch[1] for copy_file_range has been merged into upstream
> kernel, we should add swapfile, immutable file, bounds tests in ltp.
> Also, add block,char,pipe dev tests and remove EXDEV test(the cross-device
> constraint has been relaxed since[2]). I follow xfstests code[3].

> [1]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=96e6e8f4a
> [2]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5dae222a5
> [3]https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/tree/tests/generic/(553,554,564,565}

> Signed-off-by: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Petr Vorel <pvorel@suse.cz>

Kind regards,
Petr
Murphy Zhou Aug. 5, 2019, 6:58 a.m. UTC | #2
Hi,

On Wed, Jul 31, 2019 at 06:40:29PM +0800, Yang Xu wrote:
> Since Amir patch[1] for copy_file_range has been merged into upstream
> kernel, we should add swapfile, immutable file, bounds tests in ltp.
> Also, add block,char,pipe dev tests and remove EXDEV test(the cross-device
> constraint has been relaxed since[2]). I follow xfstests code[3].
> 
> [1]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=96e6e8f4a
> [2]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5dae222a5
> [3]https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/tree/tests/generic/(553,554,564,565}
> 
> Signed-off-by: Yang Xu <xuyang2018.jy@cn.fujitsu.com>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> 
> ----
> v5->v6:
>    1)directly use the tst_find_free_loopdev filling dev_path
>    2)use TST_ABI64 instead of __WORDSIZE == 64
> v6->v7:
>     fix undefined PAGE_SHIFT build error
> ---
> ---
>  include/lapi/fs.h                             |   9 ++
>  .../copy_file_range/copy_file_range.h         |  13 +-
>  .../copy_file_range/copy_file_range02.c       | 145 +++++++++++++++---
>  3 files changed, 146 insertions(+), 21 deletions(-)
> 
> diff --git a/include/lapi/fs.h b/include/lapi/fs.h
> index 42cb4f9b2..1af55628c 100644
> --- a/include/lapi/fs.h
> +++ b/include/lapi/fs.h
> @@ -7,6 +7,8 @@
>  #ifdef HAVE_LINUX_FS_H
>  # include <linux/fs.h>
>  #endif
> +# include <sys/user.h>
> +# include "lapi/abisize.h"
>  
>  #ifndef LAPI_FS_H
>  #define LAPI_FS_H
> @@ -35,4 +37,11 @@
>  #define FS_NODUMP_FL	   0x00000040 /* do not dump file */
>  #endif
>  
> +/* Referred form linux kernel include/linux/fs.h */
> +#ifdef TST_ABI64
> + #define MAX_LFS_FILESIZE   ((loff_t)LLONG_MAX)
> +#else
> + #define MAX_LFS_FILESIZE   ((loff_t)ULONG_MAX << PAGE_SHIFT)
> +#endif
> +
>  #endif
> diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range.h b/testcases/kernel/syscalls/copy_file_range/copy_file_range.h
> index b6d132978..c7f423e45 100644
> --- a/testcases/kernel/syscalls/copy_file_range/copy_file_range.h
> +++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range.h
> @@ -9,7 +9,10 @@
>  
>  #include <stdbool.h>
>  #include <unistd.h>
> +#include <sys/sysmacros.h>
> +#include <limits.h>
>  #include "lapi/syscalls.h"
> +#include "lapi/fs.h"
>  
>  #define TEST_VARIANTS	2
>  
> @@ -18,10 +21,18 @@
>  #define FILE_DEST_PATH  "file_dest"
>  #define FILE_RDONL_PATH "file_rdonl"
>  #define FILE_DIR_PATH	"file_dir"
> -#define FILE_MNTED_PATH	MNTPOINT"/file_mnted"
> +#define FILE_MNTED_PATH  MNTPOINT"/file_mnted"
> +#define FILE_IMMUTABLE_PATH "file_immutable"
> +#define FILE_SWAP_PATH "file_swap"
> +#define FILE_CHRDEV    "/dev/null"
> +#define FILE_FIFO      "file_fifo"
> +#define FILE_COPY_PATH  "file_copy"
>  
>  #define CONTENT		"ABCDEFGHIJKLMNOPQRSTUVWXYZ12345\n"
>  #define CONTSIZE	(sizeof(CONTENT) - 1)
> +#define MAX_LEN   MAX_LFS_FILESIZE
> +#define MIN_OFF   65537
> +#define MAX_OFF   (MAX_LEN - MIN_OFF)
>  
>  static void syscall_info(void)
>  {
> diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> index 07c0207c2..36976156e 100644
> --- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> +++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> @@ -10,15 +10,25 @@
>   *
>   * 1) Try to copy contents to file open as readonly
>   *    -> EBADF
> - * 2) Try to copy contents to file on different mounted
> - *    filesystem -> EXDEV
> - * 3) Try to copy contents to directory -> EISDIR
> - * 4) Try to copy contents to a file opened with the
> + * 2) Try to copy contents to directory -> EISDIR
> + * 3) Try to copy contents to a file opened with the
>   *    O_APPEND flag -> EBADF
> - * 5) Try to copy contents to closed filedescriptor
> + * 4) Try to copy contents to closed filedescriptor
>   *    -> EBADF
> - * 6) Try to copy contents with invalid 'flags' value
> + * 5) Try to copy contents with invalid 'flags' value
>   *    -> EINVAL
> + * 6) Try to copy contents to a file chattred with +i
> + *    flag -> EPERM
> + * 7) Try to copy contents to a swapfile ->ETXTBSY
> + * 8) Try to copy contents to the samefile with overlapping
> + *    ->EINVAL
> + * 9) Try to copy contents to a blkdev ->EINVAL
> + * 10) Try to copy contents to a chardev ->EINVAL
> + * 11) Try to copy contents to a FIFO ->EINVAL
> + * 12) Try to copy contents to a file with length beyond
> + *     16EiB wraps around 0 -> EOVERFLOW
> + * 13) Try to copy contents to a file with target file range
> + *     beyond maximum supported file size ->EFBIG

Test 13) fails on latest Linus tree. Is there any report or working on this?

Thanks!
M

>   */
>  
>  #define _GNU_SOURCE
> @@ -29,30 +39,78 @@
>  static int fd_src;
>  static int fd_dest;
>  static int fd_rdonly;
> -static int fd_mnted;
>  static int fd_dir;
>  static int fd_closed;
>  static int fd_append;
> +static int fd_immutable;
> +static int fd_swapfile;
> +static int fd_dup;
> +static int fd_blkdev;
> +static int fd_chrdev;
> +static int fd_fifo;
> +static int fd_copy;
> +
> +static int chattr_i_nsup;
> +static int swap_nsup;
> +static int loop_devn;
>  
>  static struct tcase {
>  	int	*copy_to_fd;
>  	int	flags;
>  	int	exp_err;
> +	loff_t  dst;
> +	loff_t     len;
>  } tcases[] = {
> -	{&fd_rdonly,	0,	EBADF},
> -	{&fd_mnted,	0,	EXDEV},
> -	{&fd_dir,	0,	EISDIR},
> -	{&fd_append,	0,	EBADF},
> -	{&fd_closed,	0,	EBADF},
> -	{&fd_dest,	-1,	EINVAL},
> +	{&fd_rdonly,	0,   EBADF,      0,     CONTSIZE},
> +	{&fd_dir,	0,   EISDIR,     0,     CONTSIZE},
> +	{&fd_append,	0,   EBADF,      0,     CONTSIZE},
> +	{&fd_closed,	0,   EBADF,      0,     CONTSIZE},
> +	{&fd_dest,	-1,  EINVAL,     0,     CONTSIZE},
> +	{&fd_immutable, 0,   EPERM,      0,     CONTSIZE},
> +	{&fd_swapfile,  0,   ETXTBSY,    0,     CONTSIZE},
> +	{&fd_dup,       0,   EINVAL,     0,     CONTSIZE/2},
> +	{&fd_blkdev,    0,   EINVAL,     0,     CONTSIZE},
> +	{&fd_chrdev,    0,   EINVAL,     0,     CONTSIZE},
> +	{&fd_fifo,      0,   EINVAL,     0,     CONTSIZE},
> +	{&fd_copy,      0,   EOVERFLOW,  MAX_OFF, ULLONG_MAX},
> +	{&fd_copy,      0,   EFBIG,      MAX_OFF, MIN_OFF},
>  };
>  
> +static int run_command(char *command, char *option, char *file)
> +{
> +	const char *const cmd[] = {command, option, file, NULL};
> +	int ret;
> +
> +	ret = tst_run_cmd(cmd, NULL, NULL, 1);
> +	switch (ret) {
> +	case 0:
> +	return 0;
> +	case 255:
> +		tst_res(TCONF, "%s binary not installed", command);
> +	return 1;
> +	default:
> +		tst_res(TCONF, "%s exited with %i", command, ret);
> +	return 2;
> +	}
> +}
> +
>  static void verify_copy_file_range(unsigned int n)
>  {
>  	struct tcase *tc = &tcases[n];
> -
> +	if (tc->copy_to_fd == &fd_immutable && chattr_i_nsup) {
> +		tst_res(TCONF, "filesystem doesn't support chattr +i, skip it");
> +		return;
> +	}
> +	if (tc->copy_to_fd == &fd_swapfile && swap_nsup) {
> +		tst_res(TCONF, "filesystem doesn't support swapfile, skip it");
> +		return;
> +	}
> +	if (tc->copy_to_fd == &fd_blkdev && loop_devn == -1) {
> +		tst_res(TCONF, "filesystem doesn't have free loopdev, skip it");
> +		return;
> +	}
>  	TEST(sys_copy_file_range(fd_src, 0, *tc->copy_to_fd,
> -				0, CONTSIZE, tc->flags));
> +				&tc->dst, tc->len, tc->flags));
>  
>  	if (TST_RET == -1) {
>  		if (tc->exp_err == TST_ERR) {
> @@ -76,33 +134,80 @@ static void cleanup(void)
>  		SAFE_CLOSE(fd_append);
>  	if (fd_dir > 0)
>  		SAFE_CLOSE(fd_dir);
> -	if (fd_mnted > 0)
> -		SAFE_CLOSE(fd_mnted);
>  	if (fd_rdonly > 0)
>  		SAFE_CLOSE(fd_rdonly);
>  	if (fd_dest > 0)
>  		SAFE_CLOSE(fd_dest);
>  	if (fd_src > 0)
>  		SAFE_CLOSE(fd_src);
> +	if (fd_immutable > 0) {
> +		run_command("chattr", "-i", FILE_IMMUTABLE_PATH);
> +		SAFE_CLOSE(fd_immutable);
> +	}
> +	if (fd_swapfile > 0) {
> +		run_command("swapoff", FILE_SWAP_PATH, NULL);
> +		SAFE_CLOSE(fd_swapfile);
> +	}
> +	if (fd_dup > 0)
> +		SAFE_CLOSE(fd_dup);
> +	if (fd_copy > 0)
> +		SAFE_CLOSE(fd_copy);
> +	SAFE_UNLINK(FILE_FIFO);
>  }
>  
>  static void setup(void)
>  {
>  	syscall_info();
> +	char dev_path[1024];
>  
>  	if (access(FILE_DIR_PATH, F_OK) == -1)
>  		SAFE_MKDIR(FILE_DIR_PATH, 0777);
> +	/*
> +	 * call tst_find_free_loopdev(), avoid overwriting its
> +	 * content on used loopdev.
> +	 */
> +	loop_devn = tst_find_free_loopdev(dev_path, sizeof(dev_path));
> +
> +	SAFE_MKNOD(FILE_FIFO, S_IFIFO | 0777, 0);
>  
>  	fd_src    = SAFE_OPEN(FILE_SRC_PATH, O_RDWR | O_CREAT, 0664);
>  	fd_dest   = SAFE_OPEN(FILE_DEST_PATH, O_RDWR | O_CREAT, 0664);
>  	fd_rdonly = SAFE_OPEN(FILE_RDONL_PATH, O_RDONLY | O_CREAT, 0664);
> -	fd_mnted  = SAFE_OPEN(FILE_MNTED_PATH, O_RDWR | O_CREAT, 0664);
>  	fd_dir    = SAFE_OPEN(FILE_DIR_PATH, O_DIRECTORY);
>  	fd_closed = -1;
>  	fd_append = SAFE_OPEN(FILE_DEST_PATH,
>  			O_RDWR | O_CREAT | O_APPEND, 0664);
> +	fd_immutable = SAFE_OPEN(FILE_IMMUTABLE_PATH, O_RDWR | O_CREAT, 0664);
> +	fd_swapfile = SAFE_OPEN(FILE_SWAP_PATH, O_RDWR | O_CREAT, 0600);
> +
> +	if (loop_devn == -1)
> +		fd_blkdev = SAFE_OPEN(dev_path, O_RDWR, 0600);
> +
> +	fd_chrdev = SAFE_OPEN(FILE_CHRDEV, O_RDWR, 0600);
> +	fd_fifo = SAFE_OPEN(FILE_FIFO, O_RDWR, 0600);
> +
> +	SAFE_WRITE(1, fd_src, CONTENT, CONTSIZE);
> +	close(fd_src);
> +	fd_src = SAFE_OPEN(FILE_SRC_PATH, O_RDONLY, 0664);
> +	fd_dup = SAFE_OPEN(FILE_SRC_PATH, O_WRONLY|O_CREAT, 0666);
> +
> +	fd_copy = SAFE_OPEN(FILE_COPY_PATH, O_RDWR | O_CREAT | O_TRUNC, 0664);
> +	chattr_i_nsup = run_command("chattr", "+i", FILE_IMMUTABLE_PATH);
> +
> +	if (!tst_fs_has_free(".", sysconf(_SC_PAGESIZE) * 10, TST_BYTES)) {
> +		tst_res(TCONF, "Insufficient disk space to create swap file");
> +		swap_nsup = 3;
> +		return;
> +	}
> +
> +	if (tst_fill_file(FILE_SWAP_PATH, 0, sysconf(_SC_PAGESIZE), 10) != 0) {
> +		tst_res(TCONF, "Failed to create swapfile");
> +		swap_nsup = 4;
> +		return;
> +	}
>  
> -	SAFE_WRITE(1, fd_src,  CONTENT,  CONTSIZE);
> +	swap_nsup = run_command("mkswap", FILE_SWAP_PATH, NULL);
> +	swap_nsup = run_command("swapon", FILE_SWAP_PATH, NULL);
>  }
>  
>  static struct tst_test test = {
> @@ -113,6 +218,6 @@ static struct tst_test test = {
>  	.needs_root = 1,
>  	.mount_device = 1,
>  	.mntpoint = MNTPOINT,
> -	.dev_fs_type = "ext4",
> +	.all_filesystems = 1,
>  	.test_variants = TEST_VARIANTS,
>  };
> -- 
> 2.18.1
> 
> 
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp
Yang Xu Aug. 5, 2019, 7:11 a.m. UTC | #3
on 2019/08/05 14:58, Murphy Zhou  wrote:

>> + * 13) Try to copy contents to a file with target file range
>> >  + *     beyond maximum supported file size ->EFBIG
> Test 13) fails on latest Linus tree. Is there any report or working on this?
Hi Murphy

    Test 13)  passed on my system(64bit, 5.2.0+, ext4,vfat,btrfs,xfs ).
    Do you provide more infomation(filesystem, 32bit or 64bit)?

Thanks
Yang Xu

> Thanks!
> M
>
Murphy Zhou Aug. 5, 2019, 10:22 a.m. UTC | #4
On Mon, Aug 05, 2019 at 03:11:53PM +0800, Yang Xu wrote:
> on 2019/08/05 14:58, Murphy Zhou  wrote:
> 
> > > + * 13) Try to copy contents to a file with target file range
> > > >  + *     beyond maximum supported file size ->EFBIG
> > Test 13) fails on latest Linus tree. Is there any report or working on this?
> Hi Murphy
> 
>    Test 13)  passed on my system(64bit, 5.2.0+, ext4,vfat,btrfs,xfs ).
>    Do you provide more infomation(filesystem, 32bit or 64bit)?

All of them, ext234 xfs and vfat. 64bit

copy_file_range02.c:127: FAIL: copy_file_range returned wrong value: 32

[root@8u ltp (master)]# gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/8/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --disable-libmpx --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 8.3.1 20190507 (Red Hat 8.3.1-4) (GCC) 
[root@8u ltp (master)]# rpm -qv glibc
glibc-2.28-72.el8.x86_64
[root@8u ltp (master)]# mke2fs -V
mke2fs 1.44.6 (5-Mar-2019)
	Using EXT2FS Library version 1.44.6
[root@8u ltp (master)]# mkfs.xfs -V
mkfs.xfs version 5.2.0-rc0
[root@8u ltp (master)]# 

Looks like the copy succeeded at that offset.

Thanks,
M

> 
> Thanks
> Yang Xu
> 
> > Thanks!
> > M
> > 
> 
> 
>
Yang Xu Aug. 5, 2019, 11:01 a.m. UTC | #5
on 2019/08/05 18:22, Murphy Zhou  wrote:

> All of them, ext234 xfs and vfat. 64bit
>
> copy_file_range02.c:127: FAIL: copy_file_range returned wrong value: 32
>
> [root@8u ltp (master)]# gcc -v
> Using built-in specs.
> COLLECT_GCC=gcc
> COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/8/lto-wrapper
> OFFLOAD_TARGET_NAMES=nvptx-none
> OFFLOAD_TARGET_DEFAULT=1
> Target: x86_64-redhat-linux
> Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla  --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --disable-libmpx --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
> Thread model: posix
> gcc version 8.3.1 20190507 (Red Hat 8.3.1-4) (GCC)
> [root@8u ltp (master)]# rpm -qv glibc
> glibc-2.28-72.el8.x86_64
> [root@8u ltp (master)]# mke2fs -V
> mke2fs 1.44.6 (5-Mar-2019)
> 	Using EXT2FS Library version 1.44.6
> [root@8u ltp (master)]# mkfs.xfs -V
> mkfs.xfs version 5.2.0-rc0
> [root@8u ltp (master)]#
>
> Looks like the copy succeeded at that offset.
Hi Murphy
Today, I use theLinux 5.3-rc3 ,  ext234 xfs and vfat 64bit all pass. This case use glibc and tst_syscall, they all failed?

my environment as below:
# gcc -v
gcc version 8.2.1 20180905 (8.2.1-3) (GCC)

#glibc -v
glibc-2.28-18.el8.x86_64

#mke2fs  -V
mke2fs 1.44.4 (18-Aug-2018)
         Using EXT2FS Library version 1.44.4

#mkfs.xfs -V
mkfs.xfs version 5.2.0-rc0

I will use your environment to reproduce this problem. Please wait.

Thanks
Yang Xu
Yang Xu Aug. 6, 2019, 6:37 a.m. UTC | #6
on 2019/08/05 19:01, Yang Xu wrote:

> on 2019/08/05 18:22, Murphy Zhou  wrote:
>> All of them, ext234 xfs and vfat. 64bit
>>
>> copy_file_range02.c:127: FAIL: copy_file_range returned wrong value: 32
>>
>> [root@8u ltp (master)]# gcc -v
>> Using built-in specs.
>> COLLECT_GCC=gcc
>> COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/8/lto-wrapper
>> OFFLOAD_TARGET_NAMES=nvptx-none
>> OFFLOAD_TARGET_DEFAULT=1
>> Target: x86_64-redhat-linux
>> Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla  --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --disable-libmpx --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
>> Thread model: posix
>> gcc version 8.3.1 20190507 (Red Hat 8.3.1-4) (GCC)
>> [root@8u ltp (master)]# rpm -qv glibc
>> glibc-2.28-72.el8.x86_64
>> [root@8u ltp (master)]# mke2fs -V
>> mke2fs 1.44.6 (5-Mar-2019)
>> 	Using EXT2FS Library version 1.44.6
>> [root@8u ltp (master)]# mkfs.xfs -V
>> mkfs.xfs version 5.2.0-rc0
>> [root@8u ltp (master)]#
>>
>> Looks like the copy succeeded at that offset.
> Hi Murphy
> Today, I use theLinux 5.3-rc3 ,  ext234 xfs and vfat 64bit all pass. This case use glibc and tst_syscall, they all failed?
>
> my environment as below:
> # gcc -v
> gcc version 8.2.1 20180905 (8.2.1-3) (GCC)
>
> #glibc -v
> glibc-2.28-18.el8.x86_64
>
> #mke2fs  -V
> mke2fs 1.44.4 (18-Aug-2018)
>          Using EXT2FS Library version 1.44.4
>
> #mkfs.xfs -V
> mkfs.xfs version 5.2.0-rc0
>
> I will use your environment to reproduce this problem. Please wait.
Hi Murphy

Test 13) still passes on my environment. mke2fs and mkfs.xfs version should not affetc all filesystem results, I think them can be excluded.
I update my gcc version to 8.3.1 20190507 ,glibc updates to  glibc-2.28-66.el8.x86_64(I don't have glibc-2.28-72.el8.x86_64, if you failed
on both glibc and syscall, I think this fail is no related with glibc).

Can you print more informatin when you run this case, as below:

diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
index 26bfa008a..e4a7fd246 100644
--- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
+++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
@@ -109,6 +109,8 @@ static void verify_copy_file_range(unsigned int n)
                 tst_res(TCONF, "filesystem doesn't have free loopdev, skip it");
                 return;
         }
+       if (tc->exp_err == EFBIG)
+               tst_res(TINFO, "tc->dst %ld  tc->len %ld", tc->dst, tc->len);
         TEST(sys_copy_file_range(fd_src, 0, *tc->copy_to_fd,
                                 &tc->dst, tc->len, tc->flags));

copy_file_range02.c:120: PASS: copy_file_range failed as expected: EOVERFLOW
copy_file_range02.c:113: INFO: tc->dst 9223372036854710270  tc->len 65537
copy_file_range02.c:120: PASS: copy_file_range failed as expected: EFBIG



> Thanks
> Yang Xu
>
>
>
Murphy Zhou Aug. 6, 2019, 9:29 a.m. UTC | #7
On Tue, Aug 06, 2019 at 02:37:01PM +0800, Yang Xu wrote:
> on 2019/08/05 19:01, Yang Xu wrote:
> 
> > on 2019/08/05 18:22, Murphy Zhou  wrote:
> > > All of them, ext234 xfs and vfat. 64bit
> > > 
> > > copy_file_range02.c:127: FAIL: copy_file_range returned wrong value: 32
> > > 
> > > [root@8u ltp (master)]# gcc -v
> > > Using built-in specs.
> > > COLLECT_GCC=gcc
> > > COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/8/lto-wrapper
> > > OFFLOAD_TARGET_NAMES=nvptx-none
> > > OFFLOAD_TARGET_DEFAULT=1
> > > Target: x86_64-redhat-linux
> > > Configured with: ../configure --enable-bootstrap --enable-languages=c,c++,fortran,lto --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla  --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --disable-libmpx --enable-offload-targets=nvptx-none --without-cuda-driver --enable-gnu-indirect-function --enable-cet --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
> > > Thread model: posix
> > > gcc version 8.3.1 20190507 (Red Hat 8.3.1-4) (GCC)
> > > [root@8u ltp (master)]# rpm -qv glibc
> > > glibc-2.28-72.el8.x86_64
> > > [root@8u ltp (master)]# mke2fs -V
> > > mke2fs 1.44.6 (5-Mar-2019)
> > > 	Using EXT2FS Library version 1.44.6
> > > [root@8u ltp (master)]# mkfs.xfs -V
> > > mkfs.xfs version 5.2.0-rc0
> > > [root@8u ltp (master)]#
> > > 
> > > Looks like the copy succeeded at that offset.
> > Hi Murphy
> > Today, I use theLinux 5.3-rc3 ,  ext234 xfs and vfat 64bit all pass. This case use glibc and tst_syscall, they all failed?
> > 
> > my environment as below:
> > # gcc -v
> > gcc version 8.2.1 20180905 (8.2.1-3) (GCC)
> > 
> > #glibc -v
> > glibc-2.28-18.el8.x86_64
> > 
> > #mke2fs  -V
> > mke2fs 1.44.4 (18-Aug-2018)
> >          Using EXT2FS Library version 1.44.4
> > 
> > #mkfs.xfs -V
> > mkfs.xfs version 5.2.0-rc0
> > 
> > I will use your environment to reproduce this problem. Please wait.
> Hi Murphy
> 
> Test 13) still passes on my environment. mke2fs and mkfs.xfs version should not affetc all filesystem results, I think them can be excluded.
> I update my gcc version to 8.3.1 20190507 ,glibc updates to  glibc-2.28-66.el8.x86_64(I don't have glibc-2.28-72.el8.x86_64, if you failed
> on both glibc and syscall, I think this fail is no related with glibc).
> 
> Can you print more informatin when you run this case, as below:
> 
> diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> index 26bfa008a..e4a7fd246 100644
> --- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> +++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> @@ -109,6 +109,8 @@ static void verify_copy_file_range(unsigned int n)
>                 tst_res(TCONF, "filesystem doesn't have free loopdev, skip it");
>                 return;
>         }
> +       if (tc->exp_err == EFBIG)
> +               tst_res(TINFO, "tc->dst %ld  tc->len %ld", tc->dst, tc->len);
>         TEST(sys_copy_file_range(fd_src, 0, *tc->copy_to_fd,
>                                 &tc->dst, tc->len, tc->flags));
> 
> copy_file_range02.c:120: PASS: copy_file_range failed as expected: EOVERFLOW
> copy_file_range02.c:113: INFO: tc->dst 9223372036854710270  tc->len 65537
> copy_file_range02.c:120: PASS: copy_file_range failed as expected: EFBIG

That's odd..

copy_file_range02.c:112: INFO: 12: tc->dst 9223372036854710270, tc->len 65537
copy_file_range02.c:128: FAIL: copy_file_range returned wrong value: 32

> 
> 
> 
> > Thanks
> > Yang Xu
> > 
> > 
> > 
> 
> 
>
Petr Vorel Aug. 6, 2019, 4:27 p.m. UTC | #8
Hi Murphy,

> On Mon, Aug 05, 2019 at 03:11:53PM +0800, Yang Xu wrote:
> > on 2019/08/05 14:58, Murphy Zhou  wrote:

> > > > + * 13) Try to copy contents to a file with target file range
> > > > >  + *     beyond maximum supported file size ->EFBIG
> > > Test 13) fails on latest Linus tree. Is there any report or working on this?
> > Hi Murphy

> >    Test 13)  passed on my system(64bit, 5.2.0+, ext4,vfat,btrfs,xfs ).
> >    Do you provide more infomation(filesystem, 32bit or 64bit)?

> All of them, ext234 xfs and vfat. 64bit
Hi, I can confirm that. Also fails on btrfs.

> copy_file_range02.c:127: FAIL: copy_file_range returned wrong value: 32
I got this one as well. I tested it today again with 5.3.0-rc3+ 0eb0ce0 ("Merge
tag 'spi-fix-v5.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi")
and got this error:

copy_file_range02.c:130: FAIL: copy_file_range failed unexpectedly; expected EFBIG, but got: EINVAL

But that is caused by tmpfs used as TMPDIR, going to send a patch fixing it.

Kind regards,
Petr
Murphy Zhou Aug. 7, 2019, 10:17 a.m. UTC | #9
ccing linux-xfs@vger.kernel.org

Hi,

Tracked down this to be a xfs specific issue:

If we call copy_file_range with a large offset like this:

	loff_t off = 9223372036854710270; // 2 ** 63
	ret = copy_file_range(fd_in, 0, fd_out, &off, 65537, 0);

(test programme cfrbig.c attached)

xfs has it done successfully, while ext4 returns EFBIG.

ccing xfs folks to check that if this is expected for xfs.

We are now expecting EFBIG in copy_file_range02.c test #12.

Thanks!

Other info:

[root@8u ~]# xfs_info /test1
meta-data=/dev/pmem0             isize=512    agcount=4, agsize=327680 blks
         =                       sectsz=4096  attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1
data     =                       bsize=4096   blocks=1310720, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=4096  sunit=1 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[root@8u ~]# mkfs.xfs -V
mkfs.xfs version 5.2.0-rc0
[root@8u ~]# mount | grep test
/dev/pmem0 on /test1 type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
[root@8u ~]# uname -r
5.3.0-rc3-v5.3-rc3-282-g33920f1
[root@8u ~]# cp a.out /test1
[root@8u ~]# cp 1t /test1
[root@8u ~]# cd /test1
[root@8u test1]# ./a.out 1t 2t
ret 40945
[root@8u test1]# ll 1t 2t
-rw-r--r--. 1 root root               40945 Aug  7 17:35 1t
-rw-r--r--. 1 root root 9223372036854751215 Aug  7 17:35 2t
[root@8u test1]# 

On Tue, Aug 06, 2019 at 06:27:03PM +0200, Petr Vorel wrote:
> Hi Murphy,
> 
> > On Mon, Aug 05, 2019 at 03:11:53PM +0800, Yang Xu wrote:
> > > on 2019/08/05 14:58, Murphy Zhou  wrote:
> 
> > > > > + * 13) Try to copy contents to a file with target file range
> > > > > >  + *     beyond maximum supported file size ->EFBIG
> > > > Test 13) fails on latest Linus tree. Is there any report or working on this?
> > > Hi Murphy
> 
> > >    Test 13)  passed on my system(64bit, 5.2.0+, ext4,vfat,btrfs,xfs ).
> > >    Do you provide more infomation(filesystem, 32bit or 64bit)?
> 
> > All of them, ext234 xfs and vfat. 64bit
> Hi, I can confirm that. Also fails on btrfs.
> 
> > copy_file_range02.c:127: FAIL: copy_file_range returned wrong value: 32
> I got this one as well. I tested it today again with 5.3.0-rc3+ 0eb0ce0 ("Merge
> tag 'spi-fix-v5.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi")
> and got this error:
> 
> copy_file_range02.c:130: FAIL: copy_file_range failed unexpectedly; expected EFBIG, but got: EINVAL
> 
> But that is caused by tmpfs used as TMPDIR, going to send a patch fixing it.

And I have a question about LTP itself.

If we run the testcase directly like:
	 ./testcases/kernel/syscalls/copy_file_range/copy_file_range02

to test all_filesystems, for every filesystem, we mkfs and mount it in
.mntpoint, but we do not chdir to .mntpoint. So we are running tests in 
the same tmpdir, fs type of which does not change while looping
all_filesystems.  Only the .mntpoint in tmpdir has different fs type in
each loop.

Now we are using this to test cross-device copy in copy_file_range01.c,
but in copy_file_range02.c, we are not using .mntpint at all, all the
tests in the all_filesystems loop are running in the same tmpdir. In other
words, we are NOT testing all filesystems.

Is this expected?

I commented out testcases in copy_file_range02.c other then #12, and add
some nasty debug info:

diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
index 56797f639..c74f1a7ec 100644
--- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
+++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
@@ -62,6 +62,7 @@ static struct tcase {
 	loff_t     len;
 	const char *tname;
 } tcases[] = {
+#if 0
 	{&fd_rdonly,	0,   EBADF,      0,     CONTSIZE, "readonly file"},
 	{&fd_dir,	0,   EISDIR,     0,     CONTSIZE, "directory"},
 	{&fd_append,	0,   EBADF,      0,     CONTSIZE, "append to file"},
@@ -74,6 +75,7 @@ static struct tcase {
 	{&fd_chrdev,    0,   EINVAL,     0,     CONTSIZE, "charr device"},
 	{&fd_fifo,      0,   EINVAL,     0,     CONTSIZE, "fifo"},
 	{&fd_copy,      0,   EOVERFLOW,  MAX_OFF, ULLONG_MAX, "max length lenght"},
+#endif
 	{&fd_copy,      0,   EFBIG,      MAX_OFF, MIN_OFF, "max file size"},
 };
 
@@ -163,6 +165,9 @@ static void setup(void)
 	syscall_info();
 	char dev_path[1024];
 
+	system("pwd");
+	system("df -Th .");
+	system("mount | grep loop");
 	if (access(FILE_DIR_PATH, F_OK) == -1)
 		SAFE_MKDIR(FILE_DIR_PATH, 0777);
 	/*


Got this: (deleted some irrelevant lines of output)

All tests on / filesystem.


tst_test.c:1161: INFO: Testing on ext2
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with ext2 opts='' extra opts=''
mke2fs 1.44.6 (5-Mar-2019)
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:44: INFO: Testing __NR_copy_file_range syscall
/tmp/koASqI
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sda2      xfs   618G  432G  187G  70% /
/dev/loop0 on /tmp/koASqI/mnt_point type ext2 (rw,relatime,seclabel,errors=continue,user_xattr,acl)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=faff58f0-a824-48b6-a103-bc6b1cc99a17
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:132: FAIL: copy_file_range returned wrong value: 32

tst_test.c:1161: INFO: Testing on ext3
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with ext3 opts='' extra opts=''
mke2fs 1.44.6 (5-Mar-2019)
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:44: INFO: Testing __NR_copy_file_range syscall
/tmp/koASqI
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sda2      xfs   618G  432G  187G  70% /
/dev/loop0 on /tmp/koASqI/mnt_point type ext3 (rw,relatime,seclabel)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=c9e759f6-866d-421d-8322-1a60e7e387ce
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:132: FAIL: copy_file_range returned wrong value: 32

tst_test.c:1161: INFO: Testing on ext4
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with ext4 opts='' extra opts=''
mke2fs 1.44.6 (5-Mar-2019)
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:44: INFO: Testing __NR_copy_file_range syscall
/tmp/koASqI
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sda2      xfs   618G  432G  187G  70% /
/dev/loop0 on /tmp/koASqI/mnt_point type ext4 (rw,relatime,seclabel)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=de87413e-3700-4928-9529-7968a6753dda
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:132: FAIL: copy_file_range returned wrong value: 32

tst_test.c:1161: INFO: Testing on xfs
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with xfs opts='' extra opts=''
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:44: INFO: Testing __NR_copy_file_range syscall
/tmp/koASqI
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sda2      xfs   618G  432G  187G  70% /
/dev/loop0 on /tmp/koASqI/mnt_point type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=bd59eb67-2ca9-44c5-9f04-1a2bd85ef3cc
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:132: FAIL: copy_file_range returned wrong value: 32

tst_test.c:1161: INFO: Testing on vfat
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with vfat opts='' extra opts=''
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:44: INFO: Testing __NR_copy_file_range syscall
/tmp/koASqI
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/sda2      xfs   618G  432G  187G  70% /
/dev/loop0 on /tmp/koASqI/mnt_point type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=e29211e3-175e-46de-b8bc-e6f021de585e
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:132: FAIL: copy_file_range returned wrong value: 32



After adding chdir to .mntpoint in setup:


diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
index 56797f639..d7b0a7cfd 100644
--- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
+++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
@@ -62,6 +62,7 @@ static struct tcase {
 	loff_t     len;
 	const char *tname;
 } tcases[] = {
+#if 0
 	{&fd_rdonly,	0,   EBADF,      0,     CONTSIZE, "readonly file"},
 	{&fd_dir,	0,   EISDIR,     0,     CONTSIZE, "directory"},
 	{&fd_append,	0,   EBADF,      0,     CONTSIZE, "append to file"},
@@ -74,6 +75,7 @@ static struct tcase {
 	{&fd_chrdev,    0,   EINVAL,     0,     CONTSIZE, "charr device"},
 	{&fd_fifo,      0,   EINVAL,     0,     CONTSIZE, "fifo"},
 	{&fd_copy,      0,   EOVERFLOW,  MAX_OFF, ULLONG_MAX, "max length lenght"},
+#endif
 	{&fd_copy,      0,   EFBIG,      MAX_OFF, MIN_OFF, "max file size"},
 };
 
@@ -156,6 +158,7 @@ static void cleanup(void)
 	if (fd_copy > 0)
 		SAFE_CLOSE(fd_copy);
 	SAFE_UNLINK(FILE_FIFO);
+	SAFE_CHDIR("..");
 }
 
 static void setup(void)
@@ -163,6 +166,11 @@ static void setup(void)
 	syscall_info();
 	char dev_path[1024];
 
+	SAFE_CHDIR(MNTPOINT);
+
+	system("pwd");
+	system("df -Th .");
+	system("mount | grep loop");
 	if (access(FILE_DIR_PATH, F_OK) == -1)
 		SAFE_MKDIR(FILE_DIR_PATH, 0777);
 	/*


Only xfs fails the test now:  (vfat brok)

tst_test.c:1161: INFO: Testing on ext2
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with ext2 opts='' extra opts=''
mke2fs 1.44.6 (5-Mar-2019)
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:41: INFO: Testing libc copy_file_range()
/tmp/QtMvgB/mnt_point
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/loop0     ext2  248M  2.1M  234M   1% /tmp/QtMvgB/mnt_point
/dev/loop0 on /tmp/QtMvgB/mnt_point type ext2 (rw,relatime,seclabel,errors=continue,user_xattr,acl)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=46d54fae-85fb-4836-ab69-2ebb23d8fa75
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:123: PASS: copy_file_range failed as expected: EFBIG

tst_test.c:1161: INFO: Testing on ext3
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with ext3 opts='' extra opts=''
mke2fs 1.44.6 (5-Mar-2019)
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:41: INFO: Testing libc copy_file_range()
/tmp/QtMvgB/mnt_point
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/loop0     ext3  240M  2.1M  226M   1% /tmp/QtMvgB/mnt_point
/dev/loop0 on /tmp/QtMvgB/mnt_point type ext3 (rw,relatime,seclabel)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=9598e117-03cc-4bf3-9706-3f072303709b
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:123: PASS: copy_file_range failed as expected: EFBIG

tst_test.c:1161: INFO: Testing on ext4
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with ext4 opts='' extra opts=''
mke2fs 1.44.6 (5-Mar-2019)
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:41: INFO: Testing libc copy_file_range()
/tmp/QtMvgB/mnt_point
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/loop0     ext4  240M  2.1M  222M   1% /tmp/QtMvgB/mnt_point
/dev/loop0 on /tmp/QtMvgB/mnt_point type ext4 (rw,relatime,seclabel)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=714961f8-dcda-451e-98df-091d2b670a97
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:123: PASS: copy_file_range failed as expected: EFBIG

tst_test.c:1161: INFO: Testing on xfs
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with xfs opts='' extra opts=''
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:41: INFO: Testing libc copy_file_range()
/tmp/QtMvgB/mnt_point
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/loop0     xfs   251M   15M  236M   6% /tmp/QtMvgB/mnt_point
/dev/loop0 on /tmp/QtMvgB/mnt_point type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
Setting up swapspace version 1, size = 36 KiB (36864 bytes)
no label, UUID=5a4b2adb-5b03-484c-a5b3-6e23ea3d80c8
copy_file_range02.c:103: INFO: Test #0: max file size
copy_file_range02.c:132: FAIL: copy_file_range returned wrong value: 32

tst_test.c:1161: INFO: Testing on vfat
tst_mkfs.c:90: INFO: Formatting /dev/loop0 with vfat opts='' extra opts=''
tst_test.c:1100: INFO: Timeout per run is 0h 05m 00s
copy_file_range.h:41: INFO: Testing libc copy_file_range()
/tmp/QtMvgB/mnt_point
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/loop0     vfat  256M     0  256M   0% /tmp/QtMvgB/mnt_point
/dev/loop0 on /tmp/QtMvgB/mnt_point type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
tst_device.c:87: INFO: Found free device 1 '/dev/loop1'
safe_macros.c:1032: BROK: copy_file_range02.c:182: mknod() failed: EPERM
safe_macros.c:360: WARN: copy_file_range02.c:160: unlink(file_fifo) failed: ENOENT


Thanks!
M

> 
> Kind regards,
> Petr
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <limits.h>

#if 0
static loff_t copy_file_range(int fd_in, loff_t *off_in, int fd_out,
		        loff_t *off_out, size_t len, unsigned int flags)
{
	return syscall(__NR_copy_file_range, fd_in, off_in, fd_out,
		           off_out, len, flags);
}
#endif

int main(int argc, char **argv)
{
	int fd_in, fd_out, ret;
	loff_t off = 9223372036854710270; // 2 ** 63

	if (argc != 3) {
		fprintf(stderr, "Usage: %s <source> <destination>\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	fd_in = open(argv[1], O_RDONLY);
	if (fd_in == -1) {
		perror("open (argv[1])");
		exit(EXIT_FAILURE);
	}

	fd_out = open(argv[2], O_CREAT | O_RDWR | O_TRUNC, 0644);
	if (fd_out == -1) {
		perror("open (argv[2])");
		exit(EXIT_FAILURE);
	}

	ret = copy_file_range(fd_in, 0, fd_out, &off, 65537, 0);
	if (ret == -1) {
		perror("copy_file_range");
		exit(EXIT_FAILURE);
	}
	printf("ret %d\n", ret);
	close(fd_in);
	close(fd_out);

	exit(EXIT_SUCCESS);
}
Dave Chinner Aug. 7, 2019, 12:12 p.m. UTC | #10
On Wed, Aug 07, 2019 at 06:17:42PM +0800, Murphy Zhou wrote:
> ccing linux-xfs@vger.kernel.org
> 
> Hi,
> 
> Tracked down this to be a xfs specific issue:
> 
> If we call copy_file_range with a large offset like this:
> 
> 	loff_t off = 9223372036854710270; // 2 ** 63
> 	ret = copy_file_range(fd_in, 0, fd_out, &off, 65537, 0);

That's not 2**63:

$ echo $((9223372036854710270 + 65537))
9223372036854775807

$ echo $((2**63 - 1))
9223372036854775807

i.e. it's LLONG_MAX, not an overflow. XFS sets sb->s_maxbytes in
xfs_max_file_offset to:

	(1 << BITS_PER_LONG - 1) - 1 = 2**63 - 1 = LLONG_MAX.

So no matter how we look at it, this operation should not return
EFBIG on XFS.

> (test programme cfrbig.c attached)
> 
> xfs has it done successfully, while ext4 returns EFBIG.

ext4 has a max file size of 2**32 * blocksize, so it doesn't support
files larger than 16TB. So it will give EFBIG on this test.

/me compiles and runs the test program on his workstation:

$ ls -l foobar
-rw------- 1 dave dave 10737418240 Apr 12 14:46 foobar
$ ./a.out foobar bar
ret 65537
$ ls -l bar
-rw-r--r-- 1 dave dave 9223372036854775807 Aug  7 22:11 bar
$

That looks like a successful copy to me, not EINVAL or EFBIG...

Cheers,

Dave.
Yang Xu Aug. 8, 2019, 3:11 a.m. UTC | #11
on 2019/08/07 18:17, Murphy Zhou wrote:

> And I have a question about LTP itself.
>
> If we run the testcase directly like:
> 	 ./testcases/kernel/syscalls/copy_file_range/copy_file_range02
>
> to test all_filesystems, for every filesystem, we mkfs and mount it in
> .mntpoint, but we do not chdir to .mntpoint. So we are running tests in 
> the same tmpdir, fs type of which does not change while looping
> all_filesystems.  Only the .mntpoint in tmpdir has different fs type in
> each loop.
>
> Now we are using this to test cross-device copy in copy_file_range01.c,
> but in copy_file_range02.c, we are not using .mntpint at all, all the
> tests in the all_filesystems loop are running in the same tmpdir. In other
> words, we are NOT testing all filesystems.
>
> Is this expected?
 I removed the mnted test for cross-device copy_file_range in copy_file_range02.c.
And I ignore the non-used mntpoint. IMO, we can directly use the FILE_MNTED to test EFBIG on all filesystems, 

as below:
diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
index 26bfa008a..67974ffa2 100644
--- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
+++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
@@ -49,6 +49,7 @@ static int fd_blkdev;
 static int fd_chrdev;
 static int fd_fifo;
 static int fd_copy;
+static int fd_mnted;

 static int chattr_i_nsup;
 static int swap_nsup;

@@ -73,7 +74,7 @@ static struct tcase {
        {&fd_chrdev,    0,   EINVAL,     0,     CONTSIZE},
        {&fd_fifo,      0,   EINVAL,     0,     CONTSIZE},
        {&fd_copy,      0,   EOVERFLOW,  MAX_OFF, ULLONG_MAX},
-       {&fd_copy,      0,   EFBIG,      MAX_OFF, MIN_OFF},
+       {&fd_mnted,      0,   EFBIG,      MAX_OFF, MIN_OFF},
 };

 static int run_command(char *command, char *option, char *file)
@@ -117,7 +118,10 @@ static void verify_copy_file_range(unsigned int n)
                        tst_res(TPASS | TTERRNO,
                                        "copy_file_range failed as expected");
                } else {
-                       tst_res(TFAIL | TTERRNO,
+                       if (tc->exp_err == EFBIG && TST_ERR == EXDEV)
+                               tst_res(TCONF, "copy_file_range doesn't support cross-device,skip it");
+                       else
+                               tst_res(TFAIL | TTERRNO,
                                "copy_file_range failed unexpectedly; expected %s, but got",
                                tst_strerrno(tc->exp_err));
                        return;

@@ -152,6 +156,8 @@ static void cleanup(void)
                SAFE_CLOSE(fd_dup);
        if (fd_copy > 0)
                SAFE_CLOSE(fd_copy);
+       if (fd_mnted > 0)
+               SAFE_CLOSE(fd_mnted);
        SAFE_UNLINK(FILE_FIFO);
 }

@@ -194,6 +200,7 @@ static void setup(void)

        fd_copy = SAFE_OPEN(FILE_COPY_PATH, O_RDWR | O_CREAT | O_TRUNC, 0664);
        chattr_i_nsup = run_command("chattr", "+i", FILE_IMMUTABLE_PATH);
+       fd_mnted  = SAFE_OPEN(FILE_MNTED_PATH, O_RDWR | O_CREAT, 0664);

        if (!tst_fs_has_free(".", sysconf(_SC_PAGESIZE) * 10, TST_BYTES)) {
                tst_res(TCONF, "Insufficient disk space to create swap file");
                swap_nsup = 3;

test12) succeed on extN, failed on both btrfs and xfs, we need to detect filesystem type to handle. Or, I think we 
can set a limit on filesize because this kind of user scene is a bit more than the first one , the EFBIG error can be 
received easily (Also, we don't need  mnt_device mntpoint all_filesystem if so).
What do you think about it?

> I commented out testcases in copy_file_range02.c other then #12, and add
> some nasty debug info:
Murphy Zhou Aug. 8, 2019, 3:46 a.m. UTC | #12
On Wed, Aug 07, 2019 at 10:12:12PM +1000, Dave Chinner wrote:
> On Wed, Aug 07, 2019 at 06:17:42PM +0800, Murphy Zhou wrote:
> > ccing linux-xfs@vger.kernel.org
> > 
> > Hi,
> > 
> > Tracked down this to be a xfs specific issue:
> > 
> > If we call copy_file_range with a large offset like this:
> > 
> > 	loff_t off = 9223372036854710270; // 2 ** 63
> > 	ret = copy_file_range(fd_in, 0, fd_out, &off, 65537, 0);
> 
> That's not 2**63:

Ya! I was looking too roughly.

> 
> $ echo $((9223372036854710270 + 65537))
> 9223372036854775807
> 
> $ echo $((2**63 - 1))
> 9223372036854775807
> 
> i.e. it's LLONG_MAX, not an overflow. XFS sets sb->s_maxbytes in
> xfs_max_file_offset to:
> 
> 	(1 << BITS_PER_LONG - 1) - 1 = 2**63 - 1 = LLONG_MAX.
> 
> So no matter how we look at it, this operation should not return
> EFBIG on XFS.
> 
> > (test programme cfrbig.c attached)
> > 
> > xfs has it done successfully, while ext4 returns EFBIG.
> 
> ext4 has a max file size of 2**32 * blocksize, so it doesn't support
> files larger than 16TB. So it will give EFBIG on this test.
> 
> /me compiles and runs the test program on his workstation:
> 
> $ ls -l foobar
> -rw------- 1 dave dave 10737418240 Apr 12 14:46 foobar
> $ ./a.out foobar bar
> ret 65537
> $ ls -l bar
> -rw-r--r-- 1 dave dave 9223372036854775807 Aug  7 22:11 bar
> $
> 
> That looks like a successful copy to me, not EINVAL or EFBIG...

Thanks Dave for the confirmation! This testcase needs some fix.

Murphy

> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com
Murphy Zhou Aug. 8, 2019, 3:57 a.m. UTC | #13
On Thu, Aug 08, 2019 at 11:11:43AM +0800, Yang Xu wrote:
> on 2019/08/07 18:17, Murphy Zhou wrote:
> 
> > And I have a question about LTP itself.
> >
> > If we run the testcase directly like:
> > 	 ./testcases/kernel/syscalls/copy_file_range/copy_file_range02
> >
> > to test all_filesystems, for every filesystem, we mkfs and mount it in
> > .mntpoint, but we do not chdir to .mntpoint. So we are running tests in 
> > the same tmpdir, fs type of which does not change while looping
> > all_filesystems.  Only the .mntpoint in tmpdir has different fs type in
> > each loop.
> >
> > Now we are using this to test cross-device copy in copy_file_range01.c,
> > but in copy_file_range02.c, we are not using .mntpint at all, all the
> > tests in the all_filesystems loop are running in the same tmpdir. In other
> > words, we are NOT testing all filesystems.
> >
> > Is this expected?
>  I removed the mnted test for cross-device copy_file_range in copy_file_range02.c.
> And I ignore the non-used mntpoint. IMO, we can directly use the FILE_MNTED to test EFBIG on all filesystems, 

If mntpoint is not used, it makes absolutely NO sense to test all_filesystems.

Because in the all_filesystems loop, various supported filesystems are
created and mounted in mntpoint.

And the copy_file_range tests happens outside of mntpoint. It just repeats
the same test several times in the same tmpdir, fs type of which depends
on /tmp configuration.

When the log prints "testing ext2", it's not the truth.

EFBIG is another issue.

Thanks,
Murphy
> 
> as below:
> diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> index 26bfa008a..67974ffa2 100644
> --- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> +++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
> @@ -49,6 +49,7 @@ static int fd_blkdev;
>  static int fd_chrdev;
>  static int fd_fifo;
>  static int fd_copy;
> +static int fd_mnted;
> 
>  static int chattr_i_nsup;
>  static int swap_nsup;
> 
> @@ -73,7 +74,7 @@ static struct tcase {
>         {&fd_chrdev,    0,   EINVAL,     0,     CONTSIZE},
>         {&fd_fifo,      0,   EINVAL,     0,     CONTSIZE},
>         {&fd_copy,      0,   EOVERFLOW,  MAX_OFF, ULLONG_MAX},
> -       {&fd_copy,      0,   EFBIG,      MAX_OFF, MIN_OFF},
> +       {&fd_mnted,      0,   EFBIG,      MAX_OFF, MIN_OFF},
>  };
> 
>  static int run_command(char *command, char *option, char *file)
> @@ -117,7 +118,10 @@ static void verify_copy_file_range(unsigned int n)
>                         tst_res(TPASS | TTERRNO,
>                                         "copy_file_range failed as expected");
>                 } else {
> -                       tst_res(TFAIL | TTERRNO,
> +                       if (tc->exp_err == EFBIG && TST_ERR == EXDEV)
> +                               tst_res(TCONF, "copy_file_range doesn't support cross-device,skip it");
> +                       else
> +                               tst_res(TFAIL | TTERRNO,
>                                 "copy_file_range failed unexpectedly; expected %s, but got",
>                                 tst_strerrno(tc->exp_err));
>                         return;
> 
> @@ -152,6 +156,8 @@ static void cleanup(void)
>                 SAFE_CLOSE(fd_dup);
>         if (fd_copy > 0)
>                 SAFE_CLOSE(fd_copy);
> +       if (fd_mnted > 0)
> +               SAFE_CLOSE(fd_mnted);
>         SAFE_UNLINK(FILE_FIFO);
>  }
> 
> @@ -194,6 +200,7 @@ static void setup(void)
> 
>         fd_copy = SAFE_OPEN(FILE_COPY_PATH, O_RDWR | O_CREAT | O_TRUNC, 0664);
>         chattr_i_nsup = run_command("chattr", "+i", FILE_IMMUTABLE_PATH);
> +       fd_mnted  = SAFE_OPEN(FILE_MNTED_PATH, O_RDWR | O_CREAT, 0664);
> 
>         if (!tst_fs_has_free(".", sysconf(_SC_PAGESIZE) * 10, TST_BYTES)) {
>                 tst_res(TCONF, "Insufficient disk space to create swap file");
>                 swap_nsup = 3;
> 
> test12) succeed on extN, failed on both btrfs and xfs, we need to detect filesystem type to handle. Or, I think we 
> can set a limit on filesize because this kind of user scene is a bit more than the first one , the EFBIG error can be 
> received easily (Also, we don't need  mnt_device mntpoint all_filesystem if so).
> What do you think about it?
> 
> > I commented out testcases in copy_file_range02.c other then #12, and add
> > some nasty debug info:
> 
> 
>
Petr Vorel Aug. 27, 2019, 10:04 a.m. UTC | #14
Hi Murphy,

> On Thu, Aug 08, 2019 at 11:11:43AM +0800, Yang Xu wrote:
> > on 2019/08/07 18:17, Murphy Zhou wrote:

> > > And I have a question about LTP itself.

> > > If we run the testcase directly like:
> > > 	 ./testcases/kernel/syscalls/copy_file_range/copy_file_range02

> > > to test all_filesystems, for every filesystem, we mkfs and mount it in
> > > .mntpoint, but we do not chdir to .mntpoint. So we are running tests in 
> > > the same tmpdir, fs type of which does not change while looping
> > > all_filesystems.  Only the .mntpoint in tmpdir has different fs type in
> > > each loop.

> > > Now we are using this to test cross-device copy in copy_file_range01.c,
> > > but in copy_file_range02.c, we are not using .mntpint at all, all the
> > > tests in the all_filesystems loop are running in the same tmpdir. In other
> > > words, we are NOT testing all filesystems.

> > > Is this expected?
> >  I removed the mnted test for cross-device copy_file_range in copy_file_range02.c.
> > And I ignore the non-used mntpoint. IMO, we can directly use the FILE_MNTED to test EFBIG on all filesystems, 

> If mntpoint is not used, it makes absolutely NO sense to test all_filesystems.
Thanks for pointing this out. I was blind when reviewing this patchset.
At least this has been fixed.

> Because in the all_filesystems loop, various supported filesystems are
> created and mounted in mntpoint.

> And the copy_file_range tests happens outside of mntpoint. It just repeats
> the same test several times in the same tmpdir, fs type of which depends
> on /tmp configuration.

> When the log prints "testing ext2", it's not the truth.

> EFBIG is another issue.
Yep, we still need to think about different errnos, which depend on LTP policy
being defined [1].

> Thanks,
> Murphy

Kind regards,
Petr

[1] https://patchwork.ozlabs.org/patch/1143438/

Patch
diff mbox series

diff --git a/include/lapi/fs.h b/include/lapi/fs.h
index 42cb4f9b2..1af55628c 100644
--- a/include/lapi/fs.h
+++ b/include/lapi/fs.h
@@ -7,6 +7,8 @@ 
 #ifdef HAVE_LINUX_FS_H
 # include <linux/fs.h>
 #endif
+# include <sys/user.h>
+# include "lapi/abisize.h"
 
 #ifndef LAPI_FS_H
 #define LAPI_FS_H
@@ -35,4 +37,11 @@ 
 #define FS_NODUMP_FL	   0x00000040 /* do not dump file */
 #endif
 
+/* Referred form linux kernel include/linux/fs.h */
+#ifdef TST_ABI64
+ #define MAX_LFS_FILESIZE   ((loff_t)LLONG_MAX)
+#else
+ #define MAX_LFS_FILESIZE   ((loff_t)ULONG_MAX << PAGE_SHIFT)
+#endif
+
 #endif
diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range.h b/testcases/kernel/syscalls/copy_file_range/copy_file_range.h
index b6d132978..c7f423e45 100644
--- a/testcases/kernel/syscalls/copy_file_range/copy_file_range.h
+++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range.h
@@ -9,7 +9,10 @@ 
 
 #include <stdbool.h>
 #include <unistd.h>
+#include <sys/sysmacros.h>
+#include <limits.h>
 #include "lapi/syscalls.h"
+#include "lapi/fs.h"
 
 #define TEST_VARIANTS	2
 
@@ -18,10 +21,18 @@ 
 #define FILE_DEST_PATH  "file_dest"
 #define FILE_RDONL_PATH "file_rdonl"
 #define FILE_DIR_PATH	"file_dir"
-#define FILE_MNTED_PATH	MNTPOINT"/file_mnted"
+#define FILE_MNTED_PATH  MNTPOINT"/file_mnted"
+#define FILE_IMMUTABLE_PATH "file_immutable"
+#define FILE_SWAP_PATH "file_swap"
+#define FILE_CHRDEV    "/dev/null"
+#define FILE_FIFO      "file_fifo"
+#define FILE_COPY_PATH  "file_copy"
 
 #define CONTENT		"ABCDEFGHIJKLMNOPQRSTUVWXYZ12345\n"
 #define CONTSIZE	(sizeof(CONTENT) - 1)
+#define MAX_LEN   MAX_LFS_FILESIZE
+#define MIN_OFF   65537
+#define MAX_OFF   (MAX_LEN - MIN_OFF)
 
 static void syscall_info(void)
 {
diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
index 07c0207c2..36976156e 100644
--- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
+++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c
@@ -10,15 +10,25 @@ 
  *
  * 1) Try to copy contents to file open as readonly
  *    -> EBADF
- * 2) Try to copy contents to file on different mounted
- *    filesystem -> EXDEV
- * 3) Try to copy contents to directory -> EISDIR
- * 4) Try to copy contents to a file opened with the
+ * 2) Try to copy contents to directory -> EISDIR
+ * 3) Try to copy contents to a file opened with the
  *    O_APPEND flag -> EBADF
- * 5) Try to copy contents to closed filedescriptor
+ * 4) Try to copy contents to closed filedescriptor
  *    -> EBADF
- * 6) Try to copy contents with invalid 'flags' value
+ * 5) Try to copy contents with invalid 'flags' value
  *    -> EINVAL
+ * 6) Try to copy contents to a file chattred with +i
+ *    flag -> EPERM
+ * 7) Try to copy contents to a swapfile ->ETXTBSY
+ * 8) Try to copy contents to the samefile with overlapping
+ *    ->EINVAL
+ * 9) Try to copy contents to a blkdev ->EINVAL
+ * 10) Try to copy contents to a chardev ->EINVAL
+ * 11) Try to copy contents to a FIFO ->EINVAL
+ * 12) Try to copy contents to a file with length beyond
+ *     16EiB wraps around 0 -> EOVERFLOW
+ * 13) Try to copy contents to a file with target file range
+ *     beyond maximum supported file size ->EFBIG
  */
 
 #define _GNU_SOURCE
@@ -29,30 +39,78 @@ 
 static int fd_src;
 static int fd_dest;
 static int fd_rdonly;
-static int fd_mnted;
 static int fd_dir;
 static int fd_closed;
 static int fd_append;
+static int fd_immutable;
+static int fd_swapfile;
+static int fd_dup;
+static int fd_blkdev;
+static int fd_chrdev;
+static int fd_fifo;
+static int fd_copy;
+
+static int chattr_i_nsup;
+static int swap_nsup;
+static int loop_devn;
 
 static struct tcase {
 	int	*copy_to_fd;
 	int	flags;
 	int	exp_err;
+	loff_t  dst;
+	loff_t     len;
 } tcases[] = {
-	{&fd_rdonly,	0,	EBADF},
-	{&fd_mnted,	0,	EXDEV},
-	{&fd_dir,	0,	EISDIR},
-	{&fd_append,	0,	EBADF},
-	{&fd_closed,	0,	EBADF},
-	{&fd_dest,	-1,	EINVAL},
+	{&fd_rdonly,	0,   EBADF,      0,     CONTSIZE},
+	{&fd_dir,	0,   EISDIR,     0,     CONTSIZE},
+	{&fd_append,	0,   EBADF,      0,     CONTSIZE},
+	{&fd_closed,	0,   EBADF,      0,     CONTSIZE},
+	{&fd_dest,	-1,  EINVAL,     0,     CONTSIZE},
+	{&fd_immutable, 0,   EPERM,      0,     CONTSIZE},
+	{&fd_swapfile,  0,   ETXTBSY,    0,     CONTSIZE},
+	{&fd_dup,       0,   EINVAL,     0,     CONTSIZE/2},
+	{&fd_blkdev,    0,   EINVAL,     0,     CONTSIZE},
+	{&fd_chrdev,    0,   EINVAL,     0,     CONTSIZE},
+	{&fd_fifo,      0,   EINVAL,     0,     CONTSIZE},
+	{&fd_copy,      0,   EOVERFLOW,  MAX_OFF, ULLONG_MAX},
+	{&fd_copy,      0,   EFBIG,      MAX_OFF, MIN_OFF},
 };
 
+static int run_command(char *command, char *option, char *file)
+{
+	const char *const cmd[] = {command, option, file, NULL};
+	int ret;
+
+	ret = tst_run_cmd(cmd, NULL, NULL, 1);
+	switch (ret) {
+	case 0:
+	return 0;
+	case 255:
+		tst_res(TCONF, "%s binary not installed", command);
+	return 1;
+	default:
+		tst_res(TCONF, "%s exited with %i", command, ret);
+	return 2;
+	}
+}
+
 static void verify_copy_file_range(unsigned int n)
 {
 	struct tcase *tc = &tcases[n];
-
+	if (tc->copy_to_fd == &fd_immutable && chattr_i_nsup) {
+		tst_res(TCONF, "filesystem doesn't support chattr +i, skip it");
+		return;
+	}
+	if (tc->copy_to_fd == &fd_swapfile && swap_nsup) {
+		tst_res(TCONF, "filesystem doesn't support swapfile, skip it");
+		return;
+	}
+	if (tc->copy_to_fd == &fd_blkdev && loop_devn == -1) {
+		tst_res(TCONF, "filesystem doesn't have free loopdev, skip it");
+		return;
+	}
 	TEST(sys_copy_file_range(fd_src, 0, *tc->copy_to_fd,
-				0, CONTSIZE, tc->flags));
+				&tc->dst, tc->len, tc->flags));
 
 	if (TST_RET == -1) {
 		if (tc->exp_err == TST_ERR) {
@@ -76,33 +134,80 @@  static void cleanup(void)
 		SAFE_CLOSE(fd_append);
 	if (fd_dir > 0)
 		SAFE_CLOSE(fd_dir);
-	if (fd_mnted > 0)
-		SAFE_CLOSE(fd_mnted);
 	if (fd_rdonly > 0)
 		SAFE_CLOSE(fd_rdonly);
 	if (fd_dest > 0)
 		SAFE_CLOSE(fd_dest);
 	if (fd_src > 0)
 		SAFE_CLOSE(fd_src);
+	if (fd_immutable > 0) {
+		run_command("chattr", "-i", FILE_IMMUTABLE_PATH);
+		SAFE_CLOSE(fd_immutable);
+	}
+	if (fd_swapfile > 0) {
+		run_command("swapoff", FILE_SWAP_PATH, NULL);
+		SAFE_CLOSE(fd_swapfile);
+	}
+	if (fd_dup > 0)
+		SAFE_CLOSE(fd_dup);
+	if (fd_copy > 0)
+		SAFE_CLOSE(fd_copy);
+	SAFE_UNLINK(FILE_FIFO);
 }
 
 static void setup(void)
 {
 	syscall_info();
+	char dev_path[1024];
 
 	if (access(FILE_DIR_PATH, F_OK) == -1)
 		SAFE_MKDIR(FILE_DIR_PATH, 0777);
+	/*
+	 * call tst_find_free_loopdev(), avoid overwriting its
+	 * content on used loopdev.
+	 */
+	loop_devn = tst_find_free_loopdev(dev_path, sizeof(dev_path));
+
+	SAFE_MKNOD(FILE_FIFO, S_IFIFO | 0777, 0);
 
 	fd_src    = SAFE_OPEN(FILE_SRC_PATH, O_RDWR | O_CREAT, 0664);
 	fd_dest   = SAFE_OPEN(FILE_DEST_PATH, O_RDWR | O_CREAT, 0664);
 	fd_rdonly = SAFE_OPEN(FILE_RDONL_PATH, O_RDONLY | O_CREAT, 0664);
-	fd_mnted  = SAFE_OPEN(FILE_MNTED_PATH, O_RDWR | O_CREAT, 0664);
 	fd_dir    = SAFE_OPEN(FILE_DIR_PATH, O_DIRECTORY);
 	fd_closed = -1;
 	fd_append = SAFE_OPEN(FILE_DEST_PATH,
 			O_RDWR | O_CREAT | O_APPEND, 0664);
+	fd_immutable = SAFE_OPEN(FILE_IMMUTABLE_PATH, O_RDWR | O_CREAT, 0664);
+	fd_swapfile = SAFE_OPEN(FILE_SWAP_PATH, O_RDWR | O_CREAT, 0600);
+
+	if (loop_devn == -1)
+		fd_blkdev = SAFE_OPEN(dev_path, O_RDWR, 0600);
+
+	fd_chrdev = SAFE_OPEN(FILE_CHRDEV, O_RDWR, 0600);
+	fd_fifo = SAFE_OPEN(FILE_FIFO, O_RDWR, 0600);
+
+	SAFE_WRITE(1, fd_src, CONTENT, CONTSIZE);
+	close(fd_src);
+	fd_src = SAFE_OPEN(FILE_SRC_PATH, O_RDONLY, 0664);
+	fd_dup = SAFE_OPEN(FILE_SRC_PATH, O_WRONLY|O_CREAT, 0666);
+
+	fd_copy = SAFE_OPEN(FILE_COPY_PATH, O_RDWR | O_CREAT | O_TRUNC, 0664);
+	chattr_i_nsup = run_command("chattr", "+i", FILE_IMMUTABLE_PATH);
+
+	if (!tst_fs_has_free(".", sysconf(_SC_PAGESIZE) * 10, TST_BYTES)) {
+		tst_res(TCONF, "Insufficient disk space to create swap file");
+		swap_nsup = 3;
+		return;
+	}
+
+	if (tst_fill_file(FILE_SWAP_PATH, 0, sysconf(_SC_PAGESIZE), 10) != 0) {
+		tst_res(TCONF, "Failed to create swapfile");
+		swap_nsup = 4;
+		return;
+	}
 
-	SAFE_WRITE(1, fd_src,  CONTENT,  CONTSIZE);
+	swap_nsup = run_command("mkswap", FILE_SWAP_PATH, NULL);
+	swap_nsup = run_command("swapon", FILE_SWAP_PATH, NULL);
 }
 
 static struct tst_test test = {
@@ -113,6 +218,6 @@  static struct tst_test test = {
 	.needs_root = 1,
 	.mount_device = 1,
 	.mntpoint = MNTPOINT,
-	.dev_fs_type = "ext4",
+	.all_filesystems = 1,
 	.test_variants = TEST_VARIANTS,
 };