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