mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
cgroup-util: drop handcrafted cg_is_empty(), always check cgroup.events populated field (#37624)
This commit is contained in:
@@ -198,47 +198,6 @@ int cg_read_pidref(FILE *f, PidRef *ret, CGroupFlags flags) {
|
||||
}
|
||||
}
|
||||
|
||||
int cg_read_event(
|
||||
const char *controller,
|
||||
const char *path,
|
||||
const char *event,
|
||||
char **ret) {
|
||||
|
||||
_cleanup_free_ char *events = NULL, *content = NULL;
|
||||
int r;
|
||||
|
||||
r = cg_get_path(controller, path, "cgroup.events", &events);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = read_full_virtual_file(events, &content, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (const char *p = content;;) {
|
||||
_cleanup_free_ char *line = NULL, *key = NULL;
|
||||
const char *q;
|
||||
|
||||
r = extract_first_word(&p, &line, "\n", 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -ENOENT;
|
||||
|
||||
q = line;
|
||||
r = extract_first_word(&q, &key, " ", 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!streq(key, event))
|
||||
continue;
|
||||
|
||||
return strdup_to(ret, q);
|
||||
}
|
||||
}
|
||||
|
||||
bool cg_kill_supported(void) {
|
||||
static thread_local int supported = -1;
|
||||
|
||||
@@ -792,81 +751,25 @@ int cg_pidref_get_path(const char *controller, const PidRef *pidref, char **ret_
|
||||
}
|
||||
|
||||
int cg_is_empty(const char *controller, const char *path) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
pid_t pid;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
|
||||
/* Check if the cgroup hierarchy under 'path' is empty. On cgroup v2 it's exposed via the "populated"
|
||||
* attribute of "cgroup.events". */
|
||||
|
||||
assert(path);
|
||||
|
||||
r = cg_enumerate_processes(controller, path, &f);
|
||||
/* The root cgroup is always populated */
|
||||
if (empty_or_root(path))
|
||||
return false;
|
||||
|
||||
r = cg_get_keyed_attribute(SYSTEMD_CGROUP_CONTROLLER, path, "cgroup.events", STRV_MAKE("populated"), &t);
|
||||
if (r == -ENOENT)
|
||||
return true;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = cg_read_pid(f, &pid, CGROUP_DONT_SKIP_UNMAPPED);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
int cg_is_empty_recursive(const char *controller, const char *path) {
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* The root cgroup is always populated */
|
||||
if (controller && empty_or_root(path))
|
||||
return false;
|
||||
|
||||
r = cg_unified_controller(controller);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
/* On the unified hierarchy we can check empty state
|
||||
* via the "populated" attribute of "cgroup.events". */
|
||||
|
||||
r = cg_read_event(controller, path, "populated", &t);
|
||||
if (r == -ENOENT)
|
||||
return true;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return streq(t, "0");
|
||||
} else {
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
char *fn;
|
||||
|
||||
r = cg_is_empty(controller, path);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = cg_enumerate_subgroups(controller, path, &d);
|
||||
if (r == -ENOENT)
|
||||
return true;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while ((r = cg_read_subgroup(d, &fn)) > 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = path_join(path, fn);
|
||||
free(fn);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = cg_is_empty_recursive(controller, p);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return true;
|
||||
}
|
||||
return streq(t, "0");
|
||||
}
|
||||
|
||||
int cg_split_spec(const char *spec, char **ret_controller, char **ret_path) {
|
||||
|
||||
@@ -188,7 +188,6 @@ typedef enum CGroupFlags {
|
||||
int cg_enumerate_processes(const char *controller, const char *path, FILE **ret);
|
||||
int cg_read_pid(FILE *f, pid_t *ret, CGroupFlags flags);
|
||||
int cg_read_pidref(FILE *f, PidRef *ret, CGroupFlags flags);
|
||||
int cg_read_event(const char *controller, const char *path, const char *event, char **ret);
|
||||
|
||||
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **ret);
|
||||
int cg_read_subgroup(DIR *d, char **ret);
|
||||
@@ -233,7 +232,6 @@ int cg_get_xattr_bool(const char *path, const char *name);
|
||||
int cg_remove_xattr(const char *path, const char *name);
|
||||
|
||||
int cg_is_empty(const char *controller, const char *path);
|
||||
int cg_is_empty_recursive(const char *controller, const char *path);
|
||||
|
||||
int cg_get_root_path(char **path);
|
||||
|
||||
|
||||
@@ -2760,7 +2760,7 @@ int unit_cgroup_is_empty(Unit *u) {
|
||||
if (!crt->cgroup_path)
|
||||
return -EOWNERDEAD;
|
||||
|
||||
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, crt->cgroup_path);
|
||||
r = cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, crt->cgroup_path);
|
||||
if (r < 0)
|
||||
log_unit_debug_errno(u, r, "Failed to determine whether cgroup %s is empty: %m", empty_to_root(crt->cgroup_path));
|
||||
return r;
|
||||
@@ -3626,8 +3626,6 @@ static int unit_get_cpu_usage_raw(const Unit *u, const CGroupRuntime *crt, nsec_
|
||||
uint64_t us;
|
||||
|
||||
r = cg_get_keyed_attribute("cpu", crt->cgroup_path, "cpu.stat", STRV_MAKE("usage_usec"), &val);
|
||||
if (IN_SET(r, -ENOENT, -ENXIO))
|
||||
return -ENODATA;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -4082,8 +4080,6 @@ static int unit_cgroup_freezer_kernel_state(Unit *u, FreezerState *ret) {
|
||||
"cgroup.events",
|
||||
STRV_MAKE("frozen"),
|
||||
&val);
|
||||
if (IN_SET(r, -ENOENT, -ENXIO))
|
||||
return -ENODATA;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -1976,7 +1976,7 @@ static int cgroup_good(Service *s) {
|
||||
if (!s->cgroup_runtime || !s->cgroup_runtime->cgroup_path)
|
||||
return 0;
|
||||
|
||||
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_runtime->cgroup_path);
|
||||
r = cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_runtime->cgroup_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -457,7 +457,7 @@ static int show_unit_cgroup(
|
||||
|
||||
/* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
|
||||
|
||||
if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
|
||||
if (cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
|
||||
return 0;
|
||||
|
||||
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, prefix, c, &leader, leader > 0, get_output_flags());
|
||||
|
||||
@@ -436,7 +436,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
|
||||
|
||||
/* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
|
||||
|
||||
if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
|
||||
if (cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
|
||||
return 0;
|
||||
|
||||
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
|
||||
|
||||
@@ -251,7 +251,7 @@ int show_cgroup_by_path(
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty_recursive(NULL, k) > 0)
|
||||
if (!(flags & OUTPUT_SHOW_ALL) && cg_is_empty(NULL, k) > 0)
|
||||
continue;
|
||||
|
||||
if (!shown_pids) {
|
||||
|
||||
@@ -106,9 +106,7 @@ TEST(cg_create) {
|
||||
free(path);
|
||||
|
||||
ASSERT_OK_POSITIVE(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, test_a));
|
||||
ASSERT_OK_POSITIVE(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, test_b));
|
||||
ASSERT_OK_POSITIVE(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, test_a));
|
||||
ASSERT_OK_ZERO(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, test_b));
|
||||
ASSERT_OK_ZERO(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, test_b));
|
||||
|
||||
ASSERT_OK_ZERO(cg_kill_recursive(test_a, 0, 0, NULL, NULL, NULL));
|
||||
ASSERT_OK_POSITIVE(cg_kill_recursive(test_b, 0, 0, NULL, NULL, NULL));
|
||||
|
||||
Reference in New Issue
Block a user