• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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