1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2017 FUJITSU LIMITED. All rights reserved.
4 * Author: Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
5 */
6
7 /*
8 * This is a regression test for a crash caused by memcg function
9 * reentrant on buggy kernel. When doing rmdir(), a pending signal can
10 * interrupt the execution and lead to cgroup_clear_css_refs()
11 * being entered repeatedly, this results in a BUG_ON().
12 */
13
14 #include <errno.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <sys/mount.h>
19 #include "tst_test.h"
20
21 #define MNTPOINT "memcg"
22 #define SUBDIR "memcg/testdir"
23
24 static int mount_flag;
25 static volatile int sigcounter;
26
sighandler(int sig LTP_ATTRIBUTE_UNUSED)27 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
28 {
29 sigcounter++;
30 }
31
do_child(void)32 static void do_child(void)
33 {
34 while (1)
35 SAFE_KILL(getppid(), SIGUSR1);
36
37 exit(0);
38 }
39
do_test(void)40 static void do_test(void)
41 {
42 pid_t cpid;
43
44 SAFE_SIGNAL(SIGUSR1, sighandler);
45
46 cpid = SAFE_FORK();
47 if (cpid == 0)
48 do_child();
49
50 while (sigcounter < 50000) {
51 if (access(SUBDIR, F_OK))
52 SAFE_MKDIR(SUBDIR, 0644);
53 rmdir(SUBDIR);
54 }
55
56 SAFE_KILL(cpid, SIGKILL);
57 SAFE_WAIT(NULL);
58
59 tst_res(TPASS, "Bug not reproduced");
60 }
61
setup(void)62 static void setup(void)
63 {
64 int ret;
65
66 SAFE_MKDIR(MNTPOINT, 0644);
67
68 ret = mount("memcg", MNTPOINT, "cgroup", 0, "memory");
69 if (ret) {
70 if (errno == ENOENT)
71 tst_brk(TCONF | TERRNO, "memcg not supported");
72
73 tst_brk(TCONF | TERRNO, "mounting memcg failed");
74 }
75 mount_flag = 1;
76 }
77
cleanup(void)78 static void cleanup(void)
79 {
80 if (!access(SUBDIR, F_OK))
81 SAFE_RMDIR(SUBDIR);
82
83 if (mount_flag)
84 tst_umount(MNTPOINT);
85 }
86
87 static struct tst_test test = {
88 .needs_root = 1,
89 .needs_tmpdir = 1,
90 .forks_child = 1,
91 .min_kver = "2.6.24",
92 .setup = setup,
93 .cleanup = cleanup,
94 .test_all = do_test,
95 };
96