I have a little program for testing the copy_file_range(2) syscall I've been working on. (The current version is attached, in case anyone is interested.)
It take a few minutes to run on a slow system and uses about 6Gbytes of disk space for the file system the output file is on. (It creates 2 files to use for testing. The first one is sparse and the second is copied from it, but grows as different byte ranges get copied, since "punching holes" is done via writes of 0 bytes.) My question is.. What needs to be done to include this in FreeBSD? I see some stuff under head/tests. I could probably figure out what the macros in those files are, but I can only see tests to see if arguments are valid and similar. As such, I'm not sure if this is the correct place for a test like this? Thanks for any help with this, rick
#include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <err.h> #include <unistd.h> static char junkbuf[128 * 1024]; /* * Write xfer bytes into outfd. */ static void junk_write(int outfd, off_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, off_t seekoff, off_t seekout, off_t xfer) { char buf[128 * 1024], buf2[128 * 1024]; ssize_t insiz, outsiz; if (seekoff == seekout) { lseek(infd, 0, SEEK_SET); lseek(outfd, 0, SEEK_SET); xfer = 0; } else { lseek(infd, seekoff, SEEK_SET); lseek(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 > 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, off_t xfer) { size_t len; ssize_t ret; while (xfer > 0) { if (xfer > SIZE_T_MAX) len = SIZE_T_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; struct stat st, outst; off_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 *= 6; ftruncate(infd, 0); ftruncate(outfd, 0); } lseek(infd, seekoff, SEEK_SET); write(infd, "XXXX", 4); lseek(infd, 256 * 1024, SEEK_CUR); write(infd, "YYYY", 4); lseek(infd, 512 * 1024, SEEK_CUR); write(infd, "ZZZZ", 4); lseek(infd, 0, SEEK_SET); lseek(outfd, 0, SEEK_SET); if (fstat(infd, &st) < 0) err(1, "can't fstat %s", argv[1]); check_alloc = false; if (st.st_size < SSIZE_MAX) check_alloc = true; for (j = 0; j < 10; j++) { if (j == 0) { seekout = seekoff = 0; xfer = st.st_size; } 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; seekout = seekoff; if (j == 9) { seekout = seekoff / 2; lseek(outfd, seekout, SEEK_SET); junk_write(outfd, xfer); } else if ((j % 2) == 0) { ftruncate(outfd, seekout); xfer = st.st_size - seekoff; } else { lseek(outfd, seekout, SEEK_SET); junk_write(outfd, xfer); } } printf("seekoff=%qd seekout=%qd xfer=%qd\n", seekoff, seekout, xfer); lseek(infd, seekoff, SEEK_SET); lseek(outfd, seekout, SEEK_SET); copy_range(infd, outfd, xfer); /* Compare infd with outfd. */ comp_files(infd, outfd, seekoff, seekout, xfer); 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) errx(1, "allocation not same"); } } } }
_______________________________________________ freebsd-current@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/freebsd-current To unsubscribe, send any mail to "freebsd-current-unsubscr...@freebsd.org"