1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2012 Jilin Xpd <jilinxpd@gmail.com> 14 * Copyright 2018 Nexenta Systems, Inc. 15 */ 16 17 /* 18 * Test if file read/write is coherent with mmap, perform 2 tests: 19 * modify file through mmap, and check the result through file read. 20 * modify file through file write, and check the result through mmap. 21 */ 22 23 #include <sys/mman.h> 24 #include <sys/types.h> 25 #include <sys/stat.h> 26 #include <fcntl.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <errno.h> 32 33 void 34 usage(void) 35 { 36 fprintf(stderr, 37 "usage: rw_mmap -n <size>[b|k|m|g] -f <filename>\n"); 38 exit(1); 39 } 40 41 int 42 main(int argc, char **argv) 43 { 44 char *suffix; 45 char *filename = NULL; 46 char *file_addr; 47 char *p; 48 size_t filesize; 49 ssize_t blksize; 50 size_t cnt = 1; 51 size_t mul = 1; 52 int c, fid; 53 char *buf; 54 55 /* 56 * parse arguments 57 */ 58 while ((c = getopt(argc, argv, "n:f:")) != -1) { 59 switch (c) { 60 case 'n': 61 cnt = (size_t)strtoul(optarg, &suffix, 0); 62 if (cnt == 0) 63 goto bad_n_arg; 64 switch (*suffix) { 65 case '\0': 66 case 'b': 67 mul = 1; 68 break; 69 case 'k': 70 mul = 1024; 71 break; 72 case 'm': 73 mul = (1024 * 1024); 74 break; 75 case 'g': 76 mul = (1024 * 1024 * 1024); 77 break; 78 default: 79 bad_n_arg: 80 fprintf(stderr, "-n %s: invalid size\n", 81 optarg); 82 return (1); 83 } 84 cnt = cnt * mul; 85 break; 86 87 case 'f': /* target file */ 88 filename = optarg; 89 break; 90 91 case ':': /* missing optarg */ 92 fprintf(stderr, 93 "Option -%c requires an arg\n", optopt); 94 usage(); 95 break; 96 case '?': 97 fprintf(stderr, 98 "Unrecognized option: -%c\n", optopt); 99 usage(); 100 break; 101 } 102 } 103 104 /* open test file */ 105 fid = open(filename, O_RDWR | O_CREAT | O_TRUNC, 106 S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH); 107 if (fid == -1) { 108 fprintf(stderr, "open %s error=%d\n", filename, errno); 109 return (1); 110 } 111 112 /* extend file */ 113 filesize = cnt; 114 if (ftruncate(fid, filesize) == -1) { 115 fprintf(stderr, "ftrunc %s error=%d\n", filename, errno); 116 return (1); 117 } 118 119 /* map file */ 120 file_addr = mmap(NULL, filesize, 121 PROT_READ | PROT_WRITE, MAP_SHARED, fid, 0); 122 if (file_addr == MAP_FAILED) { 123 fprintf(stderr, "mmap %s error=%d\n", filename, errno); 124 return (1); 125 } 126 127 blksize = 4096; 128 buf = malloc(blksize); 129 if (buf == NULL) { 130 fprintf(stderr, "malloc failed\n"); 131 return (1); 132 } 133 134 /* verify fread and mmap see the same data */ 135 p = file_addr + 2013; /* not aligned to 4KB, on purpose */ 136 lseek(fid, 2013, SEEK_SET); 137 while (p < file_addr + filesize) { 138 blksize = read(fid, buf, blksize); 139 if (blksize < 0) { 140 perror(filename); 141 return (1); 142 } 143 if (blksize == 0) 144 break; 145 if (memcmp(buf, p, blksize) != 0) { 146 fprintf(stderr, "memcmp failed 1\n"); 147 return (1); 148 } 149 p += blksize; 150 } 151 152 /* modify file through mmap, verify fread can see the change */ 153 blksize = 4096; 154 p = file_addr + 2013; /* not aligned to 4KB */ 155 lseek(fid, 2013, SEEK_SET); 156 c = 'a'; 157 while (p < file_addr + filesize) { 158 if (p + blksize > file_addr + filesize) 159 blksize = file_addr + filesize - p; 160 memset(p, c++, blksize); 161 blksize = read(fid, buf, blksize); 162 if (blksize < 0) { 163 perror(filename); 164 return (1); 165 } 166 if (blksize == 0) 167 break; 168 if (memcmp(buf, p, blksize) != 0) { 169 fprintf(stderr, "memcmp failed 2\n"); 170 return (1); 171 } 172 p += blksize; 173 } 174 175 /* modify file through fwrite, verify mmap can see the change */ 176 blksize = 4096; 177 p = file_addr + 2013; /* not aligned to 4KB */ 178 lseek(fid, 2013, SEEK_SET); 179 c = 'Z'; 180 while (p < file_addr + filesize) { 181 if (p + blksize > file_addr + filesize) 182 blksize = file_addr + filesize - p; 183 memset(buf, c--, blksize); 184 blksize = write(fid, buf, blksize); 185 if (blksize < 0) { 186 perror(filename); 187 return (1); 188 } 189 if (blksize == 0) 190 break; 191 if (memcmp(buf, p, blksize) != 0) { 192 fprintf(stderr, "memcmp failed 3\n"); 193 return (1); 194 } 195 p += blksize; 196 } 197 198 /* sync pages to file */ 199 if (msync(file_addr, filesize, MS_SYNC) == -1) { 200 fprintf(stderr, "msync %s error=%d\n", filename, errno); 201 return (1); 202 } 203 204 /* unmap file */ 205 if (munmap(file_addr, filesize) == -1) { 206 fprintf(stderr, "munmap %s error=%d\n", filename, errno); 207 return (1); 208 } 209 210 /* close file */ 211 if (close(fid) == -1) { 212 fprintf(stderr, "close %s error=%d\n", filename, errno); 213 return (1); 214 } 215 216 return (0); 217 } 218