[LTP] [PATCH v2] syscalls: add new test for copy_file_range(2)

Jan Stancek jstancek@redhat.com
Wed Apr 19 13:55:30 CEST 2017


----- Original Message -----
> Signed-off-by: Li Wang <liwang@redhat.com>
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <errno.h>
> +#include "tst_test.h"
> +#include "tst_safe_stdio.h"
> +#include "linux_syscall_numbers.h"
> +
> +#define TEST_FILE_1 "copy_file_range_ltp01.txt"
> +#define TEST_FILE_2 "copy_file_range_ltp02.txt"
> +#define STR "abcdefghijklmnopqrstuvwxyz12345\n"
> +
> +static size_t len1 = 1;
> +static size_t len2;       /* stat.st_size */
> +static size_t len3;       /* stat.st_size - 1 */
> +static size_t page_size1; /* pagesize - 1 */
> +static size_t page_size2; /* pagesize     */
> +static size_t page_size3; /* pagesize + 1 */
> +
> +static struct tcase {
> +	loff_t *off_in;
> +	loff_t *off_out;
> +	size_t *len;
> +} tcases[] = {
> +	{NULL, NULL, &len1}, /* NULL, NULL, 1 */
> +	{NULL, NULL, &len2}, /* NULL, NULL, stat.st_size */
> +	{(loff_t *)&len3,             (loff_t *)&len3,      &len1}, /* stat.st_size
> - 1, stat.st_size - 1, 1 */
> +	{(loff_t *)&page_size1, (loff_t *)&page_size1, &page_size1}, /* pagesize -
> 1, pagesize - 1, pagesize - 1 */
> +	{(loff_t *)&page_size2, (loff_t *)&page_size2, &page_size2}, /* pagesize,
> pagesize, pagesize */
> +	{(loff_t *)&page_size3, (loff_t *)&page_size3, &page_size3}, /* pagesize +
> 1, pagesize + 1, pagesize + 1 */
> +};

Hi,

With -m32 and -D_FILE_OFFSET_BITS=64 you're in trouble, because you are
treating (recasting) pointer to 4 bytes as pointer to 8 bytes.

Make page_size[123] off_t and avoid pointer casts.

> +
> +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 tst_syscall(__NR_copy_file_range, fd_in, off_in, fd_out,
> +			off_out, len, flags);
> +}

I'd use tst_syscall() directly. If you define copy_file_range
won't that create conflict when glibc defines it too?

> +
> +static void setup(void)
> +{
> +	int i, fd;
> +	struct stat stat;
> +
> +	page_size2 = getpagesize();
> +	page_size1 = page_size2 - 1;
> +	page_size3 = page_size2 + 1;
> +
> +	fd = SAFE_OPEN(TEST_FILE_1, O_RDWR | O_CREAT, 0664);
> +	/* Writing 1024 KB of random data into this file [32 * 32768 = 1048576] */

It doesn't look very random :-). Anyway, do we need 1MB? Seems like
page_size * 4 would suffice for all cases.

> +	for (i = 0; i < 32768; i++)
> +		SAFE_WRITE(1, fd, STR, strlen(STR));
> +
> +	SAFE_FSTAT(fd, &stat);
> +	len2 = stat.st_size;
> +	len3 = len2 - 1;
> +
> +	SAFE_CLOSE(fd);
> +}
> +
> +static void copy_file_range_verify(unsigned int i)
> +{
> +	int fd_in, fd_out;
> +	loff_t off_in_ori = 0;
> +	loff_t off_out_ori = 0;
> +
> +	struct tcase *tc = &tcases[i];
> +	loff_t len = *(tc->len);
> +
> +	if (tc->off_in) {
> +		/*
> +		 * off_in/off_out will be changed if it is not NULL,
> +		 * here save the original value first
> +		 */
> +		off_in_ori = *(tc->off_in);
> +		off_out_ori = *(tc->off_out);
> +	}
> +	loff_t len_ori = len;
> +
> +	fd_in = SAFE_OPEN(TEST_FILE_1, O_RDONLY);
> +	fd_out = SAFE_OPEN(TEST_FILE_2, O_CREAT | O_WRONLY | O_TRUNC, 0644);
> +
> +	/*
> +	 * copy_file_range() will return the number of bytes copied between files.
> +	 * This could be less than the length originally requested.
> +	 */
> +	do {
> +		TEST(copy_file_range(fd_in, tc->off_in, fd_out, tc->off_out, len, 0));
> +		if (TEST_RETURN == -1) {
> +			tst_res(TFAIL | TTERRNO, "copy_file_range() failed");
> +			SAFE_CLOSE(fd_in);
> +			SAFE_CLOSE(fd_out);
> +			return;
> +		}
> +
> +		len -= TEST_RETURN;
> +	} while (len > 0);
> +
> +	/* Compare these two file contents */
> +	FILE *fp1, *fp2;
> +	int ch1, ch2;
> +	loff_t count = 0;
> +
> +	fp1 = SAFE_FOPEN(TEST_FILE_1, "r");
> +	fseek(fp1, off_in_ori, SEEK_SET);
> +	fp2 = SAFE_FOPEN(TEST_FILE_2, "r");
> +	fseek(fp2, off_out_ori, SEEK_SET);
> +
> +	do {
> +		ch1 = getc(fp1);
> +		ch2 = getc(fp2);
> +		count++;
> +	} while ((count < len_ori) && (ch1 == ch2));
> +
> +	if (ch1 == ch2) {

I'd put TPASS here, that says content matches.

> +		/*
> +		 * If off_in is NULL, the file offset is adjusted by the number of bytes
> copied.
> +		 * If off_in is not NULL, the file offset of fd_in is not changed, but
> off_in is
> +		 * adjusted appropriately.
> +		 */
> +		if (!tc->off_in) {
> +			if (lseek(fd_in, 0, SEEK_CUR) == lseek(fd_out, 0, SEEK_CUR))

SAFE_LSEEK

> +				tst_res(TPASS, "copy_file_range() returned %ld", TEST_RETURN);

and this TPASS can say that offsets are as expected.

> +			else
> +				tst_res(TFAIL,"these two files offset are not same");
> +		} else {
> +			if (*(tc->off_in) == (off_in_ori + len_ori))
> +				tst_res(TPASS, "copy_file_range() returned %ld", TEST_RETURN);

same here

Regards,
Jan

> +			else
> +				tst_res(TFAIL,"these two file off_in have no adjusted");
> +		}
> +	} else {
> +		tst_res(TFAIL,"these two file contents are not match");
> +	}
> +
> +	SAFE_FCLOSE(fp1);
> +	SAFE_FCLOSE(fp2);
> +	SAFE_CLOSE(fd_in);
> +	SAFE_CLOSE(fd_out);
> +}
> +
> +static struct tst_test test = {
> +	.tid = "copy_file_range01",
> +	.setup = setup,
> +	.needs_tmpdir = 1,
> +	.tcnt = ARRAY_SIZE(tcases),
> +	.test = copy_file_range_verify,
> +};
> --
> 2.9.3
> 
> 


More information about the ltp mailing list