This is my very rough tester for testing seek_hole/seek_data.  Please look over
it and make sure we all agree that the semantics are correct.  My btrfs patch
passes with this and ext3 passes as well.  I still have to added fallocate() to
it, but for now this seems to cover most of the corner cases.  Thanks,

Josef

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define SEEK_HOLE       3
#define SEEK_DATA       4

#define ERROR(str)      \
        fprintf(stderr, "%s: pos=%lu, errno=%d\n", str, pos, errno)

static int reset_file(int fd)
{
        int ret;

        ret = ftruncate(fd, 0);
        if (ret < 0) {
                fprintf(stderr, "Truncate failed: %d\n", errno);
                return 1;
        }

        return 0;
}

int main(int argc, char **argv)
{
        char buf[4096 * 4];
        ssize_t bytes;
        off_t pos;
        int prealloc_is_hole = 0;
        int whole_file_is_data = 0;
        int ret;
        int i;
        int fd;

        fd = open("testfile", O_RDWR|O_CREAT|O_TRUNC, 0644);
        if (fd < 0) {
                fprintf(stderr, "Failed to open testfile: %d\n", errno);
                return 1;
        }

        /* Empty file */
        printf("Testing an empty file\n");
        pos = lseek(fd, 0, SEEK_DATA);
        if (pos != -1) {
                if (errno == EINVAL) {
                        fprintf(stderr, "Kernel does not support seek "
                                "hole/data\n");
                        close(fd);
                        return 1;
                }
                if (errno != ENXIO)
                        ERROR("Seek data did not return a proper error");
                close(fd);
                return 1;
        }

        pos = lseek(fd, 0, SEEK_HOLE);
        if (pos != -1 && errno != ENXIO) {
                ERROR("Seek hole did not return a proper error");
                close(fd);
                return 1;
        }

        memset(&buf, 'a', 4096 * 4);
        /*
         * All data file
         */
        printf("Testing a normal data filled file\n");
        for (i = 0; i < 4; i++) {
                bytes = write(fd, &buf, 4096);
                if (bytes < 4096) {
                        fprintf(stderr, "Failed to write to testfile: %d\n",
                                errno);
                        close(fd);
                        return 1;
                }
        }

        pos = lseek(fd, 0, SEEK_HOLE);
        if (pos != (4096 * 4) || pos == -1) {
                ERROR("Seek hole failed to dump us out at the end of the file");
                close(fd);
                return 1;
        }

        pos = lseek(fd, 0, SEEK_DATA);
        if (pos != 0) {
                ERROR("Seek data failed to dump us out at the beginning of the"
                      " file");
                close(fd);
                return 1;
        }

        /*
         * File with a hole at the front and data at the end
         */
        printf("Testing file with hole at the start and data in the rest\n");
        if (reset_file(fd)) {
                close(fd);
                return 1;
        }

        bytes = pwrite(fd, &buf, 4096 * 3, 4096);
        if (bytes < (4096 * 3)) {
                fprintf(stderr, "Failed to write to testfile: %d\n");
                close(fd);
                return 1;
        }

        pos = lseek(fd, 0, SEEK_HOLE);
        if (pos != 0 && pos != (4096 * 4)) {
                ERROR("Seek hole failed to return 0");
                close(fd);
                return 1;
        } else if (pos == (4096 * 4)) {
                whole_file_is_data = 1;
                printf("Current file system views treats the entire file as "
                       "data\n");
        }

        pos = lseek(fd, 0, SEEK_DATA);
        if (pos != 4096 || (pos != 0 && whole_file_is_data)) {
                if (whole_file_is_data)
                        ERROR("Seek data failed to return 0");
                else
                        ERROR("Seek data failed to return 4096");
                close(fd);
                return 1;
        }

        if (whole_file_is_data) {
                pos = lseek(fd, 1, SEEK_DATA);
                if (pos != -1 && errno != ENXIO) {
                        ERROR("Seek data failed to retun an error");
                        close(fd);
                        return 1;
                }
        }
        /*
         * File with a hole at the end and data at the beginning
         */
        printf("Testing file with hole at the end and data at the beginning\n");
        if (reset_file(fd)) {
                close(fd);
                return 1;
        }

        ret = ftruncate(fd, 4096 * 4);
        if (ret < 0) {
                fprintf(stderr, "Truncate failed: %d\n", errno);
                close(fd);
                return 1;
        }

        pwrite(fd, &buf, 4096 * 3, 0);
        if (bytes < (4096 * 3)) {
                fprintf(stderr, "Failed to write to testfile: %d\n", errno);
                close(fd);
                return 1;
        }

        pos = lseek(fd, 0, SEEK_HOLE);
        if (pos != (4096 * 3) || (pos != (4096 * 4) && whole_file_is_data)) {
                ERROR("Seeking hole didn't work right");
                close(fd);
                return 1;
        }

        if (whole_file_is_data) {
                pos = lseek(fd, 4096, SEEK_DATA);
                if (pos != 4096) {
                        ERROR("Seeking data didn't return the same offset");
                        close(fd);
                        return 1;
                }
                printf("No more tests to run since we treat the whole file as "
                       "data\n");
                goto out;
        }

        pos = lseek(fd, pos, SEEK_HOLE);
        if (pos != (4096 * 3)) {
                ERROR("Seek hole didn't return same position");
                close(fd);
                return 1;
        }

        pos = lseek(fd, pos+1, SEEK_HOLE);
        if (pos != (4096 * 4)) {
                ERROR("Seek hole didn't return the end of the file");
                close(fd);
                return 1;
        }

        pos = lseek(fd, pos, SEEK_DATA);
        if (pos != -1 && errno != ENXIO) {
                ERROR("Seek data didn't return ENXIO");
                close(fd);
                return 1;
        }

        /*
         * Hole - Data - Hole - Data file
         */
        printf("Testing file [Hole][Data][Hole][Data]\n");
        if (reset_file(fd)) {
                close(fd);
                return 1;
        }

        ret = ftruncate(fd, 4096 * 4);
        if (ret < 0) {
                fprintf(stderr, "ftruncate failed: %d\n", errno);
                close(fd);
                return 1;
        }

        bytes = pwrite(fd, &buf, 4096, 4096);
        if (bytes < 4096) {
                fprintf(stderr, "Failed to write: %d\n", errno);
                close(fd);
                return 1;
        }

        bytes = pwrite(fd, &buf, 4096, 4096 * 3);
        if (bytes < 4096) {
                fprintf(stderr, "Failed to write: %d\n", errno);
                close(fd);
                return 1;
        }

        pos = lseek(fd, 0, SEEK_DATA);
        if (pos != 4096) {
                ERROR("Seek data did not return 4096");
                close(fd);
                return 1;
        }

        pos = lseek(fd, pos, SEEK_HOLE);
        if (pos != (4096 * 2)) {
                ERROR("Seek hole did not return 4096*2");
                close(fd);
                return 1;
        }

        pos = lseek(fd, pos, SEEK_DATA);
        if (pos != (4096 * 3)) {
                ERROR("Seek data did not return 4096*3");
                close(fd);
                return 1;
        }
out:
        close(fd);
        return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to