1/* $NetBSD: t_msync.c,v 1.3 2017/01/14 20:52:42 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jukka Ruohonen. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31#include <sys/cdefs.h> 32__RCSID("$NetBSD: t_msync.c,v 1.3 2017/01/14 20:52:42 christos Exp $"); 33 34#include <sys/mman.h> 35 36#include <atf-c.h> 37#include <errno.h> 38#include <fcntl.h> 39#include <limits.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43 44static long page = 0; 45static const off_t off = 512; 46static const char path[] = "msync"; 47 48static const char *msync_sync(const char *, int); 49 50static const char * 51msync_sync(const char *garbage, int flags) 52{ 53 char *buf, *map = MAP_FAILED; 54 const char *str = NULL; 55 size_t len; 56 int fd, rv; 57 58 /* 59 * Create a temporary file, write 60 * one page to it, and map the file. 61 */ 62 buf = malloc(page); 63 64 if (buf == NULL) 65 return NULL; 66 67 memset(buf, 'x', page); 68 69 fd = open(path, O_RDWR | O_CREAT, 0700); 70 71 if (fd < 0) { 72 free(buf); 73 return "failed to open"; 74 } 75 76 ATF_REQUIRE_MSG(write(fd, buf, page) != -1, "write(2) failed: %s", 77 strerror(errno)); 78 79 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE, 80 fd, 0); 81 82 if (map == MAP_FAILED) { 83 str = "failed to map"; 84 goto out; 85 } 86 87 /* 88 * Seek to an arbitrary offset and 89 * write garbage to this position. 90 */ 91 if (lseek(fd, off, SEEK_SET) != off) { 92 str = "failed to seek"; 93 goto out; 94 } 95 96 len = strlen(garbage); 97 rv = write(fd, garbage, len); 98 99 if (rv != (ssize_t)len) { 100 str = "failed to write garbage"; 101 goto out; 102 } 103 104 /* 105 * Synchronize the mapping and verify 106 * that garbage is at the given offset. 107 */ 108 if (msync(map, page, flags) != 0) { 109 str = "failed to msync"; 110 goto out; 111 } 112 113 if (memcmp(map + off, garbage, len) != 0) { 114 str = "msync did not synchronize"; 115 goto out; 116 } 117 118out: 119 free(buf); 120 121 (void)close(fd); 122 (void)unlink(path); 123 124 if (map != MAP_FAILED) 125 (void)munmap(map, page); 126 127 return str; 128} 129 130ATF_TC(msync_async); 131ATF_TC_HEAD(msync_async, tc) 132{ 133 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_ASYNC"); 134} 135 136ATF_TC_BODY(msync_async, tc) 137{ 138 const char *str; 139 140 str = msync_sync("garbage", MS_ASYNC); 141 142 if (str != NULL) 143 atf_tc_fail("%s", str); 144} 145 146ATF_TC(msync_err); 147ATF_TC_HEAD(msync_err, tc) 148{ 149 atf_tc_set_md_var(tc, "descr", "Test error conditions in msync(2)"); 150} 151 152ATF_TC_BODY(msync_err, tc) 153{ 154 155 char *map = MAP_FAILED; 156 157 /* 158 * Test that invalid flags error out. 159 */ 160#ifdef __FreeBSD__ 161 errno = 0; 162 ATF_REQUIRE_ERRNO(EINVAL, msync_sync("error", -1) != NULL); 163 errno = 0; 164 ATF_REQUIRE_ERRNO(EINVAL, msync_sync("error", INT_MAX) != NULL); 165#else 166 ATF_REQUIRE(msync_sync("error", -1) != NULL); 167 ATF_REQUIRE(msync_sync("error", INT_MAX) != NULL); 168#endif 169 170 errno = 0; 171 172 /* 173 * Map a page and then unmap to get an unmapped address. 174 */ 175 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 176 -1, 0); 177 ATF_REQUIRE(map != MAP_FAILED); 178 179 (void)munmap(map, page); 180 181 ATF_REQUIRE(msync(map, page, MS_SYNC) != 0); 182#ifdef __FreeBSD__ 183 ATF_REQUIRE(errno == ENOMEM); 184#else 185 ATF_REQUIRE(errno == EFAULT); 186#endif 187} 188 189ATF_TC(msync_invalidate); 190ATF_TC_HEAD(msync_invalidate, tc) 191{ 192 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_INVALIDATE"); 193} 194 195ATF_TC_BODY(msync_invalidate, tc) 196{ 197 const char *str; 198 199 str = msync_sync("garbage", MS_INVALIDATE); 200 201 if (str != NULL) 202 atf_tc_fail("%s", str); 203} 204 205ATF_TC(msync_sync); 206ATF_TC_HEAD(msync_sync, tc) 207{ 208 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_SYNC"); 209} 210 211ATF_TC_BODY(msync_sync, tc) 212{ 213 const char *str; 214 215 str = msync_sync("garbage", MS_SYNC); 216 217 if (str != NULL) 218 atf_tc_fail("%s", str); 219} 220 221ATF_TP_ADD_TCS(tp) 222{ 223 224 page = sysconf(_SC_PAGESIZE); 225 226 ATF_REQUIRE(page >= 0); 227 ATF_REQUIRE(page > off); 228 229 ATF_TP_ADD_TC(tp, msync_async); 230 ATF_TP_ADD_TC(tp, msync_err); 231 ATF_TP_ADD_TC(tp, msync_invalidate); 232 ATF_TP_ADD_TC(tp, msync_sync); 233 234 return atf_no_error(); 235} 236