1 1.15 rin /* $NetBSD: t_mincore.c,v 1.15 2020/02/24 12:20:30 rin Exp $ */ 2 1.1 jruoho 3 1.1 jruoho /*- 4 1.1 jruoho * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 1.1 jruoho * All rights reserved. 6 1.1 jruoho * 7 1.1 jruoho * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jruoho * by Jukka Ruohonen. 9 1.1 jruoho * 10 1.1 jruoho * Redistribution and use in source and binary forms, with or without 11 1.1 jruoho * modification, are permitted provided that the following conditions 12 1.1 jruoho * are met: 13 1.1 jruoho * 1. Redistributions of source code must retain the above copyright 14 1.1 jruoho * notice, this list of conditions and the following disclaimer. 15 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jruoho * notice, this list of conditions and the following disclaimer in the 17 1.1 jruoho * documentation and/or other materials provided with the distribution. 18 1.1 jruoho * 19 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jruoho * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jruoho */ 31 1.2 jruoho 32 1.2 jruoho /*- 33 1.2 jruoho * Copyright (c) 1999 The NetBSD Foundation, Inc. 34 1.2 jruoho * All rights reserved. 35 1.2 jruoho * 36 1.2 jruoho * This code is derived from software contributed to The NetBSD Foundation 37 1.2 jruoho * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 38 1.2 jruoho * NASA Ames Research Center. 39 1.2 jruoho * 40 1.2 jruoho * Redistribution and use in source and binary forms, with or without 41 1.2 jruoho * modification, are permitted provided that the following conditions 42 1.2 jruoho * are met: 43 1.2 jruoho * 1. Redistributions of source code must retain the above copyright 44 1.2 jruoho * notice, this list of conditions and the following disclaimer. 45 1.2 jruoho * 2. Redistributions in binary form must reproduce the above copyright 46 1.2 jruoho * notice, this list of conditions and the following disclaimer in the 47 1.2 jruoho * documentation and/or other materials provided with the distribution. 48 1.2 jruoho * 49 1.2 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 50 1.2 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 51 1.2 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 52 1.2 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 53 1.2 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54 1.2 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55 1.2 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56 1.2 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57 1.2 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58 1.2 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 1.2 jruoho * POSSIBILITY OF SUCH DAMAGE. 60 1.2 jruoho */ 61 1.1 jruoho #include <sys/cdefs.h> 62 1.15 rin __RCSID("$NetBSD: t_mincore.c,v 1.15 2020/02/24 12:20:30 rin Exp $"); 63 1.1 jruoho 64 1.1 jruoho #include <sys/mman.h> 65 1.9 christos #include <sys/stat.h> 66 1.2 jruoho #include <sys/shm.h> 67 1.1 jruoho 68 1.1 jruoho #include <atf-c.h> 69 1.1 jruoho #include <errno.h> 70 1.1 jruoho #include <fcntl.h> 71 1.6 martin #include <kvm.h> 72 1.14 kre #include <signal.h> 73 1.2 jruoho #include <stdio.h> 74 1.1 jruoho #include <stdlib.h> 75 1.2 jruoho #include <string.h> 76 1.1 jruoho #include <unistd.h> 77 1.6 martin #include <sys/resource.h> 78 1.1 jruoho 79 1.1 jruoho static long page = 0; 80 1.1 jruoho static const char path[] = "mincore"; 81 1.2 jruoho static size_t check_residency(void *, size_t); 82 1.2 jruoho 83 1.11 christos #define ATF_REQUIRE_STRERROR(a) ATF_REQUIRE_MSG(a, " (%s)", strerror(errno)) 84 1.11 christos 85 1.13 kre #ifndef PROT_MPROTECT 86 1.13 kre # define PROT_MPROTECT(flags) (0) 87 1.13 kre #endif 88 1.13 kre 89 1.2 jruoho static size_t 90 1.2 jruoho check_residency(void *addr, size_t npgs) 91 1.2 jruoho { 92 1.2 jruoho size_t i, resident; 93 1.2 jruoho char *vec; 94 1.2 jruoho 95 1.2 jruoho vec = malloc(npgs); 96 1.2 jruoho 97 1.2 jruoho ATF_REQUIRE(vec != NULL); 98 1.2 jruoho ATF_REQUIRE(mincore(addr, npgs * page, vec) == 0); 99 1.2 jruoho 100 1.2 jruoho for (i = resident = 0; i < npgs; i++) { 101 1.2 jruoho 102 1.2 jruoho if (vec[i] != 0) 103 1.2 jruoho resident++; 104 1.2 jruoho 105 1.7 martin #if 0 106 1.15 rin (void)fprintf(stderr, "page %p is %sresident\n", 107 1.2 jruoho (char *)addr + (i * page), vec[i] ? "" : "not "); 108 1.7 martin #endif 109 1.2 jruoho } 110 1.2 jruoho 111 1.2 jruoho free(vec); 112 1.2 jruoho 113 1.2 jruoho return resident; 114 1.2 jruoho } 115 1.1 jruoho 116 1.1 jruoho ATF_TC(mincore_err); 117 1.1 jruoho ATF_TC_HEAD(mincore_err, tc) 118 1.1 jruoho { 119 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test errors from mincore(2)"); 120 1.1 jruoho } 121 1.1 jruoho 122 1.1 jruoho ATF_TC_BODY(mincore_err, tc) 123 1.1 jruoho { 124 1.1 jruoho char *map, *vec; 125 1.1 jruoho 126 1.1 jruoho map = mmap(NULL, page, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 127 1.1 jruoho vec = malloc(page); 128 1.1 jruoho 129 1.1 jruoho ATF_REQUIRE(vec != NULL); 130 1.1 jruoho ATF_REQUIRE(map != MAP_FAILED); 131 1.1 jruoho 132 1.1 jruoho errno = 0; 133 1.1 jruoho ATF_REQUIRE_ERRNO(EINVAL, mincore(map, 0, vec) == -1); 134 1.1 jruoho 135 1.1 jruoho errno = 0; 136 1.1 jruoho ATF_REQUIRE_ERRNO(ENOMEM, mincore(0, page, vec) == -1); 137 1.1 jruoho 138 1.1 jruoho errno = 0; 139 1.1 jruoho ATF_REQUIRE_ERRNO(EFAULT, mincore(map, page, (void *)-1) == -1); 140 1.1 jruoho 141 1.1 jruoho free(vec); 142 1.1 jruoho ATF_REQUIRE(munmap(map, page) == 0); 143 1.1 jruoho } 144 1.1 jruoho 145 1.3 jruoho ATF_TC_WITH_CLEANUP(mincore_resid); 146 1.3 jruoho ATF_TC_HEAD(mincore_resid, tc) 147 1.1 jruoho { 148 1.3 jruoho atf_tc_set_md_var(tc, "descr", "Test page residency with mincore(2)"); 149 1.10 christos atf_tc_set_md_var(tc, "require.user", "root"); 150 1.1 jruoho } 151 1.1 jruoho 152 1.3 jruoho ATF_TC_BODY(mincore_resid, tc) 153 1.2 jruoho { 154 1.2 jruoho void *addr, *addr2, *addr3, *buf; 155 1.7 martin size_t npgs = 0, resident; 156 1.2 jruoho struct stat st; 157 1.2 jruoho int fd, rv; 158 1.6 martin struct rlimit rlim; 159 1.6 martin 160 1.6 martin ATF_REQUIRE(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0); 161 1.10 christos /* 162 1.10 christos * Bump the mlock limit to unlimited so the rest of the testcase 163 1.10 christos * passes instead of failing on the mlock call. 164 1.10 christos */ 165 1.10 christos rlim.rlim_max = RLIM_INFINITY; 166 1.7 martin rlim.rlim_cur = rlim.rlim_max; 167 1.7 martin ATF_REQUIRE(setrlimit(RLIMIT_MEMLOCK, &rlim) == 0); 168 1.2 jruoho 169 1.2 jruoho (void)memset(&st, 0, sizeof(struct stat)); 170 1.2 jruoho 171 1.2 jruoho fd = open(path, O_RDWR | O_CREAT, 0700); 172 1.2 jruoho buf = malloc(page * 5); 173 1.2 jruoho 174 1.2 jruoho ATF_REQUIRE(fd >= 0); 175 1.2 jruoho ATF_REQUIRE(buf != NULL); 176 1.2 jruoho 177 1.5 martin rv = write(fd, buf, page * 5); 178 1.5 martin ATF_REQUIRE(rv >= 0); 179 1.2 jruoho 180 1.2 jruoho ATF_REQUIRE(fd >= 0); 181 1.2 jruoho ATF_REQUIRE(fstat(fd, &st) == 0); 182 1.2 jruoho 183 1.2 jruoho addr = mmap(NULL, (size_t)st.st_size, PROT_READ, 184 1.2 jruoho MAP_FILE | MAP_SHARED, fd, (off_t) 0); 185 1.2 jruoho 186 1.2 jruoho ATF_REQUIRE(addr != MAP_FAILED); 187 1.2 jruoho 188 1.2 jruoho (void)close(fd); 189 1.2 jruoho 190 1.2 jruoho npgs = st.st_size / page; 191 1.2 jruoho 192 1.2 jruoho if (st.st_size % page != 0) 193 1.2 jruoho npgs++; 194 1.2 jruoho 195 1.2 jruoho (void)check_residency(addr, npgs); 196 1.2 jruoho 197 1.7 martin rv = mlock(addr, npgs * page); 198 1.7 martin if (rv == -1 && errno == EAGAIN) 199 1.7 martin atf_tc_skip("hit process resource limits"); 200 1.2 jruoho ATF_REQUIRE(munmap(addr, st.st_size) == 0); 201 1.2 jruoho 202 1.2 jruoho npgs = 128; 203 1.2 jruoho 204 1.2 jruoho addr = mmap(NULL, npgs * page, PROT_READ | PROT_WRITE, 205 1.2 jruoho MAP_ANON | MAP_PRIVATE | MAP_WIRED, -1, (off_t)0); 206 1.2 jruoho 207 1.2 jruoho if (addr == MAP_FAILED) 208 1.8 martin atf_tc_skip("could not mmap wired anonymous test area, system " 209 1.7 martin "might be low on memory"); 210 1.2 jruoho 211 1.2 jruoho ATF_REQUIRE(check_residency(addr, npgs) == npgs); 212 1.2 jruoho ATF_REQUIRE(munmap(addr, npgs * page) == 0); 213 1.2 jruoho 214 1.2 jruoho npgs = 128; 215 1.2 jruoho 216 1.2 jruoho addr = mmap(NULL, npgs * page, PROT_READ | PROT_WRITE, 217 1.2 jruoho MAP_ANON | MAP_PRIVATE, -1, (off_t)0); 218 1.2 jruoho 219 1.7 martin ATF_REQUIRE(addr != MAP_FAILED); 220 1.2 jruoho 221 1.3 jruoho /* 222 1.3 jruoho * Check that the in-core pages match the locked pages. 223 1.3 jruoho */ 224 1.2 jruoho ATF_REQUIRE(check_residency(addr, npgs) == 0); 225 1.4 jruoho 226 1.4 jruoho errno = 0; 227 1.4 jruoho if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0 && errno != ENOMEM) 228 1.4 jruoho atf_tc_fail("mlockall(2) failed"); 229 1.7 martin if (errno == ENOMEM) 230 1.7 martin atf_tc_skip("mlockall() exceeded process resource limits"); 231 1.4 jruoho 232 1.7 martin resident = check_residency(addr, npgs); 233 1.7 martin if (resident < npgs) 234 1.7 martin atf_tc_fail("mlockall(MCL_FUTURE) succeeded, still only " 235 1.7 martin "%zu pages of the newly mapped %zu pages are resident", 236 1.7 martin resident, npgs); 237 1.2 jruoho 238 1.2 jruoho addr2 = mmap(NULL, npgs * page, PROT_READ, MAP_ANON, -1, (off_t)0); 239 1.12 kre addr3 = mmap(NULL, npgs * page, PROT_MPROTECT(PROT_READ) | PROT_NONE, 240 1.12 kre MAP_ANON, -1, (off_t)0); 241 1.2 jruoho 242 1.2 jruoho if (addr2 == MAP_FAILED || addr3 == MAP_FAILED) 243 1.8 martin atf_tc_skip("could not mmap more anonymous test pages with " 244 1.7 martin "mlockall(MCL_FUTURE) in effect, system " 245 1.7 martin "might be low on memory"); 246 1.2 jruoho 247 1.2 jruoho ATF_REQUIRE(check_residency(addr2, npgs) == npgs); 248 1.2 jruoho ATF_REQUIRE(check_residency(addr3, npgs) == 0); 249 1.11 christos ATF_REQUIRE_STRERROR(mprotect(addr3, npgs * page, PROT_READ) == 0); 250 1.2 jruoho ATF_REQUIRE(check_residency(addr, npgs) == npgs); 251 1.2 jruoho ATF_REQUIRE(check_residency(addr2, npgs) == npgs); 252 1.2 jruoho 253 1.2 jruoho (void)munlockall(); 254 1.2 jruoho 255 1.11 christos ATF_REQUIRE_STRERROR(madvise(addr2, npgs * page, MADV_FREE) == 0); 256 1.2 jruoho ATF_REQUIRE(check_residency(addr2, npgs) == 0); 257 1.2 jruoho 258 1.2 jruoho (void)memset(addr, 0, npgs * page); 259 1.2 jruoho 260 1.11 christos ATF_REQUIRE_STRERROR(madvise(addr, npgs * page, MADV_FREE) == 0); 261 1.2 jruoho ATF_REQUIRE(check_residency(addr, npgs) == 0); 262 1.2 jruoho 263 1.2 jruoho (void)munmap(addr, npgs * page); 264 1.2 jruoho (void)munmap(addr2, npgs * page); 265 1.2 jruoho (void)munmap(addr3, npgs * page); 266 1.2 jruoho (void)unlink(path); 267 1.10 christos free(buf); 268 1.2 jruoho } 269 1.2 jruoho 270 1.3 jruoho ATF_TC_CLEANUP(mincore_resid, tc) 271 1.2 jruoho { 272 1.2 jruoho (void)unlink(path); 273 1.2 jruoho } 274 1.2 jruoho 275 1.14 kre static volatile int sig_caught; 276 1.14 kre 277 1.14 kre static void 278 1.14 kre sigsys_handler(int signum) 279 1.14 kre { 280 1.14 kre 281 1.14 kre sig_caught = signum; 282 1.14 kre } 283 1.14 kre 284 1.14 kre static int 285 1.14 kre no_kernel_sysvmsg(void) 286 1.14 kre { 287 1.14 kre int id; 288 1.14 kre void (*osig)(int); 289 1.14 kre 290 1.14 kre sig_caught = 0; 291 1.14 kre osig = signal(SIGSYS, sigsys_handler); 292 1.14 kre id = shmget(IPC_PRIVATE, page, IPC_CREAT | S_IRUSR | S_IWUSR); 293 1.14 kre if (sig_caught || id == -1) 294 1.14 kre return 1; 295 1.14 kre 296 1.14 kre (void)shmctl(id, IPC_RMID, 0); 297 1.14 kre (void)signal(SIGSYS, osig); 298 1.14 kre 299 1.14 kre return 0; 300 1.14 kre } 301 1.14 kre 302 1.2 jruoho ATF_TC(mincore_shmseg); 303 1.2 jruoho ATF_TC_HEAD(mincore_shmseg, tc) 304 1.2 jruoho { 305 1.2 jruoho atf_tc_set_md_var(tc, "descr", "residency of shared memory"); 306 1.2 jruoho } 307 1.2 jruoho 308 1.2 jruoho ATF_TC_BODY(mincore_shmseg, tc) 309 1.2 jruoho { 310 1.2 jruoho size_t npgs = 128; 311 1.2 jruoho void *addr = NULL; 312 1.2 jruoho int shmid; 313 1.2 jruoho 314 1.14 kre if (no_kernel_sysvmsg()) 315 1.14 kre atf_tc_skip("No SYSVSHM in kernel"); 316 1.14 kre 317 1.2 jruoho shmid = shmget(IPC_PRIVATE, npgs * page, 318 1.2 jruoho IPC_CREAT | S_IRUSR | S_IWUSR); 319 1.2 jruoho 320 1.11 christos ATF_REQUIRE_STRERROR(shmid != -1); 321 1.2 jruoho 322 1.2 jruoho addr = shmat(shmid, NULL, 0); 323 1.2 jruoho 324 1.11 christos ATF_REQUIRE_STRERROR(addr != NULL); 325 1.2 jruoho ATF_REQUIRE(check_residency(addr, npgs) == 0); 326 1.2 jruoho 327 1.2 jruoho (void)memset(addr, 0xff, npgs * page); 328 1.2 jruoho 329 1.2 jruoho ATF_REQUIRE(check_residency(addr, npgs) == npgs); 330 1.11 christos ATF_REQUIRE_STRERROR(madvise(addr, npgs * page, MADV_FREE) == 0); 331 1.2 jruoho 332 1.2 jruoho /* 333 1.2 jruoho * NOTE! Even though we have MADV_FREE'd the range, 334 1.2 jruoho * there is another reference (the kernel's) to the 335 1.2 jruoho * object which owns the pages. In this case, the 336 1.2 jruoho * kernel does not simply free the pages, as haphazardly 337 1.2 jruoho * freeing pages when there are still references to 338 1.2 jruoho * an object can cause data corruption (say, the other 339 1.2 jruoho * referencer doesn't expect the pages to be freed, 340 1.2 jruoho * and is surprised by the subsequent ZFOD). 341 1.2 jruoho * 342 1.2 jruoho * Because of this, we simply report the number of 343 1.2 jruoho * pages still resident, for information only. 344 1.2 jruoho */ 345 1.2 jruoho npgs = check_residency(addr, npgs); 346 1.2 jruoho 347 1.2 jruoho (void)fprintf(stderr, "%zu pages still resident\n", npgs); 348 1.2 jruoho 349 1.11 christos ATF_REQUIRE_STRERROR(shmdt(addr) == 0); 350 1.11 christos ATF_REQUIRE_STRERROR(shmctl(shmid, IPC_RMID, NULL) == 0); 351 1.2 jruoho } 352 1.2 jruoho 353 1.1 jruoho ATF_TP_ADD_TCS(tp) 354 1.1 jruoho { 355 1.1 jruoho 356 1.1 jruoho page = sysconf(_SC_PAGESIZE); 357 1.1 jruoho ATF_REQUIRE(page >= 0); 358 1.1 jruoho 359 1.1 jruoho ATF_TP_ADD_TC(tp, mincore_err); 360 1.3 jruoho ATF_TP_ADD_TC(tp, mincore_resid); 361 1.2 jruoho ATF_TP_ADD_TC(tp, mincore_shmseg); 362 1.1 jruoho 363 1.1 jruoho return atf_no_error(); 364 1.1 jruoho } 365