Skip to content

Commit 00f1714

Browse files
BtbNkeszybz
authored andcommitted
cgroup-util: allow cg_read_pid() to skip unmapped (zero) pids
1 parent 19614a0 commit 00f1714

File tree

7 files changed

+48
-32
lines changed

7 files changed

+48
-32
lines changed

src/basic/cgroup-util.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,35 +95,41 @@ int cg_enumerate_processes(const char *controller, const char *path, FILE **ret)
9595
return cg_enumerate_items(controller, path, ret, "cgroup.procs");
9696
}
9797

98-
int cg_read_pid(FILE *f, pid_t *ret) {
98+
int cg_read_pid(FILE *f, pid_t *ret, CGroupFlags flags) {
9999
unsigned long ul;
100100

101101
/* Note that the cgroup.procs might contain duplicates! See cgroups.txt for details. */
102102

103103
assert(f);
104104
assert(ret);
105105

106-
errno = 0;
107-
if (fscanf(f, "%lu", &ul) != 1) {
106+
for (;;) {
107+
errno = 0;
108+
if (fscanf(f, "%lu", &ul) != 1) {
108109

109-
if (feof(f)) {
110-
*ret = 0;
111-
return 0;
110+
if (feof(f)) {
111+
*ret = 0;
112+
return 0;
113+
}
114+
115+
return errno_or_else(EIO);
112116
}
113117

114-
return errno_or_else(EIO);
115-
}
118+
if (ul > PID_T_MAX)
119+
return -EIO;
116120

117-
if (ul <= 0)
118-
return -EIO;
119-
if (ul > PID_T_MAX)
120-
return -EIO;
121+
/* In some circumstances (e.g. WSL), cgroups might contain unmappable PIDs from other
122+
* contexts. These show up as zeros, and depending on the caller, can either be plain
123+
* skipped over, or returned as-is. */
124+
if (ul == 0 && !FLAGS_SET(flags, CGROUP_DONT_SKIP_UNMAPPED))
125+
continue;
121126

122-
*ret = (pid_t) ul;
123-
return 1;
127+
*ret = (pid_t) ul;
128+
return 1;
129+
}
124130
}
125131

126-
int cg_read_pidref(FILE *f, PidRef *ret) {
132+
int cg_read_pidref(FILE *f, PidRef *ret, CGroupFlags flags) {
127133
int r;
128134

129135
assert(f);
@@ -132,14 +138,17 @@ int cg_read_pidref(FILE *f, PidRef *ret) {
132138
for (;;) {
133139
pid_t pid;
134140

135-
r = cg_read_pid(f, &pid);
141+
r = cg_read_pid(f, &pid, flags);
136142
if (r < 0)
137143
return r;
138144
if (r == 0) {
139145
*ret = PIDREF_NULL;
140146
return 0;
141147
}
142148

149+
if (pid == 0)
150+
return -EREMOTE;
151+
143152
r = pidref_set_pid(ret, pid);
144153
if (r >= 0)
145154
return 1;
@@ -343,7 +352,7 @@ static int cg_kill_items(
343352
for (;;) {
344353
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
345354

346-
r = cg_read_pidref(f, &pidref);
355+
r = cg_read_pidref(f, &pidref, /* flags = */ 0);
347356
if (r < 0)
348357
return RET_GATHER(ret, r);
349358
if (r == 0)
@@ -938,7 +947,7 @@ int cg_is_empty(const char *controller, const char *path) {
938947
if (r < 0)
939948
return r;
940949

941-
r = cg_read_pid(f, &pid);
950+
r = cg_read_pid(f, &pid, CGROUP_DONT_SKIP_UNMAPPED);
942951
if (r < 0)
943952
return r;
944953

src/basic/cgroup-util.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,20 +183,21 @@ typedef enum CGroupUnified {
183183
int cg_path_open(const char *controller, const char *path);
184184
int cg_cgroupid_open(int fsfd, uint64_t id);
185185

186+
typedef enum CGroupFlags {
187+
CGROUP_SIGCONT = 1 << 0,
188+
CGROUP_IGNORE_SELF = 1 << 1,
189+
CGROUP_REMOVE = 1 << 2,
190+
CGROUP_DONT_SKIP_UNMAPPED = 1 << 3,
191+
} CGroupFlags;
192+
186193
int cg_enumerate_processes(const char *controller, const char *path, FILE **ret);
187-
int cg_read_pid(FILE *f, pid_t *ret);
188-
int cg_read_pidref(FILE *f, PidRef *ret);
194+
int cg_read_pid(FILE *f, pid_t *ret, CGroupFlags flags);
195+
int cg_read_pidref(FILE *f, PidRef *ret, CGroupFlags flags);
189196
int cg_read_event(const char *controller, const char *path, const char *event, char **ret);
190197

191198
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **ret);
192199
int cg_read_subgroup(DIR *d, char **ret);
193200

194-
typedef enum CGroupFlags {
195-
CGROUP_SIGCONT = 1 << 0,
196-
CGROUP_IGNORE_SELF = 1 << 1,
197-
CGROUP_REMOVE = 1 << 2,
198-
} CGroupFlags;
199-
200201
typedef int (*cg_kill_log_func_t)(const PidRef *pid, int sig, void *userdata);
201202

202203
int cg_kill(const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);

src/cgtop/cgtop.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ static int process(
207207
return r;
208208

209209
g->n_tasks = 0;
210-
while (cg_read_pid(f, &pid) > 0) {
210+
while (cg_read_pid(f, &pid, CGROUP_DONT_SKIP_UNMAPPED) > 0) {
211211

212212
if (arg_count == COUNT_USERSPACE_PROCESSES && pid_is_kernel_thread(pid) > 0)
213213
continue;

src/core/cgroup.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3627,7 +3627,9 @@ int unit_search_main_pid(Unit *u, PidRef *ret) {
36273627
for (;;) {
36283628
_cleanup_(pidref_done) PidRef npidref = PIDREF_NULL;
36293629

3630-
r = cg_read_pidref(f, &npidref);
3630+
/* cg_read_pidref() will return an error on unmapped PIDs.
3631+
* We can't reasonably deal with units that contain those. */
3632+
r = cg_read_pidref(f, &npidref, CGROUP_DONT_SKIP_UNMAPPED);
36313633
if (r < 0)
36323634
return r;
36333635
if (r == 0)
@@ -3669,7 +3671,7 @@ static int unit_watch_pids_in_path(Unit *u, const char *path) {
36693671
for (;;) {
36703672
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
36713673

3672-
r = cg_read_pidref(f, &pid);
3674+
r = cg_read_pidref(f, &pid, /* flags = */ 0);
36733675
if (r == 0)
36743676
break;
36753677
if (r < 0) {

src/core/dbus-unit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) {
13001300
* threaded domain cgroup contains the PIDs of all processes in the subtree and is not
13011301
* readable in the subtree proper. */
13021302

1303-
r = cg_read_pidref(f, &pidref);
1303+
r = cg_read_pidref(f, &pidref, /* flags = */ 0);
13041304
if (IN_SET(r, 0, -EOPNOTSUPP))
13051305
break;
13061306
if (r < 0)

src/shared/cgroup-setup.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,11 @@ int cg_migrate(
614614
if (r < 0)
615615
return RET_GATHER(ret, r);
616616

617-
while ((r = cg_read_pid(f, &pid)) > 0) {
617+
while ((r = cg_read_pid(f, &pid, flags)) > 0) {
618+
/* Throw an error if unmappable PIDs are in output, we can't migrate those. */
619+
if (pid == 0)
620+
return -EREMOTE;
621+
618622
/* This might do weird stuff if we aren't a single-threaded program. However, we
619623
* luckily know we are. */
620624
if (FLAGS_SET(flags, CGROUP_IGNORE_SELF) && pid == getpid_cached())

src/shared/cgroup-show.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static int show_cgroup_one_by_path(
108108
* From https://docs.kernel.org/admin-guide/cgroup-v2.html#threads,
109109
* “cgroup.procs” in a threaded domain cgroup contains the PIDs of all processes in
110110
* the subtree and is not readable in the subtree proper. */
111-
r = cg_read_pid(f, &pid);
111+
r = cg_read_pid(f, &pid, /* flags = */ 0);
112112
if (IN_SET(r, 0, -EOPNOTSUPP))
113113
break;
114114
if (r < 0)

0 commit comments

Comments
 (0)