Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 
0003 #include <errno.h>
0004 #include <linux/limits.h>
0005 #include <stdbool.h>
0006 #include <stdio.h>
0007 #include <stdlib.h>
0008 #include <string.h>
0009 #include <sys/types.h>
0010 #include <unistd.h>
0011 
0012 #include "../kselftest.h"
0013 #include "../pidfd/pidfd.h"
0014 #include "cgroup_util.h"
0015 
0016 /*
0017  * Kill the given cgroup and wait for the inotify signal.
0018  * If there are no events in 10 seconds, treat this as an error.
0019  * Then check that the cgroup is in the desired state.
0020  */
0021 static int cg_kill_wait(const char *cgroup)
0022 {
0023     int fd, ret = -1;
0024 
0025     fd = cg_prepare_for_wait(cgroup);
0026     if (fd < 0)
0027         return fd;
0028 
0029     ret = cg_write(cgroup, "cgroup.kill", "1");
0030     if (ret)
0031         goto out;
0032 
0033     ret = cg_wait_for(fd);
0034     if (ret)
0035         goto out;
0036 
0037 out:
0038     close(fd);
0039     return ret;
0040 }
0041 
0042 /*
0043  * A simple process running in a sleep loop until being
0044  * re-parented.
0045  */
0046 static int child_fn(const char *cgroup, void *arg)
0047 {
0048     int ppid = getppid();
0049 
0050     while (getppid() == ppid)
0051         usleep(1000);
0052 
0053     return getppid() == ppid;
0054 }
0055 
0056 static int test_cgkill_simple(const char *root)
0057 {
0058     pid_t pids[100];
0059     int ret = KSFT_FAIL;
0060     char *cgroup = NULL;
0061     int i;
0062 
0063     cgroup = cg_name(root, "cg_test_simple");
0064     if (!cgroup)
0065         goto cleanup;
0066 
0067     if (cg_create(cgroup))
0068         goto cleanup;
0069 
0070     for (i = 0; i < 100; i++)
0071         pids[i] = cg_run_nowait(cgroup, child_fn, NULL);
0072 
0073     if (cg_wait_for_proc_count(cgroup, 100))
0074         goto cleanup;
0075 
0076     if (cg_read_strcmp(cgroup, "cgroup.events", "populated 1\n"))
0077         goto cleanup;
0078 
0079     if (cg_kill_wait(cgroup))
0080         goto cleanup;
0081 
0082     ret = KSFT_PASS;
0083 
0084 cleanup:
0085     for (i = 0; i < 100; i++)
0086         wait_for_pid(pids[i]);
0087 
0088     if (ret == KSFT_PASS &&
0089         cg_read_strcmp(cgroup, "cgroup.events", "populated 0\n"))
0090         ret = KSFT_FAIL;
0091 
0092     if (cgroup)
0093         cg_destroy(cgroup);
0094     free(cgroup);
0095     return ret;
0096 }
0097 
0098 /*
0099  * The test creates the following hierarchy:
0100  *       A
0101  *    / / \ \
0102  *   B  E  I K
0103  *  /\  |
0104  * C  D F
0105  *      |
0106  *      G
0107  *      |
0108  *      H
0109  *
0110  * with a process in C, H and 3 processes in K.
0111  * Then it tries to kill the whole tree.
0112  */
0113 static int test_cgkill_tree(const char *root)
0114 {
0115     pid_t pids[5];
0116     char *cgroup[10] = {0};
0117     int ret = KSFT_FAIL;
0118     int i;
0119 
0120     cgroup[0] = cg_name(root, "cg_test_tree_A");
0121     if (!cgroup[0])
0122         goto cleanup;
0123 
0124     cgroup[1] = cg_name(cgroup[0], "B");
0125     if (!cgroup[1])
0126         goto cleanup;
0127 
0128     cgroup[2] = cg_name(cgroup[1], "C");
0129     if (!cgroup[2])
0130         goto cleanup;
0131 
0132     cgroup[3] = cg_name(cgroup[1], "D");
0133     if (!cgroup[3])
0134         goto cleanup;
0135 
0136     cgroup[4] = cg_name(cgroup[0], "E");
0137     if (!cgroup[4])
0138         goto cleanup;
0139 
0140     cgroup[5] = cg_name(cgroup[4], "F");
0141     if (!cgroup[5])
0142         goto cleanup;
0143 
0144     cgroup[6] = cg_name(cgroup[5], "G");
0145     if (!cgroup[6])
0146         goto cleanup;
0147 
0148     cgroup[7] = cg_name(cgroup[6], "H");
0149     if (!cgroup[7])
0150         goto cleanup;
0151 
0152     cgroup[8] = cg_name(cgroup[0], "I");
0153     if (!cgroup[8])
0154         goto cleanup;
0155 
0156     cgroup[9] = cg_name(cgroup[0], "K");
0157     if (!cgroup[9])
0158         goto cleanup;
0159 
0160     for (i = 0; i < 10; i++)
0161         if (cg_create(cgroup[i]))
0162             goto cleanup;
0163 
0164     pids[0] = cg_run_nowait(cgroup[2], child_fn, NULL);
0165     pids[1] = cg_run_nowait(cgroup[7], child_fn, NULL);
0166     pids[2] = cg_run_nowait(cgroup[9], child_fn, NULL);
0167     pids[3] = cg_run_nowait(cgroup[9], child_fn, NULL);
0168     pids[4] = cg_run_nowait(cgroup[9], child_fn, NULL);
0169 
0170     /*
0171      * Wait until all child processes will enter
0172      * corresponding cgroups.
0173      */
0174 
0175     if (cg_wait_for_proc_count(cgroup[2], 1) ||
0176         cg_wait_for_proc_count(cgroup[7], 1) ||
0177         cg_wait_for_proc_count(cgroup[9], 3))
0178         goto cleanup;
0179 
0180     /*
0181      * Kill A and check that we get an empty notification.
0182      */
0183     if (cg_kill_wait(cgroup[0]))
0184         goto cleanup;
0185 
0186     ret = KSFT_PASS;
0187 
0188 cleanup:
0189     for (i = 0; i < 5; i++)
0190         wait_for_pid(pids[i]);
0191 
0192     if (ret == KSFT_PASS &&
0193         cg_read_strcmp(cgroup[0], "cgroup.events", "populated 0\n"))
0194         ret = KSFT_FAIL;
0195 
0196     for (i = 9; i >= 0 && cgroup[i]; i--) {
0197         cg_destroy(cgroup[i]);
0198         free(cgroup[i]);
0199     }
0200 
0201     return ret;
0202 }
0203 
0204 static int forkbomb_fn(const char *cgroup, void *arg)
0205 {
0206     int ppid;
0207 
0208     fork();
0209     fork();
0210 
0211     ppid = getppid();
0212 
0213     while (getppid() == ppid)
0214         usleep(1000);
0215 
0216     return getppid() == ppid;
0217 }
0218 
0219 /*
0220  * The test runs a fork bomb in a cgroup and tries to kill it.
0221  */
0222 static int test_cgkill_forkbomb(const char *root)
0223 {
0224     int ret = KSFT_FAIL;
0225     char *cgroup = NULL;
0226     pid_t pid = -ESRCH;
0227 
0228     cgroup = cg_name(root, "cg_forkbomb_test");
0229     if (!cgroup)
0230         goto cleanup;
0231 
0232     if (cg_create(cgroup))
0233         goto cleanup;
0234 
0235     pid = cg_run_nowait(cgroup, forkbomb_fn, NULL);
0236     if (pid < 0)
0237         goto cleanup;
0238 
0239     usleep(100000);
0240 
0241     if (cg_kill_wait(cgroup))
0242         goto cleanup;
0243 
0244     if (cg_wait_for_proc_count(cgroup, 0))
0245         goto cleanup;
0246 
0247     ret = KSFT_PASS;
0248 
0249 cleanup:
0250     if (pid > 0)
0251         wait_for_pid(pid);
0252 
0253     if (ret == KSFT_PASS &&
0254         cg_read_strcmp(cgroup, "cgroup.events", "populated 0\n"))
0255         ret = KSFT_FAIL;
0256 
0257     if (cgroup)
0258         cg_destroy(cgroup);
0259     free(cgroup);
0260     return ret;
0261 }
0262 
0263 #define T(x) { x, #x }
0264 struct cgkill_test {
0265     int (*fn)(const char *root);
0266     const char *name;
0267 } tests[] = {
0268     T(test_cgkill_simple),
0269     T(test_cgkill_tree),
0270     T(test_cgkill_forkbomb),
0271 };
0272 #undef T
0273 
0274 int main(int argc, char *argv[])
0275 {
0276     char root[PATH_MAX];
0277     int i, ret = EXIT_SUCCESS;
0278 
0279     if (cg_find_unified_root(root, sizeof(root)))
0280         ksft_exit_skip("cgroup v2 isn't mounted\n");
0281     for (i = 0; i < ARRAY_SIZE(tests); i++) {
0282         switch (tests[i].fn(root)) {
0283         case KSFT_PASS:
0284             ksft_test_result_pass("%s\n", tests[i].name);
0285             break;
0286         case KSFT_SKIP:
0287             ksft_test_result_skip("%s\n", tests[i].name);
0288             break;
0289         default:
0290             ret = EXIT_FAILURE;
0291             ksft_test_result_fail("%s\n", tests[i].name);
0292             break;
0293         }
0294     }
0295 
0296     return ret;
0297 }