1272343Sngie/* $NetBSD: t_mincore.c,v 1.8 2012/06/08 07:18:58 martin Exp $ */ 2272343Sngie 3272343Sngie/*- 4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc. 5272343Sngie * All rights reserved. 6272343Sngie * 7272343Sngie * This code is derived from software contributed to The NetBSD Foundation 8272343Sngie * by Jukka Ruohonen. 9272343Sngie * 10272343Sngie * Redistribution and use in source and binary forms, with or without 11272343Sngie * modification, are permitted provided that the following conditions 12272343Sngie * are met: 13272343Sngie * 1. Redistributions of source code must retain the above copyright 14272343Sngie * notice, this list of conditions and the following disclaimer. 15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 16272343Sngie * notice, this list of conditions and the following disclaimer in the 17272343Sngie * documentation and/or other materials provided with the distribution. 18272343Sngie * 19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22272343Sngie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29272343Sngie * POSSIBILITY OF SUCH DAMAGE. 30272343Sngie */ 31272343Sngie 32272343Sngie/*- 33272343Sngie * Copyright (c) 1999 The NetBSD Foundation, Inc. 34272343Sngie * All rights reserved. 35272343Sngie * 36272343Sngie * This code is derived from software contributed to The NetBSD Foundation 37272343Sngie * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 38272343Sngie * NASA Ames Research Center. 39272343Sngie * 40272343Sngie * Redistribution and use in source and binary forms, with or without 41272343Sngie * modification, are permitted provided that the following conditions 42272343Sngie * are met: 43272343Sngie * 1. Redistributions of source code must retain the above copyright 44272343Sngie * notice, this list of conditions and the following disclaimer. 45272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 46272343Sngie * notice, this list of conditions and the following disclaimer in the 47272343Sngie * documentation and/or other materials provided with the distribution. 48272343Sngie * 49272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 50272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 51272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 52272343Sngie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 53272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59272343Sngie * POSSIBILITY OF SUCH DAMAGE. 60272343Sngie */ 61272343Sngie#include <sys/cdefs.h> 62272343Sngie__RCSID("$NetBSD: t_mincore.c,v 1.8 2012/06/08 07:18:58 martin Exp $"); 63272343Sngie 64272343Sngie#include <sys/mman.h> 65272343Sngie#include <sys/shm.h> 66272343Sngie 67272343Sngie#include <atf-c.h> 68272343Sngie#include <errno.h> 69272343Sngie#include <fcntl.h> 70272343Sngie#include <kvm.h> 71272343Sngie#include <stdio.h> 72272343Sngie#include <stdlib.h> 73272343Sngie#include <string.h> 74272343Sngie#include <unistd.h> 75272343Sngie#include <sys/resource.h> 76272343Sngie 77276478Sngie#ifdef __FreeBSD__ 78276478Sngie#include <sys/stat.h> 79276478Sngie#endif 80276478Sngie 81272343Sngiestatic long page = 0; 82272343Sngiestatic const char path[] = "mincore"; 83272343Sngiestatic size_t check_residency(void *, size_t); 84272343Sngie 85272343Sngiestatic size_t 86272343Sngiecheck_residency(void *addr, size_t npgs) 87272343Sngie{ 88272343Sngie size_t i, resident; 89272343Sngie char *vec; 90272343Sngie 91272343Sngie vec = malloc(npgs); 92272343Sngie 93272343Sngie ATF_REQUIRE(vec != NULL); 94272343Sngie ATF_REQUIRE(mincore(addr, npgs * page, vec) == 0); 95272343Sngie 96272343Sngie for (i = resident = 0; i < npgs; i++) { 97272343Sngie 98272343Sngie if (vec[i] != 0) 99272343Sngie resident++; 100272343Sngie 101272343Sngie#if 0 102272343Sngie (void)fprintf(stderr, "page 0x%p is %sresident\n", 103272343Sngie (char *)addr + (i * page), vec[i] ? "" : "not "); 104272343Sngie#endif 105272343Sngie } 106272343Sngie 107272343Sngie free(vec); 108272343Sngie 109272343Sngie return resident; 110272343Sngie} 111272343Sngie 112272343SngieATF_TC(mincore_err); 113272343SngieATF_TC_HEAD(mincore_err, tc) 114272343Sngie{ 115272343Sngie atf_tc_set_md_var(tc, "descr", "Test errors from mincore(2)"); 116272343Sngie} 117272343Sngie 118272343SngieATF_TC_BODY(mincore_err, tc) 119272343Sngie{ 120272343Sngie char *map, *vec; 121272343Sngie 122272343Sngie map = mmap(NULL, page, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); 123272343Sngie vec = malloc(page); 124272343Sngie 125272343Sngie ATF_REQUIRE(vec != NULL); 126272343Sngie ATF_REQUIRE(map != MAP_FAILED); 127272343Sngie 128276478Sngie#ifdef __NetBSD__ 129272343Sngie errno = 0; 130272343Sngie ATF_REQUIRE_ERRNO(EINVAL, mincore(map, 0, vec) == -1); 131276478Sngie#endif 132272343Sngie 133272343Sngie errno = 0; 134272343Sngie ATF_REQUIRE_ERRNO(ENOMEM, mincore(0, page, vec) == -1); 135272343Sngie 136272343Sngie errno = 0; 137272343Sngie ATF_REQUIRE_ERRNO(EFAULT, mincore(map, page, (void *)-1) == -1); 138272343Sngie 139272343Sngie free(vec); 140272343Sngie ATF_REQUIRE(munmap(map, page) == 0); 141272343Sngie} 142272343Sngie 143272343SngieATF_TC_WITH_CLEANUP(mincore_resid); 144272343SngieATF_TC_HEAD(mincore_resid, tc) 145272343Sngie{ 146272343Sngie atf_tc_set_md_var(tc, "descr", "Test page residency with mincore(2)"); 147272343Sngie} 148272343Sngie 149272343SngieATF_TC_BODY(mincore_resid, tc) 150272343Sngie{ 151272343Sngie void *addr, *addr2, *addr3, *buf; 152272343Sngie size_t npgs = 0, resident; 153272343Sngie struct stat st; 154272343Sngie int fd, rv; 155272343Sngie struct rlimit rlim; 156272343Sngie 157272343Sngie ATF_REQUIRE(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0); 158272343Sngie rlim.rlim_cur = rlim.rlim_max; 159272343Sngie ATF_REQUIRE(setrlimit(RLIMIT_MEMLOCK, &rlim) == 0); 160272343Sngie 161272343Sngie (void)memset(&st, 0, sizeof(struct stat)); 162272343Sngie 163272343Sngie fd = open(path, O_RDWR | O_CREAT, 0700); 164272343Sngie buf = malloc(page * 5); 165272343Sngie 166272343Sngie ATF_REQUIRE(fd >= 0); 167272343Sngie ATF_REQUIRE(buf != NULL); 168272343Sngie 169272343Sngie rv = write(fd, buf, page * 5); 170272343Sngie ATF_REQUIRE(rv >= 0); 171272343Sngie 172272343Sngie ATF_REQUIRE(fd >= 0); 173272343Sngie ATF_REQUIRE(fstat(fd, &st) == 0); 174272343Sngie 175272343Sngie addr = mmap(NULL, (size_t)st.st_size, PROT_READ, 176272343Sngie MAP_FILE | MAP_SHARED, fd, (off_t) 0); 177272343Sngie 178272343Sngie ATF_REQUIRE(addr != MAP_FAILED); 179272343Sngie 180272343Sngie (void)close(fd); 181272343Sngie 182272343Sngie npgs = st.st_size / page; 183272343Sngie 184272343Sngie if (st.st_size % page != 0) 185272343Sngie npgs++; 186272343Sngie 187272343Sngie (void)check_residency(addr, npgs); 188272343Sngie 189272343Sngie rv = mlock(addr, npgs * page); 190272343Sngie if (rv == -1 && errno == EAGAIN) 191272343Sngie atf_tc_skip("hit process resource limits"); 192272343Sngie ATF_REQUIRE(munmap(addr, st.st_size) == 0); 193272343Sngie 194272343Sngie npgs = 128; 195272343Sngie 196276478Sngie#ifdef __FreeBSD__ 197272343Sngie addr = mmap(NULL, npgs * page, PROT_READ | PROT_WRITE, 198276478Sngie MAP_ANON | MAP_PRIVATE, -1, (off_t)0); 199276478Sngie#else 200276478Sngie addr = mmap(NULL, npgs * page, PROT_READ | PROT_WRITE, 201272343Sngie MAP_ANON | MAP_PRIVATE | MAP_WIRED, -1, (off_t)0); 202276478Sngie#endif 203272343Sngie 204272343Sngie if (addr == MAP_FAILED) 205272343Sngie atf_tc_skip("could not mmap wired anonymous test area, system " 206272343Sngie "might be low on memory"); 207272343Sngie 208276478Sngie#ifdef __FreeBSD__ 209276478Sngie ATF_REQUIRE(mlock(addr, npgs * page) == 0); 210276478Sngie#endif 211272343Sngie ATF_REQUIRE(check_residency(addr, npgs) == npgs); 212272343Sngie ATF_REQUIRE(munmap(addr, npgs * page) == 0); 213272343Sngie 214272343Sngie npgs = 128; 215272343Sngie 216272343Sngie addr = mmap(NULL, npgs * page, PROT_READ | PROT_WRITE, 217272343Sngie MAP_ANON | MAP_PRIVATE, -1, (off_t)0); 218272343Sngie 219272343Sngie ATF_REQUIRE(addr != MAP_FAILED); 220272343Sngie 221272343Sngie /* 222272343Sngie * Check that the in-core pages match the locked pages. 223272343Sngie */ 224272343Sngie ATF_REQUIRE(check_residency(addr, npgs) == 0); 225272343Sngie 226272343Sngie errno = 0; 227272343Sngie if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0 && errno != ENOMEM) 228272343Sngie atf_tc_fail("mlockall(2) failed"); 229272343Sngie if (errno == ENOMEM) 230272343Sngie atf_tc_skip("mlockall() exceeded process resource limits"); 231272343Sngie 232272343Sngie resident = check_residency(addr, npgs); 233272343Sngie if (resident < npgs) 234272343Sngie atf_tc_fail("mlockall(MCL_FUTURE) succeeded, still only " 235272343Sngie "%zu pages of the newly mapped %zu pages are resident", 236272343Sngie resident, npgs); 237272343Sngie 238272343Sngie addr2 = mmap(NULL, npgs * page, PROT_READ, MAP_ANON, -1, (off_t)0); 239272343Sngie addr3 = mmap(NULL, npgs * page, PROT_NONE, MAP_ANON, -1, (off_t)0); 240272343Sngie 241272343Sngie if (addr2 == MAP_FAILED || addr3 == MAP_FAILED) 242272343Sngie atf_tc_skip("could not mmap more anonymous test pages with " 243272343Sngie "mlockall(MCL_FUTURE) in effect, system " 244272343Sngie "might be low on memory"); 245272343Sngie 246272343Sngie ATF_REQUIRE(check_residency(addr2, npgs) == npgs); 247272343Sngie ATF_REQUIRE(check_residency(addr3, npgs) == 0); 248272343Sngie ATF_REQUIRE(mprotect(addr3, npgs * page, PROT_READ) == 0); 249272343Sngie ATF_REQUIRE(check_residency(addr, npgs) == npgs); 250272343Sngie ATF_REQUIRE(check_residency(addr2, npgs) == npgs); 251272343Sngie 252272343Sngie (void)munlockall(); 253272343Sngie 254272343Sngie ATF_REQUIRE(madvise(addr2, npgs * page, MADV_FREE) == 0); 255276478Sngie#ifdef __NetBSD__ 256272343Sngie ATF_REQUIRE(check_residency(addr2, npgs) == 0); 257276478Sngie#endif 258272343Sngie 259272343Sngie (void)memset(addr, 0, npgs * page); 260272343Sngie 261272343Sngie ATF_REQUIRE(madvise(addr, npgs * page, MADV_FREE) == 0); 262276478Sngie#ifdef __NetBSD__ 263272343Sngie ATF_REQUIRE(check_residency(addr, npgs) == 0); 264276478Sngie#endif 265272343Sngie 266272343Sngie (void)munmap(addr, npgs * page); 267272343Sngie (void)munmap(addr2, npgs * page); 268272343Sngie (void)munmap(addr3, npgs * page); 269272343Sngie (void)unlink(path); 270272343Sngie} 271272343Sngie 272272343SngieATF_TC_CLEANUP(mincore_resid, tc) 273272343Sngie{ 274272343Sngie (void)unlink(path); 275272343Sngie} 276272343Sngie 277272343SngieATF_TC(mincore_shmseg); 278272343SngieATF_TC_HEAD(mincore_shmseg, tc) 279272343Sngie{ 280272343Sngie atf_tc_set_md_var(tc, "descr", "residency of shared memory"); 281272343Sngie} 282272343Sngie 283272343SngieATF_TC_BODY(mincore_shmseg, tc) 284272343Sngie{ 285272343Sngie size_t npgs = 128; 286272343Sngie void *addr = NULL; 287272343Sngie int shmid; 288272343Sngie 289272343Sngie shmid = shmget(IPC_PRIVATE, npgs * page, 290272343Sngie IPC_CREAT | S_IRUSR | S_IWUSR); 291272343Sngie 292272343Sngie ATF_REQUIRE(shmid != -1); 293272343Sngie 294272343Sngie addr = shmat(shmid, NULL, 0); 295272343Sngie 296272343Sngie ATF_REQUIRE(addr != NULL); 297272343Sngie ATF_REQUIRE(check_residency(addr, npgs) == 0); 298272343Sngie 299272343Sngie (void)memset(addr, 0xff, npgs * page); 300272343Sngie 301272343Sngie ATF_REQUIRE(check_residency(addr, npgs) == npgs); 302272343Sngie ATF_REQUIRE(madvise(addr, npgs * page, MADV_FREE) == 0); 303272343Sngie 304272343Sngie /* 305272343Sngie * NOTE! Even though we have MADV_FREE'd the range, 306272343Sngie * there is another reference (the kernel's) to the 307272343Sngie * object which owns the pages. In this case, the 308272343Sngie * kernel does not simply free the pages, as haphazardly 309272343Sngie * freeing pages when there are still references to 310272343Sngie * an object can cause data corruption (say, the other 311272343Sngie * referencer doesn't expect the pages to be freed, 312272343Sngie * and is surprised by the subsequent ZFOD). 313272343Sngie * 314272343Sngie * Because of this, we simply report the number of 315272343Sngie * pages still resident, for information only. 316272343Sngie */ 317272343Sngie npgs = check_residency(addr, npgs); 318272343Sngie 319272343Sngie (void)fprintf(stderr, "%zu pages still resident\n", npgs); 320272343Sngie 321272343Sngie ATF_REQUIRE(shmdt(addr) == 0); 322272343Sngie ATF_REQUIRE(shmctl(shmid, IPC_RMID, NULL) == 0); 323272343Sngie} 324272343Sngie 325272343SngieATF_TP_ADD_TCS(tp) 326272343Sngie{ 327272343Sngie 328272343Sngie page = sysconf(_SC_PAGESIZE); 329272343Sngie ATF_REQUIRE(page >= 0); 330272343Sngie 331272343Sngie ATF_TP_ADD_TC(tp, mincore_err); 332272343Sngie ATF_TP_ADD_TC(tp, mincore_resid); 333272343Sngie ATF_TP_ADD_TC(tp, mincore_shmseg); 334272343Sngie 335272343Sngie return atf_no_error(); 336272343Sngie} 337