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