On Wed, Feb 18, 2026 at 5:22 AM T.J. Mercier <[email protected]> wrote: > > Add two new tests that verify inotify events are sent when memcg files > are removed. > > Signed-off-by: T.J. Mercier <[email protected]> > Acked-by: Tejun Heo <[email protected]>
Feel free to add: Acked-by: Amir Goldstein <[email protected]> Although... > --- > .../selftests/cgroup/test_memcontrol.c | 122 ++++++++++++++++++ > 1 file changed, 122 insertions(+) > > diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c > b/tools/testing/selftests/cgroup/test_memcontrol.c > index 4e1647568c5b..2b065d03b730 100644 > --- a/tools/testing/selftests/cgroup/test_memcontrol.c > +++ b/tools/testing/selftests/cgroup/test_memcontrol.c > @@ -10,6 +10,7 @@ > #include <sys/stat.h> > #include <sys/types.h> > #include <unistd.h> > +#include <sys/inotify.h> > #include <sys/socket.h> > #include <sys/wait.h> > #include <arpa/inet.h> > @@ -1625,6 +1626,125 @@ static int test_memcg_oom_group_score_events(const > char *root) > return ret; > } > > +static int read_event(int inotify_fd, int expected_event, int expected_wd) > +{ > + struct inotify_event event; > + ssize_t len = 0; > + > + len = read(inotify_fd, &event, sizeof(event)); > + if (len < (ssize_t)sizeof(event)) > + return -1; > + > + if (event.mask != expected_event || event.wd != expected_wd) { > + fprintf(stderr, > + "event does not match expected values: mask %d > (expected %d) wd %d (expected %d)\n", > + event.mask, expected_event, event.wd, expected_wd); > + return -1; > + } > + > + return 0; > +} > + > +static int test_memcg_inotify_delete_file(const char *root) > +{ > + int ret = KSFT_FAIL; > + char *memcg = NULL, *child_memcg = NULL; > + int fd, wd; > + > + memcg = cg_name(root, "memcg_test_0"); > + > + if (!memcg) > + goto cleanup; > + > + if (cg_create(memcg)) > + goto cleanup; > + > + if (cg_write(memcg, "cgroup.subtree_control", "+memory")) > + goto cleanup; > + > + child_memcg = cg_name(memcg, "child"); > + if (!child_memcg) > + goto cleanup; > + > + if (cg_create(child_memcg)) > + goto cleanup; > + > + fd = inotify_init1(0); > + if (fd == -1) > + goto cleanup; > + > + wd = inotify_add_watch(fd, cg_control(child_memcg, "memory.events"), > IN_DELETE_SELF); > + if (wd == -1) > + goto cleanup; > + > + cg_write(memcg, "cgroup.subtree_control", "-memory"); > + > + if (read_event(fd, IN_DELETE_SELF, wd)) > + goto cleanup; > + > + if (read_event(fd, IN_IGNORED, wd)) > + goto cleanup; > + > + ret = KSFT_PASS; > + > +cleanup: > + if (fd >= 0) > + close(fd); > + if (child_memcg) > + cg_destroy(child_memcg); > + free(child_memcg); > + if (memcg) > + cg_destroy(memcg); > + free(memcg); > + > + return ret; > +} > + > +static int test_memcg_inotify_delete_rmdir(const char *root) > +{ > + int ret = KSFT_FAIL; > + char *memcg = NULL; > + int fd, wd; > + > + memcg = cg_name(root, "memcg_test_0"); > + > + if (!memcg) > + goto cleanup; > + > + if (cg_create(memcg)) > + goto cleanup; > + > + fd = inotify_init1(0); > + if (fd == -1) > + goto cleanup; > + > + wd = inotify_add_watch(fd, cg_control(memcg, "memory.events"), > IN_DELETE_SELF); > + if (wd == -1) > + goto cleanup; > + > + if (cg_destroy(memcg)) > + goto cleanup; > + free(memcg); > + memcg = NULL; > + > + if (read_event(fd, IN_DELETE_SELF, wd)) > + goto cleanup; > + > + if (read_event(fd, IN_IGNORED, wd)) > + goto cleanup; > + > + ret = KSFT_PASS; > + > +cleanup: > + if (fd >= 0) > + close(fd); > + if (memcg) > + cg_destroy(memcg); > + free(memcg); > + > + return ret; > +} > + > #define T(x) { x, #x } > struct memcg_test { > int (*fn)(const char *root); > @@ -1644,6 +1764,8 @@ struct memcg_test { > T(test_memcg_oom_group_leaf_events), > T(test_memcg_oom_group_parent_events), > T(test_memcg_oom_group_score_events), > + T(test_memcg_inotify_delete_file), > + T(test_memcg_inotify_delete_rmdir), How about another test case: - Watch the cgroup directory (not the child file) - Destroy cgroup - Expect IN_DELETE_SELF | IN_ISDIR I realize that this test won't pass with your implementation (right?) but that is not ok IMO. If we wish to make IN_DELETE_SELF available for kernfs, it should not be confined to regular files IMO. Thanks, Amir.

