1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2018 Dell EMC Isilon
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29#include <sys/param.h>
30#include <sys/mman.h>
31#include <sys/stat.h>
32#include <sys/wait.h>
33
34#include <machine/atomic.h>
35
36#include <err.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <time.h>
43#include <unistd.h>
44
45#define PARALLEL 3
46#define SYNC 0
47
48static void cr1(void);
49static void cr2(void);
50static void cr3(void);
51static void rn1(void);
52static void rw1(void);
53static void rw2(void);
54static void (*functions[])(void) = {&cr1, &cr2, &cr3, &rn1, &rw1, &rw2};
55
56static volatile u_int *share;
57static int tests;
58
59static void
60cr1(void)
61{
62	int fd, i, j;
63	int loops = 9000;
64	char file[128];
65
66	setproctitle("%s sync", __func__);
67	atomic_add_int(&share[SYNC], 1);
68	while (share[SYNC] != (volatile u_int)tests * PARALLEL)
69		usleep(100);
70	setproctitle("%s", __func__);
71	for (j = 0; j < 10; j++) {
72		for (i = 0; i < loops; i++) {
73			snprintf(file, sizeof(file), "%s.%06d.%03d",
74			    __func__, getpid(), i);
75			if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
76			    DEFFILEMODE)) == -1)
77				err(1, "open(%s)", file);
78			close(fd);
79			if (i % 1000 == 0)
80				usleep(100);
81		}
82		for (i = 0; i < loops; i++) {
83			snprintf(file, sizeof(file), "%s.%06d.%03d",
84			    __func__, getpid(), i);
85			if (unlink(file) == -1)
86				err(1, "unlink(%s)", file);
87		}
88	}
89}
90
91static void
92cr2(void)
93{
94	int fd, i, j;
95	char file[1024];
96
97	setproctitle("%s sync", __func__);
98	atomic_add_int(&share[SYNC], 1);
99	while (share[SYNC] != (volatile u_int)tests * PARALLEL)
100		usleep(100);
101	setproctitle("%s", __func__);
102	for (j = 0; j < 3; j++) {
103		for (i = 0; i < 40000; i++) {
104			snprintf(file, sizeof(file), "%s.%06d.%03d",
105			    __func__, getpid(), i);
106			if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
107			    DEFFILEMODE)) == -1)
108				err(1, "open(%s)", file);
109			close(fd);
110			if (unlink(file) == -1)
111				err(1, "unlink(%s)", file);
112			if (i % 1000 == 0)
113				usleep(100);
114		}
115	}
116}
117
118static void
119cr3(void)
120{
121	int fd, i, j;
122	int loops = 10000;
123	char file[1024], path[1024];
124
125	setproctitle("%s sync", __func__);
126	atomic_add_int(&share[SYNC], 1);
127	while (share[SYNC] != (volatile u_int)tests * PARALLEL)
128		usleep(100);
129	setproctitle("%s", __func__);
130	getcwd(path, sizeof(path));
131	for (j = 0; j < 7; j++) {
132		for (i = 0; i < loops; i++) {
133			snprintf(file, sizeof(file), "%s/%s.%06d.%03d",
134			    path, __func__, getpid(), i);
135			if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
136			    DEFFILEMODE)) == -1)
137				err(1, "open(%s)", file);
138			close(fd);
139			if (i % 1000 == 0)
140				usleep(100);
141		}
142		for (i = 0; i < loops; i++) {
143			snprintf(file, sizeof(file), "%s/%s.%06d.%03d",
144			    path, __func__, getpid(), i);
145			if (unlink(file) == -1)
146				err(1, "unlink(%s)", file);
147		}
148	}
149}
150
151static void
152rn1(void)
153{
154	int fd, i, j;
155	int loops = 10000;
156	char file[128], new[128];
157
158	setproctitle("%s sync", __func__);
159	atomic_add_int(&share[SYNC], 1);
160	while (share[SYNC] != (volatile u_int)tests * PARALLEL)
161		usleep(100);
162	setproctitle("%s", __func__);
163
164	for (j = 0; j < 8; j++) {
165		for (i = 0; i < loops; i++) {
166			snprintf(file, sizeof(file), "%s.%06d.%03d",
167			    __func__, getpid(), i);
168			if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
169			    DEFFILEMODE)) == -1)
170				err(1, "open(%s)", file);
171			close(fd);
172			snprintf(new, sizeof(new), "%s.%06d.%03d.new",
173			    __func__, getpid(), i);
174			if (rename(file, new) == -1)
175				err(1, "rename(%s, %s)", file, new);
176			if (unlink(new) == -1)
177				err(1, "unlink(%s)", new);
178			if (i % 1000 == 0)
179				usleep(100);
180		}
181	}
182}
183
184static void
185rw1(void)
186{
187	int fd, i;
188	int loops = 10000;
189	char buf[512], file[128];
190
191	setproctitle("%s sync", __func__);
192	atomic_add_int(&share[SYNC], 1);
193	while (share[SYNC] != (volatile u_int)tests * PARALLEL)
194		usleep(100);
195
196	setproctitle("%s", __func__);
197        memset(buf, 0, sizeof(buf));
198        for (i = 0; i < loops; i++) {
199                snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
200                if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
201                    DEFFILEMODE)) == -1)
202                        err(1, "open(%s)", file);
203                if (write(fd, buf, sizeof(buf)) != sizeof(buf))
204                        err(1, "write(%s)", file);
205                close(fd);
206        }
207        for (i = 0; i < loops; i++) {
208                snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
209                if ((fd = open(file, O_RDONLY)) == -1)
210                        err(1, "open(%s)", file);
211                if (read(fd, buf, sizeof(buf)) != sizeof(buf))
212                        err(1, "write(%s)", file);
213                close(fd);
214                usleep(100);
215        }
216        for (i = 0; i < loops; i++) {
217                snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
218                if (unlink(file) == -1)
219                        err(1, "unlink(%s)", file);
220        }
221}
222
223static void
224rw2(void)
225{
226	int fd, i;
227	int loops = 8000;
228	int siz = 4096;
229	char *buf, file[128];
230
231	setproctitle("%s sync", __func__);
232	atomic_add_int(&share[SYNC], 1);
233	while (share[SYNC] != (volatile u_int)tests * PARALLEL)
234		usleep(100);
235
236	setproctitle("%s", __func__);
237	buf = calloc(1, siz);
238        for (i = 0; i < loops; i++) {
239                snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
240                if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC,
241                    DEFFILEMODE)) == -1)
242                        err(1, "open(%s)", file);
243                if (write(fd, buf, siz) != siz)
244                        err(1, "write(%s)", file);
245                close(fd);
246        }
247        for (i = 0; i < loops; i++) {
248                snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
249                if ((fd = open(file, O_RDONLY)) == -1)
250                        err(1, "open(%s)", file);
251                if (read(fd, buf, siz) != siz)
252                        err(1, "write(%s)", file);
253                close(fd);
254                usleep(100);
255        }
256        for (i = 0; i < loops; i++) {
257                snprintf(file, sizeof(file), "rw1.%06d.%03d", getpid(), i);
258                if (unlink(file) == -1)
259                        err(1, "unlink(%s)", file);
260        }
261}
262
263static void
264spawn(void f(), int idx)
265{
266	pid_t pids[PARALLEL];
267	int i, status;
268	char dir[128];
269
270	snprintf(dir, sizeof(dir), "f%d.%d.d",getpid(), idx);
271	rmdir(dir);
272	if (mkdir(dir, 0770) == -1)
273		err(1, "mkdir(%s)", dir);
274	if (chdir(dir) == -1)
275		err(1, "chdir(%s)", dir);
276	for (i = 0; i < PARALLEL; i++) {
277		if ((pids[i] = fork()) == 0) {
278			f();
279			_exit(0);
280		}
281		if (pids[i] == -1)
282			err(1, "fork(). %s:%d", __func__, __LINE__);
283	}
284	for (i = 0; i < PARALLEL; i++) {
285		if (waitpid(pids[i], &status, 0) != pids[i])
286			err(1, "waitpid(). %s:%d", __func__, __LINE__);
287	}
288	if (chdir("..") == -1)
289		err(1, "chdir(..)");
290	if (rmdir(dir) == -1)
291		err(1, "rmdir(%s)", dir);
292
293}
294
295void
296usage(void)
297{
298	fprintf(stderr, "Usage: %s [-t]\n", getprogname());
299	exit(1);
300}
301
302int
303main(int argc, char *argv[])
304{
305	pid_t *pids;
306	struct timeval t1, t2, diff;
307	size_t len;
308	time_t start __unused;
309	int ch, i, status, timing;
310
311	timing = 0;
312	while ((ch = getopt(argc, argv, "t")) != -1)
313		switch(ch) {
314		case 't':
315			timing = 1;
316			break;
317		default:
318			usage();
319		}
320	argc -= optind;
321	argv += optind;
322
323	setproctitle("%s", __func__);
324	tests = (int)(sizeof(functions) / sizeof(functions[0]));
325	pids = malloc(tests * sizeof(pid_t));
326	len = PAGE_SIZE;
327	if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE,
328	    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
329		err(1, "mmap");
330
331	gettimeofday(&t1, NULL);
332	for (i = 0; i < tests; i++) {
333		if ((pids[i] = fork()) == 0) {
334			start = time(NULL);
335			spawn(functions[i], i);
336#if defined(DEBUG)
337			fprintf(stderr, "%d: %ld elapsed\n", i ,
338			    (long)(time(NULL) - start));
339#endif
340			_exit(0);
341		}
342		if (pids[i] == -1)
343			err(1, "fork(). %s:%d", __func__, __LINE__);
344	}
345	for (i = 0; i < tests; i++) {
346		if (waitpid(pids[i], &status, 0) != pids[i])
347			err(1, "waitpid(%d). i=%d %s:%d", pids[i], i,
348					__func__, __LINE__);
349	}
350	gettimeofday(&t2, NULL);
351	timersub(&t2, &t1, &diff);
352	if (timing == 1)
353		printf("%jd.%06ld\n",(intmax_t)diff.tv_sec, diff.tv_usec);
354
355	return (0);
356}
357