1 /* $NetBSD: t_msync.c,v 1.2 2012/03/16 06:15:17 matt 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.2 2012/03/16 06:15:17 matt 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 #ifdef __FreeBSD__ 56 size_t len; 57 #else 58 size_t i, len; 59 ssize_t tot; 60 #endif 61 int fd, rv; 62 63 /* 64 * Create a temporary file, write 65 * one page to it, and map the file. 66 */ 67 buf = malloc(page); 68 69 if (buf == NULL) 70 return NULL; 71 72 #ifdef __FreeBSD__ 73 memset(buf, 'x', page); 74 #else 75 for (i = 0; i < (size_t)page; i++) 76 buf[i] = 'x'; 77 #endif 78 79 fd = open(path, O_RDWR | O_CREAT, 0700); 80 81 if (fd < 0) { 82 #ifdef __FreeBSD__ 83 free(buf); 84 return "failed to open"; 85 #else 86 str = "failed to open"; 87 goto out; 88 #endif 89 } 90 91 #if __FreeBSD__ 92 (void)write(fd, buf, page); 93 #else 94 tot = 0; 95 96 while (tot < page) { 97 98 rv = write(fd, buf, sizeof(buf)); 99 if (rv < 0) { 100 str = "failed to write"; 101 goto out; 102 } 103 104 tot += rv; 105 } 106 #endif 107 108 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE, 109 fd, 0); 110 111 if (map == MAP_FAILED) { 112 str = "failed to map"; 113 goto out; 114 } 115 116 /* 117 * Seek to an arbitrary offset and 118 * write garbage to this position. 119 */ 120 if (lseek(fd, off, SEEK_SET) != off) { 121 str = "failed to seek"; 122 goto out; 123 } 124 125 len = strlen(garbage); 126 rv = write(fd, garbage, len); 127 128 if (rv != (ssize_t)len) { 129 str = "failed to write garbage"; 130 goto out; 131 } 132 133 /* 134 * Synchronize the mapping and verify 135 * that garbage is at the given offset. 136 */ 137 if (msync(map, page, flags) != 0) { 138 str = "failed to msync"; 139 goto out; 140 } 141 142 if (memcmp(map + off, garbage, len) != 0) { 143 str = "msync did not synchronize"; 144 goto out; 145 } 146 147 out: 148 free(buf); 149 150 (void)close(fd); 151 (void)unlink(path); 152 153 if (map != MAP_FAILED) 154 (void)munmap(map, page); 155 156 return str; 157 } 158 159 ATF_TC(msync_async); 160 ATF_TC_HEAD(msync_async, tc) 161 { 162 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_ASYNC"); 163 } 164 165 ATF_TC_BODY(msync_async, tc) 166 { 167 const char *str; 168 169 str = msync_sync("garbage", MS_ASYNC); 170 171 if (str != NULL) 172 atf_tc_fail("%s", str); 173 } 174 175 ATF_TC(msync_err); 176 ATF_TC_HEAD(msync_err, tc) 177 { 178 atf_tc_set_md_var(tc, "descr", "Test error conditions in msync(2)"); 179 } 180 181 ATF_TC_BODY(msync_err, tc) 182 { 183 184 char *map = MAP_FAILED; 185 186 /* 187 * Test that invalid flags error out. 188 */ 189 #ifdef __FreeBSD__ 190 errno = 0; 191 ATF_REQUIRE_ERRNO(EINVAL, msync_sync("error", -1) != NULL); 192 errno = 0; 193 ATF_REQUIRE_ERRNO(EINVAL, msync_sync("error", INT_MAX) != NULL); 194 #else 195 ATF_REQUIRE(msync_sync("error", -1) != NULL); 196 ATF_REQUIRE(msync_sync("error", INT_MAX) != NULL); 197 #endif 198 199 errno = 0; 200 201 /* 202 * Map a page and then unmap to get an unmapped address. 203 */ 204 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 205 -1, 0); 206 ATF_REQUIRE(map != MAP_FAILED); 207 208 (void)munmap(map, page); 209 210 ATF_REQUIRE(msync(map, page, MS_SYNC) != 0); 211 #ifdef __FreeBSD__ 212 ATF_REQUIRE(errno == ENOMEM); 213 #else 214 ATF_REQUIRE(errno == EFAULT); 215 #endif 216 } 217 218 ATF_TC(msync_invalidate); 219 ATF_TC_HEAD(msync_invalidate, tc) 220 { 221 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_INVALIDATE"); 222 } 223 224 ATF_TC_BODY(msync_invalidate, tc) 225 { 226 const char *str; 227 228 str = msync_sync("garbage", MS_INVALIDATE); 229 230 if (str != NULL) 231 atf_tc_fail("%s", str); 232 } 233 234 ATF_TC(msync_sync); 235 ATF_TC_HEAD(msync_sync, tc) 236 { 237 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_SYNC"); 238 } 239 240 ATF_TC_BODY(msync_sync, tc) 241 { 242 const char *str; 243 244 str = msync_sync("garbage", MS_SYNC); 245 246 if (str != NULL) 247 atf_tc_fail("%s", str); 248 } 249 250 ATF_TP_ADD_TCS(tp) 251 { 252 253 page = sysconf(_SC_PAGESIZE); 254 255 ATF_REQUIRE(page >= 0); 256 ATF_REQUIRE(page > off); 257 258 ATF_TP_ADD_TC(tp, msync_async); 259 ATF_TP_ADD_TC(tp, msync_err); 260 ATF_TP_ADD_TC(tp, msync_invalidate); 261 ATF_TP_ADD_TC(tp, msync_sync); 262 263 return atf_no_error(); 264 } 265