hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/tools/testing/selftests/cgroup/cgroup_util.c
....@@ -15,6 +15,7 @@
1515 #include <unistd.h>
1616
1717 #include "cgroup_util.h"
18
+#include "../clone3/clone3_selftests.h"
1819
1920 static ssize_t read_text(const char *path, char *buf, size_t max_len)
2021 {
....@@ -70,6 +71,16 @@
7071 char *ret = malloc(len);
7172
7273 snprintf(ret, len, "%s/%s_%d", root, name, index);
74
+
75
+ return ret;
76
+}
77
+
78
+char *cg_control(const char *cgroup, const char *control)
79
+{
80
+ size_t len = strlen(cgroup) + strlen(control) + 2;
81
+ char *ret = malloc(len);
82
+
83
+ snprintf(ret, len, "%s/%s", cgroup, control);
7384
7485 return ret;
7586 }
....@@ -148,6 +159,22 @@
148159 return atol(ptr + strlen(key));
149160 }
150161
162
+long cg_read_lc(const char *cgroup, const char *control)
163
+{
164
+ char buf[PAGE_SIZE];
165
+ const char delim[] = "\n";
166
+ char *line;
167
+ long cnt = 0;
168
+
169
+ if (cg_read(cgroup, control, buf, sizeof(buf)))
170
+ return -1;
171
+
172
+ for (line = strtok(buf, delim); line; line = strtok(NULL, delim))
173
+ cnt++;
174
+
175
+ return cnt;
176
+}
177
+
151178 int cg_write(const char *cgroup, const char *control, char *buf)
152179 {
153180 char path[PATH_MAX];
....@@ -192,10 +219,35 @@
192219
193220 int cg_create(const char *cgroup)
194221 {
195
- return mkdir(cgroup, 0644);
222
+ return mkdir(cgroup, 0755);
196223 }
197224
198
-static int cg_killall(const char *cgroup)
225
+int cg_wait_for_proc_count(const char *cgroup, int count)
226
+{
227
+ char buf[10 * PAGE_SIZE] = {0};
228
+ int attempts;
229
+ char *ptr;
230
+
231
+ for (attempts = 10; attempts >= 0; attempts--) {
232
+ int nr = 0;
233
+
234
+ if (cg_read(cgroup, "cgroup.procs", buf, sizeof(buf)))
235
+ break;
236
+
237
+ for (ptr = buf; *ptr; ptr++)
238
+ if (*ptr == '\n')
239
+ nr++;
240
+
241
+ if (nr >= count)
242
+ return 0;
243
+
244
+ usleep(100000);
245
+ }
246
+
247
+ return -1;
248
+}
249
+
250
+int cg_killall(const char *cgroup)
199251 {
200252 char buf[PAGE_SIZE];
201253 char *ptr = buf;
....@@ -226,9 +278,7 @@
226278 retry:
227279 ret = rmdir(cgroup);
228280 if (ret && errno == EBUSY) {
229
- ret = cg_killall(cgroup);
230
- if (ret)
231
- return ret;
281
+ cg_killall(cgroup);
232282 usleep(100);
233283 goto retry;
234284 }
....@@ -239,12 +289,22 @@
239289 return ret;
240290 }
241291
242
-int cg_enter_current(const char *cgroup)
292
+int cg_enter(const char *cgroup, int pid)
243293 {
244294 char pidbuf[64];
245295
246
- snprintf(pidbuf, sizeof(pidbuf), "%d", getpid());
296
+ snprintf(pidbuf, sizeof(pidbuf), "%d", pid);
247297 return cg_write(cgroup, "cgroup.procs", pidbuf);
298
+}
299
+
300
+int cg_enter_current(const char *cgroup)
301
+{
302
+ return cg_write(cgroup, "cgroup.procs", "0");
303
+}
304
+
305
+int cg_enter_current_thread(const char *cgroup)
306
+{
307
+ return cg_write(cgroup, "cgroup.threads", "0");
248308 }
249309
250310 int cg_run(const char *cgroup,
....@@ -272,11 +332,111 @@
272332 }
273333 }
274334
335
+pid_t clone_into_cgroup(int cgroup_fd)
336
+{
337
+#ifdef CLONE_ARGS_SIZE_VER2
338
+ pid_t pid;
339
+
340
+ struct __clone_args args = {
341
+ .flags = CLONE_INTO_CGROUP,
342
+ .exit_signal = SIGCHLD,
343
+ .cgroup = cgroup_fd,
344
+ };
345
+
346
+ pid = sys_clone3(&args, sizeof(struct __clone_args));
347
+ /*
348
+ * Verify that this is a genuine test failure:
349
+ * ENOSYS -> clone3() not available
350
+ * E2BIG -> CLONE_INTO_CGROUP not available
351
+ */
352
+ if (pid < 0 && (errno == ENOSYS || errno == E2BIG))
353
+ goto pretend_enosys;
354
+
355
+ return pid;
356
+
357
+pretend_enosys:
358
+#endif
359
+ errno = ENOSYS;
360
+ return -ENOSYS;
361
+}
362
+
363
+int clone_reap(pid_t pid, int options)
364
+{
365
+ int ret;
366
+ siginfo_t info = {
367
+ .si_signo = 0,
368
+ };
369
+
370
+again:
371
+ ret = waitid(P_PID, pid, &info, options | __WALL | __WNOTHREAD);
372
+ if (ret < 0) {
373
+ if (errno == EINTR)
374
+ goto again;
375
+ return -1;
376
+ }
377
+
378
+ if (options & WEXITED) {
379
+ if (WIFEXITED(info.si_status))
380
+ return WEXITSTATUS(info.si_status);
381
+ }
382
+
383
+ if (options & WSTOPPED) {
384
+ if (WIFSTOPPED(info.si_status))
385
+ return WSTOPSIG(info.si_status);
386
+ }
387
+
388
+ if (options & WCONTINUED) {
389
+ if (WIFCONTINUED(info.si_status))
390
+ return 0;
391
+ }
392
+
393
+ return -1;
394
+}
395
+
396
+int dirfd_open_opath(const char *dir)
397
+{
398
+ return open(dir, O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW | O_PATH);
399
+}
400
+
401
+#define close_prot_errno(fd) \
402
+ if (fd >= 0) { \
403
+ int _e_ = errno; \
404
+ close(fd); \
405
+ errno = _e_; \
406
+ }
407
+
408
+static int clone_into_cgroup_run_nowait(const char *cgroup,
409
+ int (*fn)(const char *cgroup, void *arg),
410
+ void *arg)
411
+{
412
+ int cgroup_fd;
413
+ pid_t pid;
414
+
415
+ cgroup_fd = dirfd_open_opath(cgroup);
416
+ if (cgroup_fd < 0)
417
+ return -1;
418
+
419
+ pid = clone_into_cgroup(cgroup_fd);
420
+ close_prot_errno(cgroup_fd);
421
+ if (pid == 0)
422
+ exit(fn(cgroup, arg));
423
+
424
+ return pid;
425
+}
426
+
275427 int cg_run_nowait(const char *cgroup,
276428 int (*fn)(const char *cgroup, void *arg),
277429 void *arg)
278430 {
279431 int pid;
432
+
433
+ pid = clone_into_cgroup_run_nowait(cgroup, fn, arg);
434
+ if (pid > 0)
435
+ return pid;
436
+
437
+ /* Genuine test failure. */
438
+ if (pid < 0 && errno != ENOSYS)
439
+ return -1;
280440
281441 pid = fork();
282442 if (pid == 0) {
....@@ -368,3 +528,51 @@
368528 close(fd);
369529 return 0;
370530 }
531
+
532
+ssize_t proc_read_text(int pid, bool thread, const char *item, char *buf, size_t size)
533
+{
534
+ char path[PATH_MAX];
535
+
536
+ if (!pid)
537
+ snprintf(path, sizeof(path), "/proc/%s/%s",
538
+ thread ? "thread-self" : "self", item);
539
+ else
540
+ snprintf(path, sizeof(path), "/proc/%d/%s", pid, item);
541
+
542
+ return read_text(path, buf, size);
543
+}
544
+
545
+int proc_read_strstr(int pid, bool thread, const char *item, const char *needle)
546
+{
547
+ char buf[PAGE_SIZE];
548
+
549
+ if (proc_read_text(pid, thread, item, buf, sizeof(buf)) < 0)
550
+ return -1;
551
+
552
+ return strstr(buf, needle) ? 0 : -1;
553
+}
554
+
555
+int clone_into_cgroup_run_wait(const char *cgroup)
556
+{
557
+ int cgroup_fd;
558
+ pid_t pid;
559
+
560
+ cgroup_fd = dirfd_open_opath(cgroup);
561
+ if (cgroup_fd < 0)
562
+ return -1;
563
+
564
+ pid = clone_into_cgroup(cgroup_fd);
565
+ close_prot_errno(cgroup_fd);
566
+ if (pid < 0)
567
+ return -1;
568
+
569
+ if (pid == 0)
570
+ exit(EXIT_SUCCESS);
571
+
572
+ /*
573
+ * We don't care whether this fails. We only care whether the initial
574
+ * clone succeeded.
575
+ */
576
+ (void)clone_reap(pid, WEXITED);
577
+ return 0;
578
+}