cgroup: handle ENODEV on cg_read_pid() gracefully

The recently added test case TEST-07-PID1.subgroup-kill.sh surfaced a
race: if we enumerate PIDs in a cgroup, and the cgroup is unlinked at
the very same time reading will result in ENODEV. We need to handle that
gracefully. Hence let's do so.

Noticed while looking at:

https://github.com/systemd/systemd/actions/runs/16143084441/job/45554929264?pr=38120
This commit is contained in:
Lennart Poettering
2025-07-09 20:45:59 +02:00
committed by Mike Yuan
parent da412f3be2
commit 726183627b
4 changed files with 22 additions and 4 deletions
+10
View File
@@ -142,6 +142,9 @@ int cg_read_pid(FILE *f, pid_t *ret, CGroupFlags flags) {
assert(f);
assert(ret);
/* NB: The kernel returns ENODEV if we tried to read from cgroup.procs of a cgroup that has been
* removed already. Callers should handle that! */
for (;;) {
errno = 0;
if (fscanf(f, "%lu", &ul) != 1) {
@@ -300,6 +303,13 @@ int cg_kill(
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = cg_read_pidref(f, &pidref, flags);
if (r == -ENODEV) {
/* reading from cgroup.pids will result in ENODEV if the cgroup is
* concurrently removed. Just leave in that case, because a removed cgroup
* contains no processes anymore. */
done = true;
break;
}
if (r < 0)
return RET_GATHER(ret, log_debug_errno(r, "Failed to read pidref from cgroup '%s': %m", path));
if (r == 0)