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
main(int argc,char ** argv)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
do_mremap(void)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
setup(void)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
cleanup(void)135 void cleanup(void)
136 {
137 }
138
139 #else
main(void)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