little testing programs for NFSv4.2

Rick Macklem <[email protected]>
Newsgroups gmane.ietf.nfsv4
Message-ID <YQBPR0101MB1652D95D2F3EF78E18AB2404DD900@YQBPR0101MB1652.CANPRD01.PROD.OUTLOOK.COM>
Hi,

Just in case anyone is interested, I've attached a couple of little test
programs I use for NFSv4.2 (SEEK_DATA/SEEK_HOLE and COPY) that
I've done a hackish port to Linux of.

testsparse-linux.c seems to work ok, but testcfr-linux.c fails pretty
quickly, since the client doesn't recognize that the file size has
increased, due to the COPY.

rick
ps: Both take to file names as arguments.

_______________________________________________
nfsv4 mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/nfsv4
testcfr-linux.c (text/plain, 6.3 KB)
#define	_LARGEFILE64_SOURCE 1
#define	_GNU_SOURCE 1
#define	_FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <inttypes.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <unistd.h>

static char junkbuf[128 * 1024];
#define	TESTSIZ		7
struct item {
	loff_t	seekoff;
	loff_t	seekout;
	loff_t	xfer;
} list[TESTSIZ] = {
	{ 0,	0,	0 },
	{ 256 * 1024, 256 * 1024, 5 },
	{ 256 * 1024, 256 * 1024, 4 },
	{ 256 * 1024, 256 * 1024, 8 },
	{ 256 * 1024, 256 * 1024, 9 },
	{ 256 * 1024, 256 * 1024, 256 * 1024 + 8 },
	{ 0,	256 * 1024, 8 },
};

/*
 * Write xfer bytes into outfd.
 */
static void
junk_write(int outfd, loff_t xfer)
{
	size_t len;
	ssize_t outsiz;

	do {
		if (xfer > sizeof(junkbuf))
			len = sizeof(junkbuf);
		else
			len = xfer;
		outsiz = write(outfd, junkbuf, len);
		if (outsiz != len)
			err(1, "Can't write junk");
		xfer -= outsiz;
	} while (xfer > 0);
}

/* Compare the two files for same data. */
static void
comp_files(int infd, int outfd, loff_t seekoff, loff_t seekout, loff_t xfer)
{
	char buf[128 * 1024], buf2[128 * 1024];
	ssize_t insiz, outsiz;

	if (seekoff == seekout) {
		lseek64(infd, 0, SEEK_SET);
		lseek64(outfd, 0, SEEK_SET);
		xfer = 0;
	} else {
		lseek64(infd, seekoff, SEEK_SET);
		lseek64(outfd, seekout, SEEK_SET);
	}
	do {
		insiz = read(infd, buf, sizeof(buf));
		if (insiz < 0)
			err(1, "Can't read infd");
		outsiz = read(outfd, buf2, sizeof(buf2));
		if (outsiz < 0)
			err(1, "Can't read outfd");
		if (xfer == 0) {
			if (insiz < outsiz)
				errx(1, "Premature EOF on infd");
			if (outsiz < insiz)
				errx(1, "Premature EOF on outfd");
		} else {
			if (insiz > outsiz)
				insiz = outsiz;
			if (insiz > xfer)
				insiz = xfer;
		}
		if (insiz > 0 && memcmp(buf, buf2, insiz) != 0)
			errx(1, "File data not same");
		if (xfer > 0) {
			xfer -= insiz;
			if (xfer == 0)
				insiz = 0;
		}
	} while (insiz > 0);
}

/*
 * Copy a file range from infd to outfd.
 */
static void
copy_range(int infd, int outfd, loff_t xfer)
{
	size_t len;
	ssize_t ret;

	while (xfer > 0) {
		if (xfer > INT_MAX)
			len = INT_MAX;
		else
			len = xfer;
		ret = copy_file_range(infd, NULL, outfd, NULL, len, 0);
		if (ret <= 0)
			err(1, "Copy range failed!");
		xfer -= ret;
	}
}

