The handler processes IN_MODIFY only. Since commit eea5d2bb34ba ("kernfs: Send IN_DELETE_SELF and IN_IGNORED") kernfs delivers both events when the cgroup is removed, but the sample warns "No IN_MODIFY event, skip it" and returns to poll() forever: after an rmdir the listener never notices and keeps polling, while a supervisor still counts it as alive, and the cleanup_memcg_events() call in main() is unreachable. The accompanying selftest, commit 2de27980e1d4 ("selftests: memcg: Add tests for IN_DELETE_SELF and IN_IGNORED"), exercises exactly this two-event sequence. Handle the removal pair by printing a clear message and exiting, and subscribe IN_DELETE_SELF explicitly. monitor_events() returns through the normal path, which also makes the cleanup call reachable again. Signed-off-by: Song Hu --- samples/cgroup/memcg_event_listener.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/samples/cgroup/memcg_event_listener.c b/samples/cgroup/memcg_event_listener.c index ec7c03fa7887..996bf6fb117c 100644 --- a/samples/cgroup/memcg_event_listener.c +++ b/samples/cgroup/memcg_event_listener.c @@ -199,7 +199,7 @@ static int read_memcg_events(struct memcg_events *events, bool show_diff) return ret; } -static void process_memcg_events(struct memcg_events *events, +static bool process_memcg_events(struct memcg_events *events, struct inotify_event *event) { int ret; @@ -207,19 +207,27 @@ static void process_memcg_events(struct memcg_events *events, if (events->inotify_wd != event->wd) { warnx("Unknown inotify event %d, should be %d", event->wd, events->inotify_wd); - return; + return true; + } + + if (event->mask & (IN_DELETE_SELF | IN_IGNORED)) { + printf("The monitored file %s was removed, exiting\n", + events->path); + return false; } printf("Received event in %s:\n", events->path); if (!(event->mask & IN_MODIFY)) { warnx("No IN_MODIFY event, skip it"); - return; + return true; } ret = read_memcg_events(events, /* show_diff = */true); if (ret) warnx("Can't read memcg events"); + + return true; } static void monitor_events(struct memcg_events *events) @@ -247,6 +255,7 @@ static void monitor_events(struct memcg_events *events) struct inotify_event *event; char buffer[INOTIFY_BUFFER_SIZE]; ssize_t length; + bool keep_going = true; length = read(fds[0].fd, buffer, INOTIFY_BUFFER_SIZE); if (length <= 0) @@ -254,9 +263,15 @@ static void monitor_events(struct memcg_events *events) event = (struct inotify_event *)buffer; while (INOTIFY_EVENT_OK(event, length)) { - process_memcg_events(events, event); + keep_going = process_memcg_events(events, + event); + if (!keep_going) + break; event = INOTIFY_EVENT_NEXT(event, length); } + + if (!keep_going) + return; } } } @@ -291,7 +306,8 @@ static int initialize_memcg_events(struct memcg_events *events, } events->inotify_wd = inotify_add_watch(events->inotify_fd, - events->path, IN_MODIFY); + events->path, + IN_MODIFY | IN_DELETE_SELF); if (events->inotify_wd < 0) { warn("Couldn't add monitor in dir %s", events->path); return -EIO; -- 2.53.0