From: Josef Bacik Subject: [TEST] test the seek_hole/seek_data functionality Date: Thu, 5 May 2011 16:16:59 -0400 Message-ID: <1304626619-1588-4-git-send-email-josef@redhat.com> References: <1304626619-1588-1-git-send-email-josef@redhat.com> To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-btrfs@vger.kernel.org, linux-ext4@vger.kernel.org, viro@ZenIV.linux.org.uk Return-path: In-Reply-To: <1304626619-1588-1-git-send-email-josef@redhat.com> Sender: linux-kernel-owner@vger.kernel.org List-Id: linux-ext4.vger.kernel.org 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 #include #include #include #include #include #include #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, pos, SEEK_HOLE); if (pos != -1 && errno != ENXIO) { ERROR("Seeking hole didn't return error"); 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; }