1 /*
2  * Copyright (c) 2017 Fujitsu Ltd.
3  * Ported: Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /*
20  * This is a regression test about the race in autogroup, this test
21  * can crash the buggy kernel, and the bug has been fixed in:
22  *
23  *   commit 18f649ef344127ef6de23a5a4272dbe2fdb73dde
24  *   Author: Oleg Nesterov <oleg@redhat.com>
25  *   Date:   Mon Nov 14 19:46:09 2016 +0100
26  *
27  *   sched/autogroup: Fix autogroup_move_group() to never skip sched_move_task()
28  */
29 
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include "tst_test.h"
34 
35 #define LOOPS	1000
36 #define PATH_AUTOGROUP	"/proc/sys/kernel/sched_autogroup_enabled"
37 
38 static int orig_autogroup = -1;
39 
do_test(void)40 static void do_test(void)
41 {
42 	int i;
43 
44 	if (!SAFE_FORK()) {
45 		SAFE_FILE_PRINTF(PATH_AUTOGROUP, "%d", 1);
46 		SAFE_SETSID();
47 
48 		if (SAFE_FORK())
49 			pause();
50 
51 		SAFE_KILL(getppid(), SIGKILL);
52 		usleep(1000);
53 
54 		// The child has gone, the grandchild runs with kref == 1
55 		SAFE_FILE_PRINTF(PATH_AUTOGROUP, "%d", 0);
56 		SAFE_SETSID();
57 
58 		// runs with the freed ag/tg
59 		for (i = 0; i < LOOPS; i++)
60 			usleep(10);
61 
62 		TST_CHECKPOINT_WAKE(0);
63 
64 		exit(0);
65 	}
66 
67 	SAFE_WAIT(NULL); // destroy the child's ag/tg
68 
69 	TST_CHECKPOINT_WAIT(0);
70 
71 	tst_res(TPASS, "Bug not reproduced");
72 }
73 
setup(void)74 static void setup(void)
75 {
76 	if (access(PATH_AUTOGROUP, F_OK))
77 		tst_brk(TCONF, "autogroup not supported");
78 
79 	SAFE_FILE_SCANF(PATH_AUTOGROUP, "%d", &orig_autogroup);
80 }
81 
cleanup(void)82 static void cleanup(void)
83 {
84 	if (orig_autogroup != -1)
85 		SAFE_FILE_PRINTF(PATH_AUTOGROUP, "%d", orig_autogroup);
86 }
87 
88 static struct tst_test test = {
89 	.forks_child = 1,
90 	.needs_root = 1,
91 	.needs_checkpoints = 1,
92 	.setup = setup,
93 	.cleanup = cleanup,
94 	.test_all = do_test,
95 };
96