summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2021-06-09 19:32:46 +0300
committerNikolaus Rath <Nikolaus@rath.org>2021-06-14 09:13:12 +0100
commit10ecd4fda404f3403e571a7dbfe6bb295d0f208b (patch)
tree20a4450ecd0189e1f282cd8dd9450061c691ed21 /test
parent494e15127c67a673779fa2f05c08abe6901f88c5 (diff)
downloadfuse-10ecd4fda404f3403e571a7dbfe6bb295d0f208b.tar.gz
test/test_syscalls.c: check unlinked testfiles at the end of the test
On some tests on regular files, open an O_PATH fd of the testfile and record it along side the size and mode and inode. At the end of all tests, use recorded testfiles info to re-check the size mode and inode of the unlinked testfiles. With O_PATH fd, the server does not have to keep the inode alive so FUSE inode may be stale or bad. Therefore, ESTALE and EIO are valid results for fstat() on the old testfile fd's, but returning the wrong size or mode is an invalid result. Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Diffstat (limited to 'test')
-rw-r--r--test/test_syscalls.c145
1 files changed, 129 insertions, 16 deletions
diff --git a/test/test_syscalls.c b/test/test_syscalls.c
index 18243c6..2ff6bcd 100644
--- a/test/test_syscalls.c
+++ b/test/test_syscalls.c
@@ -49,6 +49,12 @@ static unsigned int select_test = 0;
static unsigned int skip_test = 0;
#define MAX_ENTRIES 1024
+#define MAX_TESTS 100
+
+static struct test {
+ int fd;
+ struct stat stat;
+} tests[MAX_TESTS];
static void test_perror(const char *func, const char *msg)
{
@@ -82,6 +88,9 @@ static void success(void)
fprintf(stderr, "%s OK\n", testname);
}
+#define this_test (&tests[testnum-1])
+#define next_test (&tests[testnum])
+
static void __start_test(const char *fmt, ...)
{
unsigned int n;
@@ -94,6 +103,11 @@ static void __start_test(const char *fmt, ...)
// Use dedicated testfile per test
sprintf(testfile, "%s/testfile.%d", basepath, testnum);
sprintf(testfile_r, "%s/testfile.%d", basepath_r, testnum);
+ if (testnum > MAX_TESTS) {
+ fprintf(stderr, "%s - too many tests\n", testname);
+ exit(1);
+ }
+ this_test->fd = -1;
}
#define start_test(msg, args...) { \
@@ -131,6 +145,12 @@ static int check_size(const char *path, int len)
return st_check_size(&stbuf, len);
}
+static int check_testfile_size(const char *path, int len)
+{
+ this_test->stat.st_size = len;
+ return check_size(path, len);
+}
+
static int st_check_type(struct stat *st, mode_t type)
{
if ((st->st_mode & S_IFMT) != type) {
@@ -172,6 +192,13 @@ static int check_mode(const char *path, mode_t mode)
return st_check_mode(&stbuf, mode);
}
+static int check_testfile_mode(const char *path, mode_t mode)
+{
+ this_test->stat.st_mode &= ~ALLPERMS;
+ this_test->stat.st_mode |= mode;
+ return check_mode(path, mode);
+}
+
static int check_times(const char *path, time_t atime, time_t mtime)
{
int err = 0;
@@ -241,12 +268,17 @@ static int check_nlink(const char *path, nlink_t nlink)
return st_check_nlink(&stbuf, nlink);
}
-static int fcheck_stat(int fd, struct stat *st)
-
+static int fcheck_stat(int fd, int flags, struct stat *st)
{
struct stat stbuf;
int res = fstat(fd, &stbuf);
if (res == -1) {
+ if (flags & O_PATH) {
+ // With O_PATH fd, the server does not have to keep
+ // the inode alive so FUSE inode may be stale or bad
+ if (errno == ESTALE || errno == EIO || errno == ENOENT)
+ return 0;
+ }
PERROR("fstat");
return -1;
}
@@ -477,6 +509,87 @@ static int create_file(const char *path, const char *data, int len)
return 0;
}
+static int create_path_fd(const char *path, const char *data, int len)
+{
+ int path_fd;
+ int res;
+
+ res = create_file(path, data, len);
+ if (res == -1)
+ return -1;
+
+ path_fd = open(path, O_PATH);
+ if (path_fd == -1)
+ PERROR("open(O_PATH)");
+
+ return path_fd;
+}
+
+// Can be called once per test
+static int create_testfile(const char *path, const char *data, int len)
+{
+ struct test *t = this_test;
+ struct stat *st = &t->stat;
+ int res, fd;
+
+ if (t->fd > 0) {
+ ERROR("testfile already created");
+ return -1;
+ }
+
+ fd = create_path_fd(path, data, len);
+ if (fd == -1)
+ return -1;
+
+ t->fd = fd;
+
+ res = fstat(fd, st);
+ if (res == -1) {
+ PERROR("fstat");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_unlinked_testfile(int fd)
+{
+ struct stat *st = &this_test->stat;
+
+ st->st_nlink = 0;
+ return fcheck_stat(fd, O_PATH, st);
+}
+
+// Check recorded testfiles after all tests completed
+static int check_unlinked_testfiles(void)
+{
+ int fd;
+ int res, err = 0;
+ int num = testnum;
+
+ testnum = 0;
+ while (testnum < num) {
+ fd = next_test->fd;
+ start_test("check_unlinked_testfile");
+ if (fd == -1)
+ continue;
+
+ err += check_unlinked_testfile(fd);
+ res = close(fd);
+ if (res == -1) {
+ PERROR("close(test_fd)");
+ err--;
+ }
+ }
+
+ if (err) {
+ fprintf(stderr, "%i unlinked testfile checks failed\n", -err);
+ return 1;
+ }
+
+ return err;
+}
+
static int cleanup_dir(const char *path, const char **dir_files, int quiet)
{
int i;
@@ -541,7 +654,7 @@ static int test_truncate(int len)
int res;
start_test("truncate(%u)", (int) len);
- res = create_file(testfile, data, datalen);
+ res = create_testfile(testfile, data, datalen);
if (res == -1)
return -1;
@@ -550,7 +663,7 @@ static int test_truncate(int len)
PERROR("truncate");
return -1;
}
- res = check_size(testfile, len);
+ res = check_testfile_size(testfile, len);
if (res == -1)
return -1;
@@ -590,7 +703,7 @@ static int test_ftruncate(int len, int mode)
int fd;
start_test("ftruncate(%u) mode: 0%03o", len, mode);
- res = create_file(testfile, data, datalen);
+ res = create_testfile(testfile, data, datalen);
if (res == -1)
return -1;
@@ -606,7 +719,7 @@ static int test_ftruncate(int len, int mode)
close(fd);
return -1;
}
- res = check_mode(testfile, mode);
+ res = check_testfile_mode(testfile, mode);
if (res == -1) {
close(fd);
return -1;
@@ -618,7 +731,7 @@ static int test_ftruncate(int len, int mode)
return -1;
}
close(fd);
- res = check_size(testfile, len);
+ res = check_testfile_size(testfile, len);
if (res == -1)
return -1;
@@ -811,7 +924,7 @@ static int test_utime(void)
int res;
start_test("utime");
- res = create_file(testfile, NULL, 0);
+ res = create_testfile(testfile, NULL, 0);
if (res == -1)
return -1;
@@ -933,7 +1046,7 @@ static int test_create_unlink(void)
.st_mode = S_IFREG | 0644,
.st_size = datalen,
};
- err = fcheck_stat(fd, &st);
+ err = fcheck_stat(fd, O_RDWR, &st);
err += fcheck_data(fd, data, 0, datalen);
res = close(fd);
if (res == -1) {
@@ -1153,7 +1266,7 @@ static int do_test_open_acc(int flags, const char *flags_str, int mode, int err)
start_test("open_acc(%s) mode: 0%03o message: '%s'", flags_str, mode,
strerror(err));
unlink(testfile);
- res = create_file(testfile, data, datalen);
+ res = create_testfile(testfile, data, datalen);
if (res == -1)
return -1;
@@ -1163,7 +1276,7 @@ static int do_test_open_acc(int flags, const char *flags_str, int mode, int err)
return -1;
}
- res = check_mode(testfile, mode);
+ res = check_testfile_mode(testfile, mode);
if (res == -1)
return -1;
@@ -1208,7 +1321,7 @@ static int test_symlink(void)
int res;
start_test("symlink");
- res = create_file(testfile, data, datalen);
+ res = create_testfile(testfile, data, datalen);
if (res == -1)
return -1;
@@ -1270,7 +1383,7 @@ static int test_link(void)
int res;
start_test("link");
- res = create_file(testfile, data, datalen);
+ res = create_testfile(testfile, data, datalen);
if (res == -1)
return -1;
@@ -1320,7 +1433,7 @@ static int test_link2(void)
int res;
start_test("link-unlink-link");
- res = create_file(testfile, data, datalen);
+ res = create_testfile(testfile, data, datalen);
if (res == -1)
return -1;
@@ -1379,7 +1492,7 @@ static int test_rename_file(void)
int res;
start_test("rename file");
- res = create_file(testfile, data, datalen);
+ res = create_testfile(testfile, data, datalen);
if (res == -1)
return -1;
@@ -1971,5 +2084,5 @@ int main(int argc, char *argv[])
return 1;
}
- return 0;
+ return check_unlinked_testfiles();
}