int
main(int argc, char *argv[])
{
	int i, infd, j, outfd, ret;
	struct stat st, outst;
	loff_t seekoff, seekout, xfer;
	bool check_alloc;
	char cp;

	if (argc != 3)
		errx(1, "Usage: testcfr <infile> <outfile>");
	/* Fill in junk_buf with the alphabet over and over and over again. */
	cp = 'a';
	for (i = 0; i < sizeof(junkbuf); i++) {
		junkbuf[i] = cp++;
		if (cp > 'z')
			cp = 'a';
	}
	infd = open(argv[1], O_CREAT | O_RDWR, 0644);
	if (infd < 0)
		err(1, "can't open %s", argv[1]);
	outfd = open(argv[2], O_CREAT | O_RDWR, 0644);
	if (outfd < 0)
		err(1, "can't create %s", argv[2]);

	seekoff = 0;
	/*
	 * Create the input file as a sparse file and then copy file ranges
	 * of it to the output file and compare the two files.
	 */
	for (i = 0; i < 2; i++) {
		if (i > 0) {
			seekoff = 1024 * 1024 * 1024;
			seekoff *= 5;
			ftruncate(infd, 0);
			ftruncate(outfd, 0);
		}
		lseek64(infd, seekoff, SEEK_SET);
		write(infd, "XXXX", 4);
		lseek64(infd, 256 * 1024, SEEK_CUR);
		write(infd, "YYYY", 4);
		lseek64(infd, 512 * 1024, SEEK_CUR);
		write(infd, "ZZZZ", 4);
#ifdef DOFSYNC
		fsync(infd);
#endif

		lseek64(infd, 0, SEEK_SET);
		lseek64(outfd, 0, SEEK_SET);
		if (fstat(infd, &st) < 0)
			err(1, "can't fstat %s", argv[1]);
		check_alloc = false;

		if (i == 0) {
			/* Test invalid arguments. */
			ret = copy_file_range(infd, NULL, outfd, NULL, 0, 0);
			printf("zero length copy ret=%d\n", ret);
			fflush(stdout);
			seekoff = 0;
			seekout = 100;
			ret = copy_file_range(infd, &seekoff, infd, &seekout,
			    1, 0);
			if (ret >= 0) {
				printf("Copy of non-overlapping byte range "
				    "of same file does not fail ret %d\n", ret);
				fflush(stdout);
			}
			seekoff = seekout = LLONG_MAX;
			ret = copy_file_range(infd, &seekoff, outfd, &seekout,
			    1, 0);
			if (ret >= 0) {
				printf("LLONG_MAX + 1 returns %d\n", ret);
				fflush(stdout);
			}
			seekoff = seekout = LLONG_MAX;
			ret = copy_file_range(infd, &seekoff, outfd, &seekout,
			    INT_MAX, 0);
			if (ret >= 0) {
				printf("Should have found LLONG_MAX plus "
				    "INT_MAX invalid\n");
				fflush(stdout);
			}
			seekoff = seekout = st.st_size - 2;
			ret = copy_file_range(infd, &seekoff, outfd, &seekout,
			    3, 0);
			if (ret >= 0) {
				printf("Exceeded file size by 1 byte returns "
				    "%d instead of failing with EINVAL\n", ret);
				fflush(stdout);
			}
			seekoff = seekout = st.st_size - 2;
			ret = copy_file_range(infd, &seekoff, outfd, &seekout,
			    2, 0);
			if (ret != 2) {
				printf("Copy of 2 bytes should work\n");
				fflush(stdout);
			}
			for (j = 0; j < TESTSIZ; j++) {
				lseek64(infd, list[j].seekoff, SEEK_SET);
				lseek64(outfd, list[j].seekout, SEEK_SET);
				if (list[j].xfer == 0)
					list[j].xfer = st.st_size -
					    list[j].seekoff;
				copy_range(infd, outfd, list[j].xfer);
#ifdef DOFSYNC
				fsync(outfd);
#endif
		
				/* Compare infd with outfd. */
				comp_files(infd, outfd, list[j].seekoff,
				    list[j].seekout, list[j].xfer);
			}
		}
		for (j = 0; j < 60; j++) {
			if ((j % 6) == 0) {
				seekoff = 0;
				xfer = st.st_size;
				ftruncate(outfd, 0);
			} else {
				seekoff = random();
				seekoff *= 4;
				if (seekoff <= 0)
					seekoff = 128 * 1024;
				seekoff %= st.st_size / 2;
				xfer = random();
				xfer *= 4;
				if (xfer <= 0 || xfer > st.st_size - seekoff)
					xfer = st.st_size - seekoff;

				if ((j % 2) == 0) {
					ftruncate(outfd, seekoff);
					xfer = st.st_size - seekoff;
				} else {
					lseek64(outfd, seekoff, SEEK_SET);
					junk_write(outfd, xfer);
				}
			}
			printf("seekoff=%jd xfer=%jd\n", (intmax_t)seekoff,
			    (intmax_t)xfer);
			fflush(stdout);
			lseek64(infd, seekoff, SEEK_SET);
			lseek64(outfd, seekoff, SEEK_SET);
			copy_range(infd, outfd, xfer);
#ifdef DOFYSNC
			fsync(outfd);
#endif

			/* Compare infd with outfd. */
			comp_files(infd, outfd, seekoff, seekoff, 0);
			if (check_alloc && seekoff == 0) {
				if (fstat(outfd, &outst) < 0)
					err(1, "can't fstat %s", argv[2]);
				if (st.st_blocks != outst.st_blocks)
					printf("allocation not same");
			}
		}
	}
}
testsparse-linux.c (text/plain, 3 KB)
#define	_LARGEFILE64_SOURCE 1
#define	_GNU_SOURCE 1
#define	_FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <inttypes.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <unistd.h>

