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 44 static long page = 0; 45 static const off_t off = 512; 46 static const char path[] = "msync"; 47 48 static const char *msync_sync(const char *, int); 49 50 static const char * 51 msync_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 118 out: 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 130 ATF_TC(msync_async); 131 ATF_TC_HEAD(msync_async, tc) 132 { 133 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_ASYNC"); 134 } 135 136 ATF_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 146 ATF_TC(msync_err); 147 ATF_TC_HEAD(msync_err, tc) 148 { 149 atf_tc_set_md_var(tc, "descr", "Test error conditions in msync(2)"); 150 } 151 152 ATF_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 189 ATF_TC(msync_invalidate); 190 ATF_TC_HEAD(msync_invalidate, tc) 191 { 192 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_INVALIDATE"); 193 } 194 195 ATF_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 205 ATF_TC(msync_sync); 206 ATF_TC_HEAD(msync_sync, tc) 207 { 208 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_SYNC"); 209 } 210 211 ATF_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 221 ATF_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