Home | History | Annotate | Download | only in regression
      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