[PATCH 2/4] samples/cgroup: exit cleanly when the monitored memcg is removed
From: Song Hu
Date: Mon Nov 02 2026 - 08:35:14 EST
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 <husong@xxxxxxxxxx>
---
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