[PATCH] erofs-utils: stress: add support for dumping inconsistent data
Gao Xiang
hsiangkao at linux.alibaba.com
Sun Mar 16 19:45:33 AEDT 2025
... dump inconsistent data for further analysis during stress tests.
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
contrib/stress.c | 65 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 59 insertions(+), 6 deletions(-)
diff --git a/contrib/stress.c b/contrib/stress.c
index eedd9b9..27d5133 100644
--- a/contrib/stress.c
+++ b/contrib/stress.c
@@ -256,6 +256,7 @@ static struct fent *getfent(int which, int r)
}
static int testdir_fd = -1, chkdir_fd = -1;
+static char *dumpfile;
static int __getdents_f(unsigned int sn, struct fent *fe)
{
@@ -288,6 +289,47 @@ static int getdents_f(int op, unsigned int sn)
return __getdents_f(sn, fe);
}
+static void baddump(unsigned int sn, char *buf1, char *buf2, unsigned int sz)
+{
+ int fd, err, i;
+ char *fn = dumpfile;
+
+ if (!fn)
+ return;
+ for (i = 0;;) {
+ fd = open(fn, O_CREAT | O_EXCL | O_WRONLY, 0644);
+ if (fd >= 0) {
+ printf("%d[%u]/%u: dump inconsistent data to \"%s\"\n",
+ getpid(), procid, sn, fn);
+ if (fn != dumpfile)
+ free(fn);
+ break;
+ }
+ if (fd < 0 && errno != EEXIST) {
+ fprintf(stderr, "%d[%u]/%u: failed to create dumpfile %s\n",
+ getpid(), procid, sn, fn);
+ if (fn != dumpfile)
+ free(fn);
+ return;
+ }
+ if (fn != dumpfile)
+ free(fn);
+ err = asprintf(&fn, "%s.%d", dumpfile, ++i);
+ if (err < 0) {
+ fprintf(stderr, "%d[%u]/%u: failed to allocate filename\n",
+ getpid(), procid, sn);
+ return;
+ }
+ }
+ if (write(fd, buf1, sz) != sz)
+ fprintf(stderr, "%d[%u]/%u: failed to write buffer1 @ %u",
+ getpid(), procid, sn, sz);
+ if (write(fd, buf2, sz) != sz)
+ fprintf(stderr, "%d[%u]/%u: failed to write buffer2 @ %u",
+ getpid(), procid, sn, sz);
+ close(fd);
+}
+
static int readlink_f(int op, unsigned int sn)
{
char buf1[PATH_MAX], buf2[PATH_MAX];
@@ -317,6 +359,7 @@ static int readlink_f(int op, unsigned int sn)
if (memcmp(buf1, buf2, sz)) {
fprintf(stderr, "%d[%u]/%u %s: symlink mismatch @%s\n",
getpid(), procid, sn, __func__, fe->subpath);
+ baddump(sn, buf1, buf2, sz);
return -EBADMSG;
}
}
@@ -382,8 +425,8 @@ static int __read_f(unsigned int sn, struct fent *fe, uint64_t filesize)
trimmed = len <= filesize - off ? len : filesize - off;
}
- printf("%d[%u]/%u read_f: %llu bytes @ %llu\n", getpid(), procid, sn,
- len | 0ULL, off | 0ULL);
+ printf("%d[%u]/%u read_f: %llu bytes @ %llu of %s\n", getpid(), procid,
+ sn, len | 0ULL, off | 0ULL, fe->subpath);
nread = pread64(fe->fd, buf, len, off);
if (nread != trimmed) {
fprintf(stderr, "%d[%u]/%u read_f: failed to read %llu bytes @ %llu of %s\n",
@@ -414,6 +457,7 @@ static int __read_f(unsigned int sn, struct fent *fe, uint64_t filesize)
fprintf(stderr, "%d[%u]/%u read_f: data mismatch %llu bytes @ %llu of %s\n",
getpid(), procid, sn, len | 0ULL, off | 0ULL,
fe->subpath);
+ baddump(sn, buf, chkbuf, nread);
return -EBADMSG;
}
return 0;
@@ -481,6 +525,7 @@ static int __doscan_f(unsigned int sn, const char *op, struct fent *fe,
fprintf(stderr, "%d[%u]/%u %s: %llu bytes mismatch @ %llu of %s\n",
getpid(), procid, sn, op, chunksize | 0ULL,
pos | 0ULL, fe->subpath);
+ baddump(sn, buf, chkbuf, nread);
return -EBADMSG;
}
}
@@ -589,7 +634,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, "d:l:p:s:")) != -1) {
switch (opt) {
case 'l':
loops = atoi(optarg);
@@ -614,6 +659,13 @@ static int parse_options(int argc, char *argv[])
return -EINVAL;
}
break;
+ case 'd':
+ if (!*optarg) {
+ fprintf(stderr, "invalid dump file\n");
+ return -EINVAL;
+ }
+ dumpfile = optarg;
+ break;
default: /* '?' */
return -EINVAL;
}
@@ -650,9 +702,10 @@ static void usage(void)
fputs("usage: [options] TESTDIR [COMPRDIR]\n\n"
"Stress test for EROFS filesystem, where TESTDIR is the directory to test and\n"
"COMPRDIR (optional) serves as a directory for data comparison.\n"
- " -l# Number of times each worker should loop (0 for infinite, default: 1)\n"
- " -p# Number of parallel worker processes (default: 1)\n"
- " -s# Seed for random generator (default: random)\n",
+ " -l# Number of times each worker should loop (0 for infinite, default: 1)\n"
+ " -p# Number of parallel worker processes (default: 1)\n"
+ " -s# Seed for random generator (default: random)\n"
+ " -d<file> Specify a dumpfile for the inconsistent data\n",
stderr);
}
--
2.43.5
More information about the Linux-erofs
mailing list