diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index f68b2103f8..e643c71714 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -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) diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 8f1f333943..cf015b5a7b 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1351,10 +1351,13 @@ static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) { /* libvirt / qemu uses threaded mode and cgroup.procs cannot be read at the lower levels. * From https://docs.kernel.org/admin-guide/cgroup-v2.html#threads, “cgroup.procs” in a * threaded domain cgroup contains the PIDs of all processes in the subtree and is not - * readable in the subtree proper. */ + * readable in the subtree proper. + * + * We'll see ENODEV when trying to enumerate processes and the cgroup is removed at the same + * time. Handle this gracefully. */ r = cg_read_pidref(f, &pidref, /* flags = */ 0); - if (IN_SET(r, 0, -EOPNOTSUPP)) + if (IN_SET(r, 0, -EOPNOTSUPP, -ENODEV)) break; if (r < 0) return r; diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c index 8e6cb55427..f6f0fe2c19 100644 --- a/src/shared/cgroup-setup.c +++ b/src/shared/cgroup-setup.c @@ -367,6 +367,8 @@ int cg_migrate( if (r < 0) return RET_GATHER(ret, r); } + if (r == -ENODEV) + continue; if (r < 0) return RET_GATHER(ret, r); } while (!done); diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index b95cecb3e6..b97edbdba7 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -107,9 +107,12 @@ static int show_cgroup_one_by_path( /* libvirt / qemu uses threaded mode and cgroup.procs cannot be read at the lower levels. * From https://docs.kernel.org/admin-guide/cgroup-v2.html#threads, * “cgroup.procs” in a threaded domain cgroup contains the PIDs of all processes in - * the subtree and is not readable in the subtree proper. */ + * the subtree and is not readable in the subtree proper. + * + * ENODEV is generated when we enumerate processes from a cgroup and the cgroup is removed + * concurrently. */ r = cg_read_pid(f, &pid, /* flags = */ 0); - if (IN_SET(r, 0, -EOPNOTSUPP)) + if (IN_SET(r, 0, -EOPNOTSUPP, -ENODEV)) break; if (r < 0) return r;