diff options
| author | Mark Johnston <markj@FreeBSD.org> | 2026-04-26 01:35:37 +0000 |
|---|---|---|
| committer | Mark Johnston <markj@FreeBSD.org> | 2026-04-26 01:56:14 +0000 |
| commit | a02d794f5acd12ba3cf1de5c204a8dd56af47edd (patch) | |
| tree | 5ad7e642f465db66915e18a32efbfda44801e615 /tests | |
| parent | bea17411473bc58608badd425c223ee59d40a465 (diff) | |
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/sys/kern/inotify_test.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/tests/sys/kern/inotify_test.c b/tests/sys/kern/inotify_test.c index 0a4df4e5fcaa..d3799b12ce20 100644 --- a/tests/sys/kern/inotify_test.c +++ b/tests/sys/kern/inotify_test.c @@ -393,6 +393,116 @@ ATF_TC_CLEANUP(inotify_nullfs, tc) } /* + * Watch a file in a nullfs mount, and remove it from the lower mount. Make + * sure that we get an IN_DELETE_SELF event and that the watch is removed. + */ +ATF_TC_WITH_CLEANUP(inotify_nullfs_remove); +ATF_TC_HEAD(inotify_nullfs_remove, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(inotify_nullfs_remove, tc) +{ + char dir[PATH_MAX], path[PATH_MAX], *p; + int error, fd, ifd, wd; + + strlcpy(dir, "./test.XXXXXX", sizeof(dir)); + p = mkdtemp(dir); + ATF_REQUIRE(p == dir); + + error = mkdir("./mnt", 0755); + ATF_REQUIRE(error == 0); + + /* Mount the testdir onto ./mnt. */ + mount_nullfs("./mnt", dir); + + snprintf(path, sizeof(path), "%s/file", dir); + fd = open(path, O_RDWR | O_CREAT, 0644); + ATF_REQUIRE(fd != -1); + close_checked(fd); + + ifd = inotify(IN_NONBLOCK); + wd = inotify_add_watch(ifd, "./mnt/file", IN_DELETE_SELF); + ATF_REQUIRE(wd != -1); + + error = unlink(path); + ATF_REQUIRE(error == 0); + + consume_event(ifd, wd, IN_DELETE_SELF, 0, NULL); + consume_event(ifd, wd, 0, IN_IGNORED, NULL); + + close_inotify(ifd); +} +ATF_TC_CLEANUP(inotify_nullfs_remove, tc) +{ + int error; + + error = unmount("./mnt", 0); + if (error != 0) { + perror("unmount"); + exit(1); + } +} + +/* + * Exercise a scenario where a watched lower vnode is deleted by a rename. The + * deletion causes the upper vnode to be reclaimed, and after that point it + * should stop trying to forward events back to the (now detached) lower vnode. + */ +ATF_TC_WITH_CLEANUP(inotify_nullfs_rename); +ATF_TC_HEAD(inotify_nullfs_rename, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(inotify_nullfs_rename, tc) +{ + char dir[PATH_MAX], path1[PATH_MAX], path2[PATH_MAX], *p; + int error, fd, ifd, wd; + + strlcpy(dir, "./test.XXXXXX", sizeof(dir)); + p = mkdtemp(dir); + ATF_REQUIRE(p == dir); + + error = mkdir("./mnt", 0755); + ATF_REQUIRE(error == 0); + + /* Mount the testdir onto ./mnt. */ + mount_nullfs("./mnt", dir); + + ifd = inotify(IN_NONBLOCK); + + /* Create two files, they will be renamed in the upper layer. */ + snprintf(path1, sizeof(path1), "%s/file1", dir); + fd = open(path1, O_RDWR | O_CREAT, 0644); + ATF_REQUIRE(fd != -1); + close_checked(fd); + snprintf(path2, sizeof(path2), "%s/file2", dir); + fd = open(path2, O_RDWR | O_CREAT, 0644); + ATF_REQUIRE(fd != -1); + close_checked(fd); + + wd = inotify_add_watch(ifd, "./mnt/file1", IN_DELETE_SELF); + ATF_REQUIRE(wd != -1); + error = rename("./mnt/file2", "./mnt/file1"); + ATF_REQUIRE(error == 0); + + consume_event(ifd, wd, IN_DELETE_SELF, 0, NULL); + consume_event(ifd, wd, 0, IN_IGNORED, NULL); + + close_inotify(ifd); +} +ATF_TC_CLEANUP(inotify_nullfs_rename, tc) +{ + int error; + + error = unmount("./mnt", 0); + if (error != 0) { + perror("unmount"); + exit(1); + } +} + +/* * Make sure that exceeding max_events pending events results in an overflow * event. */ @@ -878,6 +988,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, inotify_coalesce); ATF_TP_ADD_TC(tp, inotify_mask_create); ATF_TP_ADD_TC(tp, inotify_nullfs); + ATF_TP_ADD_TC(tp, inotify_nullfs_remove); + ATF_TP_ADD_TC(tp, inotify_nullfs_rename); ATF_TP_ADD_TC(tp, inotify_queue_overflow); /* Tests for the various inotify event types. */ ATF_TP_ADD_TC(tp, inotify_event_access_file); |
