Home | History | Annotate | Download | only in thp
      1 /*
      2  * Copyright (C) 2011  Red Hat, Inc.
      3  * This program is free software; you can redistribute it and/or
      4  * modify it under the terms of version 2 of the GNU General Public
      5  * License as published by the Free Software Foundation.
      6  *
      7  * This program is distributed in the hope that it would be useful,
      8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     10  *
     11  * Further, this software is distributed without any warranty that it
     12  * is free of the rightful claim of any third person regarding
     13  * infringement or the like.  Any license provided herein, whether
     14  * implied or otherwise, applies only to this software file.  Patent
     15  * licenses, if any, provided herein do not apply to combinations of
     16  * this program with other software, or any other product whatsoever.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write the Free Software
     20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     21  * 02110-1301, USA.
     22  *
     23  * thp02 - detect mremap bug when THP is enabled.
     24  *
     25  * There was a bug in mremap THP support, sometimes crash happened
     26  * due to the following reason according to developers:
     27  *
     28  * "alloc_new_pmd was forcing the allocation of a pte before calling
     29  * move_huge_page and that resulted in a VM_BUG_ON in move_huge_page
     30  * because the pmd wasn't zero."
     31  *
     32  * There are 4 cases to test this bug:
     33  *
     34  * 1) old_addr hpage aligned, old_end not hpage aligned, new_addr
     35  *    hpage aligned;
     36  * 2) old_addr hpage aligned, old_end not hpage aligned, new_addr not
     37  *    hpage aligned;
     38  * 3) old_addr not hpage aligned, old_end hpage aligned, new_addr
     39  *    hpage aligned;
     40  * 4) old_addr not hpage aligned, old_end hpage aligned, new_addr not
     41  *    hpage aligned.
     42  *
     43  */
     44 
     45 #define _GNU_SOURCE
     46 #include "config.h"
     47 #include <sys/types.h>
     48 #include <sys/mman.h>
     49 #include <stdio.h>
     50 #include <stdlib.h>
     51 #include <string.h>
     52 #include <unistd.h>
     53 #include "mem.h"
     54 
     55 char *TCID = "thp02";
     56 int TST_TOTAL = 1;
     57 
     58 #ifdef HAVE_MREMAP_FIXED
     59 static int ps;
     60 static long hps, size;
     61 static void *p, *p2, *p3, *p4;
     62 
     63 static void do_mremap(void);
     64 
     65 int main(int argc, char **argv)
     66 {
     67 	int lc;
     68 
     69 	tst_parse_opts(argc, argv, NULL, NULL);
     70 
     71 	setup();
     72 
     73 	for (lc = 0; TEST_LOOPING(lc); lc++) {
     74 		tst_count = 0;
     75 
     76 		do_mremap();
     77 	}
     78 	tst_resm(TPASS, "Still alive.");
     79 
     80 	cleanup();
     81 	tst_exit();
     82 
     83 }
     84 
     85 static void do_mremap(void)
     86 {
     87 	int i;
     88 	void *old_addr, *new_addr;
     89 
     90 	for (i = 0; i < 4; i++) {
     91 		if (posix_memalign(&p, hps, size))
     92 			tst_brkm(TBROK | TERRNO, cleanup, "memalign p");
     93 		if (posix_memalign(&p2, hps, size))
     94 			tst_brkm(TBROK | TERRNO, cleanup, "memalign p2");
     95 		if (posix_memalign(&p3, hps, size))
     96 			tst_brkm(TBROK | TERRNO, cleanup, "memalign p3");
     97 
     98 		memset(p, 0xff, size);
     99 		memset(p2, 0xff, size);
    100 		memset(p3, 0x77, size);
    101 
    102 		/*
    103 		 * Will try to do the following 4 mremaps cases:
    104 		 *   mremap(p, size-ps, size-ps, flag, p3);
    105 		 *   mremap(p, size-ps, size-ps, flag, p3+ps);
    106 		 *   mremap(p+ps, size-ps, size-ps, flag, p3);
    107 		 *   mremap(p+ps, size-ps, size-ps, flag, p3+ps);
    108 		 */
    109 		old_addr = p + ps * (i >> 1);
    110 		new_addr = p3 + ps * (i & 1);
    111 		tst_resm(TINFO, "mremap %p to %p", old_addr, new_addr);
    112 
    113 		p4 = mremap(old_addr, size - ps, size - ps,
    114 			    MREMAP_FIXED | MREMAP_MAYMOVE, new_addr);
    115 		if (p4 == MAP_FAILED)
    116 			tst_brkm(TBROK | TERRNO, cleanup, "mremap");
    117 		if (memcmp(p4, p2, size - ps))
    118 			tst_brkm(TBROK, cleanup, "mremap bug");
    119 	}
    120 }
    121 
    122 void setup(void)
    123 {
    124 	if (access(PATH_THP, F_OK) == -1)
    125 		tst_brkm(TCONF, NULL, "THP not enabled in kernel?");
    126 
    127 	tst_sig(FORK, DEF_HANDLER, cleanup);
    128 	TEST_PAUSE;
    129 
    130 	ps = sysconf(_SC_PAGESIZE);
    131 	hps = read_meminfo("Hugepagesize:") * 1024;
    132 	size = hps * 4;
    133 }
    134 
    135 void cleanup(void)
    136 {
    137 }
    138 
    139 #else
    140 int main(void)
    141 {
    142 	tst_brkm(TCONF, NULL, "MREMAP_FIXED not present in <sys/mman.h>");
    143 }
    144 #endif /* HAVE_MREMAP_FIXED */
    145