This patch add some new test options (direct_io, mmap and fadvise) for stress test.
Signed-off-by: Jiawei Wang <[email protected]> --- tests/erofsstress/stress.c | 459 +++++++++++++++++++++++++++++++++---- 1 file changed, 418 insertions(+), 41 deletions(-) diff --git a/tests/erofsstress/stress.c b/tests/erofsstress/stress.c index 4dfe489..84a665c 100644 --- a/tests/erofsstress/stress.c +++ b/tests/erofsstress/stress.c @@ -17,6 +17,7 @@ #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> +#include <sys/mman.h> #include <time.h> #include <unistd.h> #include <fcntl.h> @@ -27,6 +28,9 @@ #define MAX_SCAN_CHUNKSIZE (256 * 1024) bool superuser; +bool direct_io = false; +bool mmap_flag = false; +bool fadvise_flag = false; unsigned int nprocs = 1, loops = 1, r_seed; sig_atomic_t should_stop = 0; @@ -114,6 +118,8 @@ int drop_file_cache(int fd, int mode) struct fent { char *subpath; + void *fd_ptr; + void *chkfd_ptr; int fd, chkfd; }; @@ -282,60 +288,276 @@ static int testdir_fd = -1, chkdir_fd = -1; int tryopen(struct fent *fe) { + int err; + uint64_t filesize; + if (fe->fd < 0) { - fe->fd = openat(testdir_fd, fe->subpath, O_RDONLY); + fe->fd = openat(testdir_fd, fe->subpath, direct_io ? O_RDONLY | O_DIRECT : O_RDONLY); if (fe->fd < 0) return -errno; /* use force_page_cache_readahead for every read request */ posix_fadvise(fe->fd, 0, 0, POSIX_FADV_RANDOM); + + filesize = lseek64(fe->fd, 0, SEEK_END); + if (mmap_flag) { + fe->fd_ptr = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fe->fd, 0); + if (fe->fd_ptr == MAP_FAILED) { + fprintf(stderr, "%s failed mmap\n", __func__); + return -errno; + } + } } - if (chkdir_fd >= 0 && fe->chkfd < 0) - fe->chkfd = openat(chkdir_fd, fe->subpath, O_RDONLY); + if (chkdir_fd >= 0 && fe->chkfd < 0) { + fe->chkfd = openat(chkdir_fd, fe->subpath, direct_io ? O_RDONLY | O_DIRECT : O_RDONLY); + + if (fe->chkfd > 0) { + filesize = lseek64(fe->chkfd, 0, SEEK_END); + if (mmap_flag) { + fe->chkfd_ptr = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fe->chkfd, 0); + if (fe->chkfd_ptr == MAP_FAILED) { + fprintf(stderr, "%s failed mmap\n", __func__); + return -errno; + } + } + } else + fe->chkfd_ptr = NULL; + } return 0; } -int doscan(int fd, int chkfd, uint64_t filesize, uint64_t chunksize) +void mismatch_output(struct fent *ent, uint64_t pos, uint64_t chunksize) +{ + int fd, ret; + ssize_t nread, nread2; + char filename[20]; + char *buf, *chkbuf; + + ret = posix_memalign(&buf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE); + if (ret) { + fprintf(stderr, "posix_memalign failed: %s\n", strerror(ret)); + goto cleanup; + } + nread = pread64(ent->fd, buf, chunksize, pos); + if (nread <= 0) { + fprintf(stderr, "read file failed"); + goto cleanup; + } + + ret = posix_memalign(&chkbuf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE); + if (ret) { + fprintf(stderr, "posix_memalign failed: %s\n", strerror(ret)); + goto cleanup; + } + nread2 = pread64(ent->chkfd, chkbuf, chunksize, pos); + if (nread2 <=0) { + fprintf(stderr, "read file failed"); + goto cleanup; + } + + sprintf(filename, "%d", getpid()); + strcat(filename, "_mismatch"); + fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (fd == -1) { + fprintf(stderr, "error opening file"); + goto cleanup; + } + + ret = write(fd, ent->subpath, strlen(ent->subpath)); + if (ret == -1) { + fprintf(stderr, "error writing file"); + goto cleanup; + } + write(fd, "\n", 1); + + ret = write(fd, buf, nread); + if (ret == -1) { + fprintf(stderr, "error writing file"); + goto cleanup; + } + write(fd, "\n", 1); + ret = write(fd, chkbuf, nread2); + if (ret == -1) { + fprintf(stderr, "error writing file"); + goto cleanup; + } +cleanup: + free(buf); + free(chkbuf); +} + +int doscan(struct fent *ent, uint64_t filesize, uint64_t chunksize) { - static char buf[MAX_SCAN_CHUNKSIZE], chkbuf[MAX_SCAN_CHUNKSIZE]; + char *buf, *chkbuf; uint64_t pos; + int err = 0; printf("doscan(%u): filesize: %llu, chunksize: %llu\n", getpid(), (unsigned long long)filesize, (unsigned long long)chunksize); - + + err = posix_memalign(&buf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE); + if (err) { + fprintf(stderr, "posix_memalign failed: %s\n", strerror(err)); + goto cleanup; + } + + err = posix_memalign(&chkbuf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE); + if (err) { + fprintf(stderr, "posix_memalign failed: %s\n", strerror(err)); + goto cleanup; + } + for (pos = 0; pos < filesize; pos += chunksize) { ssize_t nread, nread2; + + nread = pread64(ent->fd, buf, chunksize, pos); + if (nread <= 0) { + err = -errno; + goto cleanup; + } - nread = pread64(fd, buf, chunksize, pos); - - if (nread <= 0) - return -errno; - - if (nread < chunksize && nread != filesize - pos) - return -ERANGE; + if (nread < chunksize && nread != filesize - pos) { + err = -ERANGE; + goto cleanup; + } - if (chkfd < 0) + if (ent->chkfd < 0) continue; - nread2 = pread64(chkfd, chkbuf, chunksize, pos); - if (nread2 <= 0) - return -errno; + nread2 = pread64(ent->chkfd, chkbuf, chunksize, pos); + if (nread2 <= 0) { + err = -errno; + goto cleanup; + } - if (nread != nread2) - return -EFBIG; + if (nread != nread2) { + err = -EFBIG; + goto cleanup; + } if (memcmp(buf, chkbuf, nread)) { fprintf(stderr, "doscan: %llu bytes mismatch @ %llu\n", (unsigned long long)chunksize, (unsigned long long)pos); + mismatch_output(ent, pos, chunksize); + err = -EBADMSG; + goto cleanup; + } + } + +cleanup: + free(buf); + free(chkbuf); + return err; +} + +int doscan_mmap(struct fent *ent, uint64_t filesize, uint64_t chunksize) +{ + uint64_t pos, nread; + + printf("doscan_mmap(%u): filesize: %llu, chunksize: %llu\n", + getpid(), (unsigned long long)filesize, + (unsigned long long)chunksize); + + if (ent->chkfd >= 0 && lseek(ent->chkfd, 0, SEEK_END) != filesize) + return -EFBIG; + + for (pos = 0; pos < filesize; pos += chunksize) { + + if (pos + chunksize < filesize) + nread = chunksize; + else + nread = filesize - pos; + + if (ent->chkfd < 0) + continue; + + if (memcmp(ent->fd_ptr + pos, ent->chkfd_ptr + pos, nread)) { + fprintf(stderr, "doscan_mmap: %llu bytes mismatch @ %llu\n", + (unsigned long long)chunksize, + (unsigned long long)pos); + mismatch_output(ent, pos, chunksize); return -EBADMSG; } } return 0; } +int doscan_fadvise(struct fent *ent, uint64_t filesize, uint64_t chunksize) +{ + int err; + uint64_t pos, nread; + + printf("doscan_fadvise(%u): filesize: %llu, chunksize: %llu\n", + getpid(), (unsigned long long)filesize, + (unsigned long long)chunksize); + + if (ent->chkfd >= 0 && lseek(ent->chkfd, 0, SEEK_END) != filesize) + return -EFBIG; + + for (pos = 0; pos < filesize; pos += chunksize) { + + if (pos + chunksize < filesize) + nread = chunksize; + else + nread = filesize - pos; + + err = posix_fadvise(ent->fd, pos, nread, POSIX_FADV_WILLNEED); + if (err) { + perror("posix_fadvise"); + return -errno;; + } + + if (ent->chkfd < 0) + continue; + + err = posix_fadvise(ent->chkfd, pos, nread, POSIX_FADV_WILLNEED); + if (err) { + perror("posix_fadvise"); + return -errno; + } + } + return 0; +} + +int doscan_random(struct fent *ent, uint64_t filesize, uint64_t chunksize) +{ + bool flag = false; + int err; + int randnum; + + srand(time(NULL)); + while(true) { + if (flag) + break; + + randnum = rand() % 3 + 1; + switch(randnum) { + case 1: + flag = true; + err = doscan(ent, filesize, chunksize); + break; + case 2: + if (mmap_flag) { + flag = true; + err = doscan_mmap(ent, filesize, chunksize); + } + break; + case 3: + if (fadvise_flag) { + flag = true; + err = doscan_fadvise(ent, filesize, chunksize); + } + break; + default: + break; + } + } + return err; +} + int getdents_f(struct fent *fe) { int dfd; @@ -379,17 +601,30 @@ int readlink_f(struct fent *fe) return 0; } -int read_f(int fd, int chkfd, uint64_t filesize) +int read_f(struct fent *ent, uint64_t filesize) { - static char buf[MAX_CHUNKSIZE], chkbuf[MAX_CHUNKSIZE]; + char *buf, *chkbuf; uint64_t lr, off, len, trimmed; size_t nread, nread2; + int err = 0; lr = ((uint64_t) random() << 32) + random(); off = lr % filesize; len = (random() % MAX_CHUNKSIZE) + 1; trimmed = len; - + + err = posix_memalign(&buf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE); + if (err) { + fprintf(stderr, "posix_memalign failed: %s\n", strerror(err)); + goto cleanup; + } + + err = posix_memalign(&chkbuf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE); + if (err) { + fprintf(stderr, "posix_memalign failed: %s\n", strerror(err)); + goto cleanup; + } + if (off + len > filesize) { uint64_t a = filesize - off + 16 * getpagesize(); @@ -397,44 +632,175 @@ int read_f(int fd, int chkfd, uint64_t filesize) len %= a; trimmed = len <= filesize - off ? len : filesize - off; } - + + if (direct_io) { + off = (((off - 1) >> PAGE_SHIFT) + 1) + << PAGE_SHIFT; + trimmed = len = (((len - 1) >> PAGE_SHIFT) + 1) + << PAGE_SHIFT; + if (!len || off + len > filesize) + goto cleanup; + } + printf("read_f(%u): %llu bytes @ %llu\n", getpid(), - len | 0ULL, off | 0ULL); + len | 0ULL, off | 0ULL); - nread = pread64(fd, buf, len, off); + nread = pread64(ent->fd, buf, len, off); if (nread != trimmed) { fprintf(stderr, "read_f(%d, %u): failed to read %llu bytes @ %llu\n", __LINE__, getpid(), len | 0ULL, off | 0ULL); - return -errno; + err = -errno; + goto cleanup; } - if (chkfd < 0) - return 0; + if (ent->chkfd < 0) + goto cleanup; - nread2 = pread64(chkfd, chkbuf, len, off); + nread2 = pread64(ent->chkfd, chkbuf, len, off); if (nread2 <= 0) { fprintf(stderr, "read_f(%d, %u): failed to read %llu bytes @ %llu\n", __LINE__, getpid(), len | 0ULL, off | 0ULL); - return -errno; + err = -errno; + goto cleanup; } if (nread != nread2) { fprintf(stderr, "read_f(%d, %u): size mismatch %llu bytes @ %llu\n", __LINE__, getpid(), len | 0ULL, off | 0ULL); - return -EFBIG; + mismatch_output(ent, off, len); + err = -EFBIG; + goto cleanup; } if (memcmp(buf, chkbuf, nread)) { fprintf(stderr, "read_f(%d, %u): data mismatch %llu bytes @ %llu\n", __LINE__, getpid(), len | 0ULL, off | 0ULL); + mismatch_output(ent, off, len); + err = -EBADMSG; + goto cleanup; + } + +cleanup: + free(buf); + free(chkbuf); + return err; +} + +int read_f_mmap(struct fent *ent, uint64_t filesize) +{ + uint64_t lr, off, len, trimmed; + + lr = ((uint64_t) random() << 32) + random(); + off = lr % filesize; + len = (random() % MAX_CHUNKSIZE) + 1; + trimmed = len; + + if (off + len > filesize) { + uint64_t a = filesize - off + 16 * getpagesize(); + + if (len > a) + len %= a; + trimmed = len <= filesize - off ? len : filesize - off; + } + + printf("read_f_mmap(%u): %llu bytes @ %llu\n", getpid(), + len | 0ULL, off | 0ULL); + + if (ent->chkfd >= 0 && lseek(ent->chkfd, 0, SEEK_END) != filesize) + return -EFBIG; + + if (ent->chkfd < 0) + return 0; + + if (memcmp(ent->fd_ptr + off, ent->chkfd_ptr + off, trimmed)) { + fprintf(stderr, "read_f_mmap(%d, %u): data mismatch %llu bytes @ %llu\n", + __LINE__, getpid(), len | 0ULL, off | 0ULL); + mismatch_output(ent, off, len); return -EBADMSG; } return 0; } -int testfd(int fd, int chkfd, int mode) +int read_f_fadvise(struct fent *ent, uint64_t filesize) { - const off64_t filesize = lseek64(fd, 0, SEEK_END); + int err; + uint64_t lr, off, len, trimmed; + + lr = ((uint64_t) random() << 32) + random(); + off = lr % filesize; + len = (random() % MAX_CHUNKSIZE) + 1; + trimmed = len; + + if (off + len > filesize) { + uint64_t a = filesize - off + 16 * getpagesize(); + + if (len > a) + len %= a; + trimmed = len <= filesize - off ? len : filesize - off; + } + + printf("read_f_fadvise(%u): %llu bytes @ %llu\n", getpid(), + len | 0ULL, off | 0ULL); + + err = posix_fadvise(ent->fd, off, trimmed, POSIX_FADV_WILLNEED); + if (err) { + perror("posix_fadvise"); + return -errno; + } + + if (ent->chkfd >= 0 && lseek(ent->chkfd, 0, SEEK_END) != filesize) + return -EFBIG; + + if (ent->chkfd < 0) + return 0; + + err = posix_fadvise(ent->chkfd, off, trimmed, POSIX_FADV_WILLNEED); + if (err) { + perror("posix_fadvise"); + return -errno; + } + return 0; +} + +int read_f_random(struct fent * ent, uint64_t filesize) +{ + bool flag = false; + int err; + int randnum; + + srand(time(NULL)); + while(true) { + if (flag) + break; + + randnum = rand() % 3 + 1; + switch(randnum) { + case 1: + flag = true; + err = read_f(ent, filesize); + break; + case 2: + if (mmap_flag) { + flag = true; + err = read_f_mmap(ent, filesize); + } + break; + case 3: + if (fadvise_flag) { + flag = true; + err = read_f_fadvise(ent, filesize); + } + break; + default: + break; + } + } + return err; +} + +int testfd(struct fent *ent, int mode) +{ + const off64_t filesize = lseek64(ent->fd, 0, SEEK_END); uint64_t chunksize, maxchunksize; int err; @@ -450,16 +816,16 @@ int testfd(int fd, int chkfd, int mode) << PAGE_SHIFT; if (!chunksize) chunksize = PAGE_SIZE; - err = doscan(fd, chkfd, filesize, chunksize); + err = doscan_random(ent, filesize, chunksize); if (err) return err; - } else if (mode == RANDSCAN_UNALIGNED) { + } else if (mode == RANDSCAN_UNALIGNED && !direct_io) { chunksize = (random() * random() % MAX_SCAN_CHUNKSIZE) + 1; - err = doscan(fd, chkfd, filesize, chunksize); + err = doscan_random(ent, filesize, chunksize); if (err) return err; } else if (mode == RANDREAD) { - err = read_f(fd, chkfd, filesize); + err = read_f_random(ent, filesize); if (err) return err; } @@ -470,7 +836,6 @@ int doproc(int mode) { struct fent *fe; int ret; - if (mode <= GETDENTS) { fe = getfent(FT_DIRm, random()); if (!fe) @@ -492,7 +857,7 @@ int doproc(int mode) ret = tryopen(fe); if (ret) return ret; - return testfd(fe->fd, fe->chkfd, mode); + return testfd(fe, mode); } void randomdelay(void) @@ -522,7 +887,7 @@ static int parse_options(int argc, char *argv[]) char *testdir, *chkdir; int opt; - while ((opt = getopt(argc, argv, "l:p:s:")) != -1) { + while ((opt = getopt(argc, argv, "l:p:s:dmf")) != -1) { switch (opt) { case 'l': loops = atoi(optarg); @@ -547,6 +912,15 @@ static int parse_options(int argc, char *argv[]) return -EINVAL; } break; + case 'd': + direct_io = true; + break; + case 'm': + mmap_flag = true; + break; + case 'f': + fadvise_flag = true; + break; default: /* '?' */ return -EINVAL; } @@ -585,7 +959,10 @@ void usage(void) " -l# specifies the no. of times the testrun should loop.\n" " *use 0 for infinite (default 1)\n" " -p# specifies the no. of processes (default 1)\n" - " -s# specifies the seed for the random generator (default random)\n", + " -s# specifies the seed for the random generator (default random)\n" + " -d using direct_io to start stress test\n" + " -m using mmap to start stress test\n" + " -f using fadvise to start stress test\n", stderr); } -- 2.34.1
