1 /* 2 * Copyright (c) 2017 Fujitsu Ltd. 3 * Author: Guangwen Feng <fenggw-fnst (at) 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 for a crash caused by memcg function 21 * reentrant on RHEL6. When doing rmdir(), a pending signal can 22 * interrupt the execution and lead to cgroup_clear_css_refs() 23 * being entered repeatedly, this results in a BUG_ON(). 24 * 25 * This bug was introduced by following RHEL6 patch on 2.6.32-488.el6: 26 * 27 * [mm] memcg: fix race condition between memcg teardown and swapin 28 * Link: https://bugzilla.redhat.com/show_bug.cgi?id=1001197 29 * Patch: ftp://partners.redhat.com/1c5d859a/de6aafa8185ed8fd934f2debc72b79eb/kernel-individual-patch/rhel6/v2.6.32-to-kernel-2.6.32-488.el6.tar.bz2 30 * 31675-mm-memcg-fix-race-condition-between-memcg-teardown-.patch 31 * 32 * This test can crash the buggy kernel on RHEL6.6GA, and the bug 33 * was fixed by following patch on 2.6.32-536.el6: 34 * 35 * [mm] memcg: fix crash in re-entrant cgroup_clear_css_refs() 36 * Link: https://bugzilla.redhat.com/show_bug.cgi?id=1168185 37 * Patch: ftp://partners.redhat.com/1c5d859a/de6aafa8185ed8fd934f2debc72b79eb/kernel-individual-patch/rhel6/v2.6.32-to-kernel-2.6.32-536.el6.tar.bz2 38 * 35944-mm-memcg-fix-crash-in-re-entrant-cgroup_clear_css_r.patch 39 */ 40 41 #include <errno.h> 42 #include <unistd.h> 43 #include <stdlib.h> 44 #include <sys/types.h> 45 #include <sys/mount.h> 46 #include "tst_test.h" 47 48 #define MNTPOINT "memcg" 49 #define SUBDIR "memcg/testdir" 50 51 static int mount_flag; 52 static volatile int sigcounter; 53 54 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) 55 { 56 sigcounter++; 57 } 58 59 static void do_child(void) 60 { 61 while (1) 62 SAFE_KILL(getppid(), SIGUSR1); 63 64 exit(0); 65 } 66 67 static void do_test(void) 68 { 69 pid_t cpid; 70 71 SAFE_SIGNAL(SIGUSR1, sighandler); 72 73 cpid = SAFE_FORK(); 74 if (cpid == 0) 75 do_child(); 76 77 while (sigcounter < 50000) { 78 if (access(SUBDIR, F_OK)) 79 SAFE_MKDIR(SUBDIR, 0644); 80 rmdir(SUBDIR); 81 } 82 83 SAFE_KILL(cpid, SIGKILL); 84 SAFE_WAIT(NULL); 85 86 tst_res(TPASS, "Bug not reproduced"); 87 } 88 89 static void setup(void) 90 { 91 int ret; 92 93 SAFE_MKDIR(MNTPOINT, 0644); 94 95 ret = mount("memcg", MNTPOINT, "cgroup", 0, "memory"); 96 if (ret) { 97 if (errno == ENOENT) 98 tst_brk(TCONF | TERRNO, "memcg not supported"); 99 100 tst_brk(TCONF | TERRNO, "mounting memcg failed"); 101 } 102 mount_flag = 1; 103 } 104 105 static void cleanup(void) 106 { 107 if (!access(SUBDIR, F_OK)) 108 SAFE_RMDIR(SUBDIR); 109 110 if (mount_flag) 111 tst_umount(MNTPOINT); 112 } 113 114 static struct tst_test test = { 115 .needs_root = 1, 116 .needs_tmpdir = 1, 117 .forks_child = 1, 118 .min_kver = "2.6.24", 119 .setup = setup, 120 .cleanup = cleanup, 121 .test_all = do_test, 122 }; 123