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"

Reply via email to