1 /*
2 * This is a reproducer from mainline commit
3 * 9d8cebd4bcd7c3878462fdfda34bbcdeb4df7ef4:
4 *
5 * "Strangely, current mbind() doesn't merge vma with neighbor vma
6 * although it's possible. Unfortunately, many vma can reduce
7 * performance..."
8 *
9 * Copyright (C) 2010 Red Hat, Inc.
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it would be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 *
18 * Further, this software is distributed without any warranty that it
19 * is free of the rightful claim of any third person regarding
20 * infringement or the like. Any license provided herein, whether
21 * implied or otherwise, applies only to this software file. Patent
22 * licenses, if any, provided herein do not apply to combinations of
23 * this program with other software, or any other product whatsoever.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 * 02110-1301, USA.
29 */
30 #include "config.h"
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <errno.h>
34 #if HAVE_NUMA_H
35 #include <numa.h>
36 #endif
37 #if HAVE_NUMAIF_H
38 #include <numaif.h>
39 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <limits.h>
45 #include "test.h"
46 #include "safe_macros.h"
47 #include "numa_helper.h"
48
49 char *TCID = "vma02";
50 int TST_TOTAL = 1;
51
52 #ifdef HAVE_NUMA_V2
53
54 static unsigned long pagesize;
55 static int opt_node;
56 static char *opt_nodestr;
57 static option_t options[] = {
58 {"n:", &opt_node, &opt_nodestr},
59 {NULL, NULL, NULL}
60 };
61
62 static void usage(void);
63
main(int argc,char ** argv)64 int main(int argc, char **argv)
65 {
66 FILE *fp;
67 void *addr, *start, *end, *lastend;
68 int node, err, lc;
69 char buf[BUFSIZ];
70 struct bitmask *nmask = numa_allocate_nodemask();
71
72 pagesize = getpagesize();
73 tst_parse_opts(argc, argv, options, usage);
74
75 if (opt_node) {
76 node = SAFE_STRTOL(NULL, opt_nodestr, 1, LONG_MAX);
77 } else {
78 err = get_allowed_nodes(NH_MEMS | NH_MEMS, 1, &node);
79 if (err == -3)
80 tst_brkm(TCONF, NULL, "requires at least one node.");
81 else if (err < 0)
82 tst_brkm(TBROK | TERRNO, NULL, "get_allowed_nodes");
83 }
84 numa_bitmask_setbit(nmask, node);
85
86 for (lc = 0; TEST_LOOPING(lc); lc++) {
87 tst_count = 0;
88 addr = mmap(NULL, pagesize * 3, PROT_WRITE,
89 MAP_ANON | MAP_PRIVATE, 0, 0);
90 if (addr == MAP_FAILED)
91 tst_brkm(TBROK | TERRNO, NULL, "mmap");
92
93 tst_resm(TINFO, "pid = %d addr = %p", getpid(), addr);
94 /* make page populate */
95 memset(addr, 0, pagesize * 3);
96
97 /* first mbind */
98 err = mbind(addr + pagesize, pagesize, MPOL_BIND, nmask->maskp,
99 nmask->size, MPOL_MF_MOVE_ALL);
100 if (err != 0) {
101 if (errno != ENOSYS)
102 tst_brkm(TBROK | TERRNO, NULL, "mbind1");
103 else
104 tst_brkm(TCONF, NULL,
105 "mbind syscall not implemented on this system.");
106 }
107
108 /* second mbind */
109 err = mbind(addr, pagesize * 3, MPOL_DEFAULT, NULL, 0, 0);
110 if (err != 0)
111 tst_brkm(TBROK | TERRNO, NULL, "mbind2");
112
113 /* /proc/self/maps in the form of
114 "00400000-00406000 r-xp 00000000". */
115 fp = fopen("/proc/self/maps", "r");
116 if (fp == NULL)
117 tst_brkm(TBROK | TERRNO, NULL, "fopen");
118
119 while (fgets(buf, BUFSIZ, fp) != NULL) {
120 if (sscanf(buf, "%p-%p ", &start, &end) != 2)
121 continue;
122
123 if (start == addr) {
124 tst_resm(TINFO, "start = %p, end = %p",
125 start, end);
126 if (end == addr + pagesize * 3) {
127 tst_resm(TPASS, "only 1 VMA.");
128 break;
129 }
130
131 lastend = end;
132 while (fgets(buf, BUFSIZ, fp) != NULL) {
133 /* No more VMAs, break */
134 if (sscanf(buf, "%p-%p ", &start,
135 &end) != 2)
136 break;
137 tst_resm(TINFO, "start = %p, end = %p",
138 start, end);
139
140 /* more VMAs found */
141 if (start == lastend)
142 lastend = end;
143 if (end == addr + pagesize * 3) {
144 tst_resm(TFAIL,
145 ">1 unmerged VMAs.");
146 break;
147 }
148 }
149 if (end != addr + pagesize * 3)
150 tst_resm(TFAIL, "no matched VMAs.");
151 break;
152 }
153 }
154 fclose(fp);
155 if (munmap(addr, pagesize * 3) == -1)
156 tst_brkm(TWARN | TERRNO, NULL, "munmap");
157 }
158 tst_exit();
159 }
160
usage(void)161 void usage(void)
162 {
163 printf(" -n Number of NUMA nodes\n");
164 }
165
166 #else
main(void)167 int main(void)
168 {
169 tst_brkm(TCONF, NULL, "test requires libnuma >= 2 and it's development packages");
170 }
171 #endif
172