static char inbuf[10 * 1024 * 1024], outbuf[1024 * 1024];

/* Compare the two files for same data. */
static void
comp_files(int infd, int outfd)
{
	ssize_t insiz, outsiz;

	lseek64(infd, 0, SEEK_SET);
	lseek64(outfd, 0, SEEK_SET);
	do {
		insiz = read(infd, inbuf, sizeof(outbuf));
		if (insiz < 0)
			err(1, "Can't read infd");
		outsiz = read(outfd, outbuf, sizeof(outbuf));
		if (outsiz < 0)
			err(1, "Can't read outfd");
		if (insiz != outsiz)
			err(1, "premature EOF");
		if (insiz > 0 && memcmp(inbuf, outbuf, insiz) != 0)
			errx(1, "File data not same");
	} while (insiz > 0);
	printf("Files have same data\n");
}

int
main(int argc, char *argv[])
{
	int i, infd, outfd;
	struct stat inst, outst;
	loff_t seekdata, seekhole;
	uint64_t xfer, offpos;
	size_t len;
	ssize_t rsiz;
	char cp;

	if (argc != 3)
		errx(1, "Usage: testsparse <infile> <outfile>");
	/* Fill in inbuf with the alphabet over and over and over again. */
	cp = 'a';
	for (i = 0; i < sizeof(inbuf); i++) {
		inbuf[i] = cp++;
		if (cp > 'z')
			cp = 'a';
	}
	infd = open(argv[1], O_CREAT | O_RDWR, 0644);
	if (infd < 0)
		err(1, "can't open %s", argv[1]);
	outfd = open(argv[2], O_CREAT | O_RDWR, 0644);
	if (outfd < 0)
		err(1, "can't create %s", argv[2]);

	/* First, create the sparse file. */
	xfer = 1024 * 1024 * 1024;
	xfer *= 5;
	printf("xfer=%jd\n", (intmax_t)xfer);
	for (offpos = 0; offpos < xfer; offpos += 101 * 1024 * 1024) {
		printf("xfer=%jd offpos=%jd\n", (intmax_t)xfer,
		    (intmax_t)offpos);
		seekdata = lseek64(infd, 100 * 1024 * 1024, SEEK_CUR);
		printf("lseek64=%jd\n", (intmax_t)seekdata);
		i = write(infd, inbuf, sizeof(inbuf));
		printf("write=%d\n", i);
	}
	lseek64(infd, 0, SEEK_SET);

	/* Now copy infd to outfd, skipping over holes. */
	seekhole = 0;
	do {
		seekdata = lseek64(infd, seekhole, SEEK_DATA);
		if (seekdata >= 0) {
			seekhole = lseek64(infd, seekdata, SEEK_HOLE);
			lseek64(infd, seekdata, SEEK_SET);
			lseek64(outfd, seekdata, SEEK_SET);
			xfer = seekhole - seekdata;
			printf("xfer=%jd seekdata=%jd seekhole=%jd\n",
			    (intmax_t)xfer, (intmax_t)seekdata,
			    (intmax_t)seekhole);
			while (xfer > 0) {
				if (xfer > SSIZE_MAX)
					len = SSIZE_MAX;
				else
					len = xfer;
				rsiz = copy_file_range(infd, NULL, outfd, NULL,
				    len, 0);
				xfer -= rsiz;
			}
		}
	} while (seekdata >= 0);

	/* Now, compare the files and check their storage sizes. */
	printf("Comparing %s with %s\n", argv[1], argv[2]);
	comp_files(infd, outfd);
	if (fstat(infd, &inst) < 0)
		err(1, "can't fstat %s", argv[1]);
	if (fstat(outfd, &outst) < 0)
		err(1, "can't fstat %s", argv[2]);
	if (inst.st_blocks != outst.st_blocks)
		printf("Files do not have same storage allocation\n");
	else
		printf("File have same storage allocation\n");
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.