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