diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 202fa639f..54549fa24 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -213,6 +213,7 @@ TST_NOFILE := \ pidns03 \ config_inotify_irmap \ pipe03 \ + unlink_multiple_largefiles \ # jobctl00 \ include ../Makefile.inc diff --git a/test/zdtm/static/unlink_multiple_largefiles.c b/test/zdtm/static/unlink_multiple_largefiles.c new file mode 100644 index 000000000..c6400b4ff --- /dev/null +++ b/test/zdtm/static/unlink_multiple_largefiles.c @@ -0,0 +1,263 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "zdtmtst.h" + + +#define FSIZE 0x3B600000ULL +#define NFILES 10 +#define BUFSIZE (1<<20) + +const char *test_doc = "C/R of ten big (951MiB) unlinked files in root dir"; +const char *test_author = "Vitaly Ostrosablin "; + +void create_check_pattern(char *buf, size_t count, unsigned char seed) +{ + int i; + + for (i = 0; i < count; i++) + buf[i] = seed++; +} + +struct fiemap *read_fiemap(int fd) +{ + test_msg("Obtaining fiemap for fd %d\n", fd); + struct fiemap *fiemap; + int extents_size; + + fiemap = malloc(sizeof(struct fiemap)); + if (fiemap == NULL) { + pr_perror("Cannot allocate fiemap"); + return NULL; + } + memset(fiemap, 0, sizeof(struct fiemap)); + + fiemap->fm_length = FIEMAP_MAX_OFFSET; + fiemap->fm_start = 0; + fiemap->fm_flags = 0; + fiemap->fm_extent_count = 0; + + if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) { + pr_perror("FIEMAP ioctl failed"); + return NULL; + } + + extents_size = sizeof(struct fiemap_extent) * fiemap->fm_mapped_extents; + + fiemap = realloc(fiemap,sizeof(struct fiemap) + extents_size); + if (fiemap == NULL) { + pr_perror("Cannot resize fiemap"); + return NULL; + } + memset(fiemap->fm_extents, 0, extents_size); + + fiemap->fm_extent_count = fiemap->fm_mapped_extents; + fiemap->fm_mapped_extents = 0; + + if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) { + pr_perror("fiemap ioctl() failed"); + return NULL; + } + test_msg("Debugkillme: %x\n", fiemap->fm_mapped_extents); + + return fiemap; +} + +void check_extent_map(struct fiemap *map) +{ + int i; + unsigned long long datasize = 0; + unsigned long long holesize = 0; + + test_msg("Verifying extent map...\n"); + + for (i = 0; i < map->fm_mapped_extents; i++) { + test_msg("Extent %d, start %llx, length %llx\n", + i, + map->fm_extents[i].fe_logical, + map->fm_extents[i].fe_length); + + if (i == 0) + holesize = map->fm_extents[i].fe_logical; + datasize += map->fm_extents[i].fe_length; + } + if (holesize != FSIZE) { + pr_err("Unexpected hole size %llx != %llx\n", holesize, + (unsigned long long) FSIZE); + exit(1); + } + if (datasize != BUFSIZE) { + pr_err("Unexpected data size %llx != %llx\n", datasize, + (unsigned long long) BUFSIZE); + exit(1); + } +} + +void compare_file_content(int fildes, int seed) +{ + char ebuf[BUFSIZE]; + char rbuf[BUFSIZE]; + char linkpath[PATH_MAX]; + int fd; + struct fiemap *fiemap; + + ssprintf(linkpath, "/proc/self/fd/%d", fildes); + + fd = open(linkpath, O_RDONLY | O_LARGEFILE); + if (fd < 0) { + pr_perror("Cannot open unlinked file %s", linkpath); + exit(1); + } + + memset(ebuf, 0, BUFSIZE); + + fiemap = read_fiemap(fd); + check_extent_map(fiemap); + free(fiemap); + + lseek64(fd, FSIZE, SEEK_SET); + + create_check_pattern(ebuf, BUFSIZE, seed); + + if (read(fd, rbuf, BUFSIZE) != BUFSIZE) { + pr_perror("Cannot read %i bytes from file", BUFSIZE); + goto failed; + } + + if (memcmp(&ebuf, &rbuf, BUFSIZE)) { + pr_err("Control Block: Data mismatch detected\n"); + goto failed; + } + + close(fd); + return; +failed: + close(fd); + exit(1); +} + +void read_proc_fd_link(int fd, char *buf) +{ + ssize_t res; + char linkpath[PATH_MAX]; + + ssprintf(linkpath, "/proc/%d/fd/%d", getpid(), fd); + + res = readlink(linkpath, buf, PATH_MAX - 1); + buf[res] = 0; + if (res < 0) { + pr_perror("Cannot read fd symlink %s", linkpath); + exit(1); + } +} + +int create_unlinked_file(int fileno) +{ + int fd; + char buf[BUFSIZE]; + char fnm[PATH_MAX]; + + ssprintf(fnm, "/unlinked%d", fileno); + fd = open(fnm, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); + if (fd < 0) { + pr_perror("Cannot create file %s", fnm); + exit(1); + } + test_msg("Created file: %s, fd %d\n", fnm, fd); + + if (lseek64(fd, FSIZE, SEEK_SET) < 0) { + pr_perror("Cannot seek to offset %llx", FSIZE); + goto failed; + } + test_msg("File positioning done, offset=%llx\n", FSIZE); + + create_check_pattern(&buf[0], BUFSIZE, fileno); + if (write(fd, buf, BUFSIZE) != BUFSIZE) { + pr_perror("Cannot write %i bytes to file", BUFSIZE); + goto failed; + } + test_msg("%i bytes written to file\n", BUFSIZE); + + if (unlink(fnm) < 0) { + pr_perror("Cannot unlink file %s", fnm); + goto failed; + } + test_msg("File %s is unlinked\n", fnm); + + return fd; +failed: + unlink(fnm); + close(fd); + return -1; +} + +int main(int argc, char **argv) +{ + int fd[NFILES] = {0}; + char links[NFILES][PATH_MAX]; + char link[PATH_MAX]; + int count = 0; + int tempfd; + + test_init(argc, argv); + + /* We need to create 10 unlinked files, each is around 1GB in size */ + for (count = 0; count < NFILES; count++) { + + test_msg("Creating unlinked file %d/%d\n", count + 1, NFILES); + tempfd = create_unlinked_file(count); + + if (tempfd < 0) { + pr_err("Cannot create unlinked file %d/%d\n", + count + 1, NFILES); + return 1; + } + + memset(&links[count][0], 0, PATH_MAX); + read_proc_fd_link(tempfd, &links[count][0]); + + fd[count] = tempfd; + } + test_msg("Created %d unlinked files\n", NFILES); + + test_daemon(); + test_msg("Test daemonized, PID %d\n", getpid()); + test_waitsig(); + + test_msg("PID %d resumed, doing final checks...\n", getpid()); + + for (count = 0; count < NFILES; count++) { + test_msg("Processing fd #%d (%d)\n", count, fd[count]); + + test_msg("Checking symlink consistency...\n"); + memset(&link[0], 0, PATH_MAX); + read_proc_fd_link(fd[count], &link[0]); + + if (strcmp(&links[count][0], &link[0])) { + pr_err("Symlink target %s has changed to %s\n", + links[count], link); + return 1; + } + + test_msg("Checking file contents...\n"); + compare_file_content(fd[count], count); + + test_msg("Closing file descriptor...\n"); + if (close(fd[count]) == -1) { + pr_perror("Close failed"); + return 1; + } + } + + pass(); + return 0; +} diff --git a/test/zdtm/static/unlink_multiple_largefiles.desc b/test/zdtm/static/unlink_multiple_largefiles.desc new file mode 100644 index 000000000..b4ab1a827 --- /dev/null +++ b/test/zdtm/static/unlink_multiple_largefiles.desc @@ -0,0 +1 @@ +{'flavor': 'ns uns', 'opts': '--ghost-limit 1G'}