xref: /openbsd/regress/sys/fileops/fileops.c (revision d89ec533)
1 /* $OpenBSD: fileops.c,v 1.2 2017/05/29 13:49:40 bluhm Exp $ */
2 /*
3  * Copyright (c) 2017 Stefan Fritsch <sf@sfritsch.de>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <assert.h>
18 #include <err.h>
19 #include <fcntl.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 
28 #define BUFSIZE (16 * 1024)
29 #define HOLESIZE (16 * BUFSIZE)
30 
31 static int	 debug = 0;
32 static int	 fd = -1;
33 static off_t	 curpos = 0;
34 static char	*fname;
35 static char	*gbuf;
36 static char	*mbuf;
37 
38 void
39 gen_data(void *buf, size_t size, uint32_t seed)
40 {
41 	assert(size % 4 == 0);
42 	if (debug)
43 		printf("%s: size %zd seed %#08x\n", __func__, size, seed);
44 	uint32_t *ibuf = buf;
45 	for (size_t i = 0; i < size / 4; i++)
46 		ibuf[i] = seed + i;
47 }
48 
49 void
50 check_data(const void *buf, size_t size, uint32_t seed)
51 {
52 	assert(size % 4 == 0);
53 	const uint32_t *ibuf = buf;
54 	for (size_t i = 0; i < size / 4; i++) {
55 		if (ibuf[i] != seed + i) {
56 			errx(3, "%s: pos %zd/%zd: expected %#08zx got %#08x",
57 			    __func__, 4 * i, size, seed + i, ibuf[i]);
58 		}
59 	}
60 }
61 
62 void
63 check_zero(const void *buf, size_t size)
64 {
65 	assert(size % 4 == 0);
66 	const uint32_t *ibuf = buf;
67 	for (size_t i = 0; i < size / 4; i++) {
68 		if (ibuf[i] != 0) {
69 			errx(3, "%s: pos %zd/%zd: expected 0 got %#08x",
70 			    __func__, 4 * i, size, ibuf[i]);
71 		}
72 	}
73 }
74 
75 void
76 check(const char *what, int64_t have, int64_t want)
77 {
78 	if (have != want) {
79 		if (have == -1)
80 			err(2, "%s returned %lld, expected %lld",
81 			    what, have, want);
82 		else
83 			errx(2, "%s returned %lld, expected %lld",
84 			    what, have, want);
85 	}
86 
87 	if (debug)
88 		printf("%s returned %lld\n", what, have);
89 }
90 
91 void
92 c_write(void *buf, size_t size)
93 {
94 	ssize_t ret = write(fd, buf, size);
95 	check("write", ret, size);
96 	curpos += ret;
97 }
98 
99 void
100 c_read(void *buf, size_t size)
101 {
102 	ssize_t ret = read(fd, buf, size);
103 	check("read", ret, size);
104 	curpos += ret;
105 }
106 
107 void
108 c_fsync(void)
109 {
110 	int ret = fsync(fd);
111 	check("fsync", ret, 0);
112 }
113 
114 void
115 c_lseek(off_t offset, int whence)
116 {
117 	off_t ret = lseek(fd, offset, whence);
118 	switch (whence) {
119 		case SEEK_SET:
120 			curpos = offset;
121 			break;
122 		case SEEK_CUR:
123 			curpos += offset;
124 			break;
125 		default:
126 			errx(1, "c_lseek not supported");
127 	}
128 	check("lseek", ret, curpos);
129 	if (debug)
130 		printf("curpos: %lld\n", (long long int)curpos);
131 }
132 
133 void
134 c_mmap(size_t size)
135 {
136 	mbuf = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, curpos);
137 	if (mbuf == MAP_FAILED)
138 		err(2, "mmap %zd pos %lld failed", size, (long long)curpos);
139 	curpos += size;
140 	if (debug)
141 		printf("mmap: %p\n", mbuf);
142 }
143 
144 void
145 c_munmap(size_t size)
146 {
147 	int ret = munmap(mbuf, size);
148 	if (ret != 0)
149 		err(2, "munmap");
150 }
151 
152 void
153 c_open(int flags)
154 {
155 	fd = open(fname, flags, S_IRUSR|S_IWUSR);
156 	if (fd == -1)
157 		err(1, "open");
158 }
159 
160 void
161 check_read(size_t size, int hole)
162 {
163 	size_t pos = 0;
164 	while (pos < size) {
165 		size_t to_read = size - pos;
166 		uint32_t seed = curpos;
167 		if (to_read > BUFSIZE)
168 			to_read = BUFSIZE;
169 		c_read(gbuf, to_read);
170 		if (hole)
171 			check_zero(gbuf, to_read);
172 		else
173 			check_data(gbuf, to_read, seed);
174 		pos += to_read;
175 	}
176 }
177 
178 /* XXX this assumes size is a multiple of the page size */
179 void
180 check_mmap(size_t size, int hole)
181 {
182 	size_t pos = 0;
183 	while (pos < size) {
184 		size_t to_read = size - pos;
185 		uint32_t seed = curpos;
186 		if (to_read > BUFSIZE)
187 			to_read = BUFSIZE;
188 		c_mmap(to_read);
189 		if (hole)
190 			check_zero(mbuf, to_read);
191 		else
192 			check_data(mbuf, to_read, seed);
193 		c_munmap(to_read);
194 		pos += to_read;
195 	}
196 }
197 
198 void
199 do_create(void)
200 {
201 	unlink(fname);
202 	c_open(O_EXCL|O_CREAT|O_RDWR);
203 
204 	gen_data(gbuf, BUFSIZE, curpos);
205 	c_write(gbuf, BUFSIZE);
206 
207 	c_lseek(HOLESIZE, SEEK_CUR);
208 
209 	gen_data(gbuf, BUFSIZE, curpos);
210 	c_write(gbuf, BUFSIZE);
211 	c_fsync();
212 }
213 
214 void
215 do_read(void)
216 {
217 	c_open(O_RDWR);
218 	check_read(BUFSIZE, 0);
219 	check_read(HOLESIZE, 1);
220 	check_read(BUFSIZE, 0);
221 }
222 
223 void
224 do_mmap(void)
225 {
226 	c_open(O_RDWR);
227 	check_mmap(BUFSIZE, 0);
228 	check_mmap(HOLESIZE, 1);
229 	check_mmap(BUFSIZE, 0);
230 }
231 
232 void
233 usage(void)
234 {
235 	errx(1, "usage: fileops (create|read|mmap) filename");
236 }
237 
238 int main(int argc, char **argv)
239 {
240 	if (argc != 3)
241 		usage();
242 
243 	fname = argv[2];
244 	gbuf = malloc(BUFSIZE);
245 	if (gbuf == NULL)
246 		err(1, "malloc");
247 
248 	if (strcmp(argv[1], "create") == 0) {
249 		do_create();
250 	} else if (strcmp(argv[1], "read") == 0) {
251 		do_read();
252 	} else if (strcmp(argv[1], "mmap") == 0) {
253 		do_mmap();
254 	} else {
255 		usage();
256 	}
257 
258 	printf("pass\n");
259 	return 0;
260 }
261