xref: /freebsd-src/sys/contrib/openzfs/tests/zfs-tests/cmd/xattrtest.c (revision 271171e0d97b88ba2a7c3bf750c9672b484c1c13)
1716fd348SMartin Matuska /*
2716fd348SMartin Matuska  * CDDL HEADER START
3716fd348SMartin Matuska  *
4716fd348SMartin Matuska  * The contents of this file are subject to the terms of the
5716fd348SMartin Matuska  * Common Development and Distribution License (the "License").
6716fd348SMartin Matuska  * You may not use this file except in compliance with the License.
7716fd348SMartin Matuska  *
8716fd348SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10716fd348SMartin Matuska  * See the License for the specific language governing permissions
11716fd348SMartin Matuska  * and limitations under the License.
12716fd348SMartin Matuska  *
13716fd348SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14716fd348SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15716fd348SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16716fd348SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17716fd348SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18716fd348SMartin Matuska  *
19716fd348SMartin Matuska  * CDDL HEADER END
20716fd348SMartin Matuska  */
21716fd348SMartin Matuska 
22716fd348SMartin Matuska /*
23716fd348SMartin Matuska  * Copyright 2016 Lawrence Livermore National Security, LLC.
24716fd348SMartin Matuska  */
25716fd348SMartin Matuska 
26716fd348SMartin Matuska /*
27716fd348SMartin Matuska  * An extended attribute (xattr) correctness test.  This program creates
28716fd348SMartin Matuska  * N files and sets M attrs on them of size S.  Optionally is will verify
29716fd348SMartin Matuska  * a pattern stored in the xattr.
30716fd348SMartin Matuska  */
31716fd348SMartin Matuska #include <stdlib.h>
32716fd348SMartin Matuska #include <stddef.h>
33716fd348SMartin Matuska #include <stdio.h>
34716fd348SMartin Matuska #include <string.h>
35716fd348SMartin Matuska #include <errno.h>
36716fd348SMartin Matuska #include <getopt.h>
37716fd348SMartin Matuska #include <fcntl.h>
38716fd348SMartin Matuska #include <time.h>
39716fd348SMartin Matuska #include <unistd.h>
40716fd348SMartin Matuska #include <sys/xattr.h>
41716fd348SMartin Matuska #include <sys/types.h>
42716fd348SMartin Matuska #include <sys/wait.h>
43716fd348SMartin Matuska #include <sys/stat.h>
44716fd348SMartin Matuska #include <sys/time.h>
45716fd348SMartin Matuska #include <linux/limits.h>
46716fd348SMartin Matuska 
47716fd348SMartin Matuska #define	ERROR(fmt, ...)                                                 \
48716fd348SMartin Matuska 	fprintf(stderr, "xattrtest: %s:%d: %s: " fmt "\n",              \
49716fd348SMartin Matuska 		__FILE__, __LINE__,      				\
50716fd348SMartin Matuska 		__func__, ## __VA_ARGS__);
51716fd348SMartin Matuska 
52716fd348SMartin Matuska static const char shortopts[] = "hvycdn:f:x:s:p:t:e:rRko:";
53716fd348SMartin Matuska static const struct option longopts[] = {
54716fd348SMartin Matuska 	{ "help",		no_argument,		0,	'h' },
55716fd348SMartin Matuska 	{ "verbose",		no_argument,		0,	'v' },
56716fd348SMartin Matuska 	{ "verify",		no_argument,		0,	'y' },
57716fd348SMartin Matuska 	{ "nth",		required_argument,	0,	'n' },
58716fd348SMartin Matuska 	{ "files",		required_argument,	0,	'f' },
59716fd348SMartin Matuska 	{ "xattrs",		required_argument,	0,	'x' },
60716fd348SMartin Matuska 	{ "size",		required_argument,	0,	's' },
61716fd348SMartin Matuska 	{ "path",		required_argument,	0,	'p' },
62716fd348SMartin Matuska 	{ "synccaches", 	no_argument,		0,	'c' },
63716fd348SMartin Matuska 	{ "dropcaches",		no_argument,		0,	'd' },
64716fd348SMartin Matuska 	{ "script",		required_argument,	0,	't' },
65716fd348SMartin Matuska 	{ "seed",		required_argument,	0,	'e' },
66716fd348SMartin Matuska 	{ "random",		no_argument,		0,	'r' },
67716fd348SMartin Matuska 	{ "randomvalue",	no_argument,		0,	'R' },
68716fd348SMartin Matuska 	{ "keep",		no_argument,		0,	'k' },
69716fd348SMartin Matuska 	{ "only",		required_argument,	0,	'o' },
70716fd348SMartin Matuska 	{ 0,			0,			0,	0   }
71716fd348SMartin Matuska };
72716fd348SMartin Matuska 
73716fd348SMartin Matuska enum phases {
74716fd348SMartin Matuska 	PHASE_ALL = 0,
75716fd348SMartin Matuska 	PHASE_CREATE,
76716fd348SMartin Matuska 	PHASE_SETXATTR,
77716fd348SMartin Matuska 	PHASE_GETXATTR,
78716fd348SMartin Matuska 	PHASE_UNLINK,
79716fd348SMartin Matuska 	PHASE_INVAL
80716fd348SMartin Matuska };
81716fd348SMartin Matuska 
82716fd348SMartin Matuska static int verbose = 0;
83716fd348SMartin Matuska static int verify = 0;
84716fd348SMartin Matuska static int synccaches = 0;
85716fd348SMartin Matuska static int dropcaches = 0;
86716fd348SMartin Matuska static int nth = 0;
87716fd348SMartin Matuska static int files = 1000;
88716fd348SMartin Matuska static int xattrs = 1;
89716fd348SMartin Matuska static int size = 6;
90716fd348SMartin Matuska static int size_is_random = 0;
91716fd348SMartin Matuska static int value_is_random = 0;
92716fd348SMartin Matuska static int keep_files = 0;
93716fd348SMartin Matuska static int phase = PHASE_ALL;
94a0b956f5SMartin Matuska static const char *path = "/tmp/xattrtest";
95a0b956f5SMartin Matuska static const char *script = "/bin/true";
96716fd348SMartin Matuska static char xattrbytes[XATTR_SIZE_MAX];
97716fd348SMartin Matuska 
98716fd348SMartin Matuska static int
usage(char * argv0)99716fd348SMartin Matuska usage(char *argv0)
100716fd348SMartin Matuska {
101716fd348SMartin Matuska 	fprintf(stderr,
102716fd348SMartin Matuska 	    "usage: %s [-hvycdrRk] [-n <nth>] [-f <files>] [-x <xattrs>]\n"
103716fd348SMartin Matuska 	    "       [-s <bytes>] [-p <path>] [-t <script> ] [-o <phase>]\n",
104716fd348SMartin Matuska 	    argv0);
105716fd348SMartin Matuska 
106716fd348SMartin Matuska 	fprintf(stderr,
107716fd348SMartin Matuska 	    "  --help        -h           This help\n"
108716fd348SMartin Matuska 	    "  --verbose     -v           Increase verbosity\n"
109716fd348SMartin Matuska 	    "  --verify      -y           Verify xattr contents\n"
110716fd348SMartin Matuska 	    "  --nth         -n <nth>     Print every nth file\n"
111716fd348SMartin Matuska 	    "  --files       -f <files>   Set xattrs on N files\n"
112716fd348SMartin Matuska 	    "  --xattrs      -x <xattrs>  Set N xattrs on each file\n"
113716fd348SMartin Matuska 	    "  --size        -s <bytes>   Set N bytes per xattr\n"
114716fd348SMartin Matuska 	    "  --path        -p <path>    Path to files\n"
115716fd348SMartin Matuska 	    "  --synccaches  -c           Sync caches between phases\n"
116716fd348SMartin Matuska 	    "  --dropcaches  -d           Drop caches between phases\n"
117716fd348SMartin Matuska 	    "  --script      -t <script>  Exec script between phases\n"
118716fd348SMartin Matuska 	    "  --seed        -e <seed>    Random seed value\n"
119716fd348SMartin Matuska 	    "  --random      -r           Randomly sized xattrs [16-size]\n"
120716fd348SMartin Matuska 	    "  --randomvalue -R           Random xattr values\n"
121716fd348SMartin Matuska 	    "  --keep        -k           Don't unlink files\n"
122716fd348SMartin Matuska 	    "  --only        -o <num>     Only run phase N\n"
123716fd348SMartin Matuska 	    "                             0=all, 1=create, 2=setxattr,\n"
124716fd348SMartin Matuska 	    "                             3=getxattr, 4=unlink\n\n");
125716fd348SMartin Matuska 
126716fd348SMartin Matuska 	return (1);
127716fd348SMartin Matuska }
128716fd348SMartin Matuska 
129716fd348SMartin Matuska static int
parse_args(int argc,char ** argv)130716fd348SMartin Matuska parse_args(int argc, char **argv)
131716fd348SMartin Matuska {
132716fd348SMartin Matuska 	long seed = time(NULL);
133716fd348SMartin Matuska 	int c;
134716fd348SMartin Matuska 	int rc = 0;
135716fd348SMartin Matuska 
136716fd348SMartin Matuska 	while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
137716fd348SMartin Matuska 		switch (c) {
138716fd348SMartin Matuska 		case 'h':
139716fd348SMartin Matuska 			return (usage(argv[0]));
140716fd348SMartin Matuska 		case 'v':
141716fd348SMartin Matuska 			verbose++;
142716fd348SMartin Matuska 			break;
143716fd348SMartin Matuska 		case 'y':
144716fd348SMartin Matuska 			verify = 1;
145716fd348SMartin Matuska 			break;
146716fd348SMartin Matuska 		case 'n':
147716fd348SMartin Matuska 			nth = strtol(optarg, NULL, 0);
148716fd348SMartin Matuska 			break;
149716fd348SMartin Matuska 		case 'f':
150716fd348SMartin Matuska 			files = strtol(optarg, NULL, 0);
151716fd348SMartin Matuska 			break;
152716fd348SMartin Matuska 		case 'x':
153716fd348SMartin Matuska 			xattrs = strtol(optarg, NULL, 0);
154716fd348SMartin Matuska 			break;
155716fd348SMartin Matuska 		case 's':
156716fd348SMartin Matuska 			size = strtol(optarg, NULL, 0);
157716fd348SMartin Matuska 			if (size > XATTR_SIZE_MAX) {
158716fd348SMartin Matuska 				fprintf(stderr, "Error: the -s value may not "
159716fd348SMartin Matuska 				    "be greater than %d\n", XATTR_SIZE_MAX);
160716fd348SMartin Matuska 				rc = 1;
161716fd348SMartin Matuska 			}
162716fd348SMartin Matuska 			break;
163716fd348SMartin Matuska 		case 'p':
164a0b956f5SMartin Matuska 			path = optarg;
165716fd348SMartin Matuska 			break;
166716fd348SMartin Matuska 		case 'c':
167716fd348SMartin Matuska 			synccaches = 1;
168716fd348SMartin Matuska 			break;
169716fd348SMartin Matuska 		case 'd':
170716fd348SMartin Matuska 			dropcaches = 1;
171716fd348SMartin Matuska 			break;
172716fd348SMartin Matuska 		case 't':
173a0b956f5SMartin Matuska 			script = optarg;
174716fd348SMartin Matuska 			break;
175716fd348SMartin Matuska 		case 'e':
176716fd348SMartin Matuska 			seed = strtol(optarg, NULL, 0);
177716fd348SMartin Matuska 			break;
178716fd348SMartin Matuska 		case 'r':
179716fd348SMartin Matuska 			size_is_random = 1;
180716fd348SMartin Matuska 			break;
181716fd348SMartin Matuska 		case 'R':
182716fd348SMartin Matuska 			value_is_random = 1;
183716fd348SMartin Matuska 			break;
184716fd348SMartin Matuska 		case 'k':
185716fd348SMartin Matuska 			keep_files = 1;
186716fd348SMartin Matuska 			break;
187716fd348SMartin Matuska 		case 'o':
188716fd348SMartin Matuska 			phase = strtol(optarg, NULL, 0);
189716fd348SMartin Matuska 			if (phase <= PHASE_ALL || phase >= PHASE_INVAL) {
190716fd348SMartin Matuska 				fprintf(stderr, "Error: the -o value must be "
191716fd348SMartin Matuska 				    "greater than %d and less than %d\n",
192716fd348SMartin Matuska 				    PHASE_ALL, PHASE_INVAL);
193716fd348SMartin Matuska 				rc = 1;
194716fd348SMartin Matuska 			}
195716fd348SMartin Matuska 			break;
196716fd348SMartin Matuska 		default:
197716fd348SMartin Matuska 			rc = 1;
198716fd348SMartin Matuska 			break;
199716fd348SMartin Matuska 		}
200716fd348SMartin Matuska 	}
201716fd348SMartin Matuska 
202716fd348SMartin Matuska 	if (rc != 0)
203716fd348SMartin Matuska 		return (rc);
204716fd348SMartin Matuska 
205716fd348SMartin Matuska 	srandom(seed);
206716fd348SMartin Matuska 
207716fd348SMartin Matuska 	if (verbose) {
208716fd348SMartin Matuska 		fprintf(stdout, "verbose:          %d\n", verbose);
209716fd348SMartin Matuska 		fprintf(stdout, "verify:           %d\n", verify);
210716fd348SMartin Matuska 		fprintf(stdout, "nth:              %d\n", nth);
211716fd348SMartin Matuska 		fprintf(stdout, "files:            %d\n", files);
212716fd348SMartin Matuska 		fprintf(stdout, "xattrs:           %d\n", xattrs);
213716fd348SMartin Matuska 		fprintf(stdout, "size:             %d\n", size);
214716fd348SMartin Matuska 		fprintf(stdout, "path:             %s\n", path);
215716fd348SMartin Matuska 		fprintf(stdout, "synccaches:       %d\n", synccaches);
216716fd348SMartin Matuska 		fprintf(stdout, "dropcaches:       %d\n", dropcaches);
217716fd348SMartin Matuska 		fprintf(stdout, "script:           %s\n", script);
218716fd348SMartin Matuska 		fprintf(stdout, "seed:             %ld\n", seed);
219716fd348SMartin Matuska 		fprintf(stdout, "random size:      %d\n", size_is_random);
220716fd348SMartin Matuska 		fprintf(stdout, "random value:     %d\n", value_is_random);
221716fd348SMartin Matuska 		fprintf(stdout, "keep:             %d\n", keep_files);
222716fd348SMartin Matuska 		fprintf(stdout, "only:             %d\n", phase);
223716fd348SMartin Matuska 		fprintf(stdout, "%s", "\n");
224716fd348SMartin Matuska 	}
225716fd348SMartin Matuska 
226716fd348SMartin Matuska 	return (rc);
227716fd348SMartin Matuska }
228716fd348SMartin Matuska 
229716fd348SMartin Matuska static int
drop_caches(void)230716fd348SMartin Matuska drop_caches(void)
231716fd348SMartin Matuska {
232716fd348SMartin Matuska 	char file[] = "/proc/sys/vm/drop_caches";
233716fd348SMartin Matuska 	int fd, rc;
234716fd348SMartin Matuska 
235716fd348SMartin Matuska 	fd = open(file, O_WRONLY);
236716fd348SMartin Matuska 	if (fd == -1) {
237716fd348SMartin Matuska 		ERROR("Error %d: open(\"%s\", O_WRONLY)\n", errno, file);
238716fd348SMartin Matuska 		return (errno);
239716fd348SMartin Matuska 	}
240716fd348SMartin Matuska 
241716fd348SMartin Matuska 	rc = write(fd, "3", 1);
242716fd348SMartin Matuska 	if ((rc == -1) || (rc != 1)) {
243716fd348SMartin Matuska 		ERROR("Error %d: write(%d, \"3\", 1)\n", errno, fd);
244716fd348SMartin Matuska 		(void) close(fd);
245716fd348SMartin Matuska 		return (errno);
246716fd348SMartin Matuska 	}
247716fd348SMartin Matuska 
248716fd348SMartin Matuska 	rc = close(fd);
249716fd348SMartin Matuska 	if (rc == -1) {
250716fd348SMartin Matuska 		ERROR("Error %d: close(%d)\n", errno, fd);
251716fd348SMartin Matuska 		return (errno);
252716fd348SMartin Matuska 	}
253716fd348SMartin Matuska 
254716fd348SMartin Matuska 	return (0);
255716fd348SMartin Matuska }
256716fd348SMartin Matuska 
257716fd348SMartin Matuska static int
run_process(const char * path,char * argv[])258716fd348SMartin Matuska run_process(const char *path, char *argv[])
259716fd348SMartin Matuska {
260716fd348SMartin Matuska 	pid_t pid;
261716fd348SMartin Matuska 	int rc, devnull_fd;
262716fd348SMartin Matuska 
263716fd348SMartin Matuska 	pid = fork();
264716fd348SMartin Matuska 	if (pid == 0) {
265716fd348SMartin Matuska 		devnull_fd = open("/dev/null", O_WRONLY);
266716fd348SMartin Matuska 
267716fd348SMartin Matuska 		if (devnull_fd < 0)
268716fd348SMartin Matuska 			_exit(-1);
269716fd348SMartin Matuska 
270716fd348SMartin Matuska 		(void) dup2(devnull_fd, STDOUT_FILENO);
271716fd348SMartin Matuska 		(void) dup2(devnull_fd, STDERR_FILENO);
272716fd348SMartin Matuska 		close(devnull_fd);
273716fd348SMartin Matuska 
274716fd348SMartin Matuska 		(void) execvp(path, argv);
275716fd348SMartin Matuska 		_exit(-1);
276716fd348SMartin Matuska 	} else if (pid > 0) {
277716fd348SMartin Matuska 		int status;
278716fd348SMartin Matuska 
279716fd348SMartin Matuska 		while ((rc = waitpid(pid, &status, 0)) == -1 &&
280716fd348SMartin Matuska 		    errno == EINTR) { }
281716fd348SMartin Matuska 
282716fd348SMartin Matuska 		if (rc < 0 || !WIFEXITED(status))
283716fd348SMartin Matuska 			return (-1);
284716fd348SMartin Matuska 
285716fd348SMartin Matuska 		return (WEXITSTATUS(status));
286716fd348SMartin Matuska 	}
287716fd348SMartin Matuska 
288716fd348SMartin Matuska 	return (-1);
289716fd348SMartin Matuska }
290716fd348SMartin Matuska 
291716fd348SMartin Matuska static int
post_hook(const char * phase)292a0b956f5SMartin Matuska post_hook(const char *phase)
293716fd348SMartin Matuska {
294a0b956f5SMartin Matuska 	char *argv[3] = { (char *)script, (char *)phase, NULL };
295716fd348SMartin Matuska 	int rc;
296716fd348SMartin Matuska 
297716fd348SMartin Matuska 	if (synccaches)
298716fd348SMartin Matuska 		sync();
299716fd348SMartin Matuska 
300716fd348SMartin Matuska 	if (dropcaches) {
301716fd348SMartin Matuska 		rc = drop_caches();
302716fd348SMartin Matuska 		if (rc)
303716fd348SMartin Matuska 			return (rc);
304716fd348SMartin Matuska 	}
305716fd348SMartin Matuska 
306716fd348SMartin Matuska 	rc = run_process(script, argv);
307716fd348SMartin Matuska 	if (rc)
308716fd348SMartin Matuska 		return (rc);
309716fd348SMartin Matuska 
310716fd348SMartin Matuska 	return (0);
311716fd348SMartin Matuska }
312716fd348SMartin Matuska 
313716fd348SMartin Matuska #define	USEC_PER_SEC	1000000
314716fd348SMartin Matuska 
315716fd348SMartin Matuska static void
timeval_normalize(struct timeval * tv,time_t sec,suseconds_t usec)316716fd348SMartin Matuska timeval_normalize(struct timeval *tv, time_t sec, suseconds_t usec)
317716fd348SMartin Matuska {
318716fd348SMartin Matuska 	while (usec >= USEC_PER_SEC) {
319716fd348SMartin Matuska 		usec -= USEC_PER_SEC;
320716fd348SMartin Matuska 		sec++;
321716fd348SMartin Matuska 	}
322716fd348SMartin Matuska 
323716fd348SMartin Matuska 	while (usec < 0) {
324716fd348SMartin Matuska 		usec += USEC_PER_SEC;
325716fd348SMartin Matuska 		sec--;
326716fd348SMartin Matuska 	}
327716fd348SMartin Matuska 
328716fd348SMartin Matuska 	tv->tv_sec = sec;
329716fd348SMartin Matuska 	tv->tv_usec = usec;
330716fd348SMartin Matuska }
331716fd348SMartin Matuska 
332716fd348SMartin Matuska static void
timeval_sub(struct timeval * delta,struct timeval * tv1,struct timeval * tv2)333716fd348SMartin Matuska timeval_sub(struct timeval *delta, struct timeval *tv1, struct timeval *tv2)
334716fd348SMartin Matuska {
335716fd348SMartin Matuska 	timeval_normalize(delta,
336716fd348SMartin Matuska 	    tv1->tv_sec - tv2->tv_sec,
337716fd348SMartin Matuska 	    tv1->tv_usec - tv2->tv_usec);
338716fd348SMartin Matuska }
339716fd348SMartin Matuska 
340716fd348SMartin Matuska static double
timeval_sub_seconds(struct timeval * tv1,struct timeval * tv2)341716fd348SMartin Matuska timeval_sub_seconds(struct timeval *tv1, struct timeval *tv2)
342716fd348SMartin Matuska {
343716fd348SMartin Matuska 	struct timeval delta;
344716fd348SMartin Matuska 
345716fd348SMartin Matuska 	timeval_sub(&delta, tv1, tv2);
346716fd348SMartin Matuska 	return ((double)delta.tv_usec / USEC_PER_SEC + delta.tv_sec);
347716fd348SMartin Matuska }
348716fd348SMartin Matuska 
349716fd348SMartin Matuska static int
create_files(void)350716fd348SMartin Matuska create_files(void)
351716fd348SMartin Matuska {
352716fd348SMartin Matuska 	int i, rc;
353716fd348SMartin Matuska 	char *file = NULL;
354716fd348SMartin Matuska 	struct timeval start, stop;
355716fd348SMartin Matuska 	double seconds;
356716fd348SMartin Matuska 	size_t fsize;
357716fd348SMartin Matuska 
358716fd348SMartin Matuska 	fsize = PATH_MAX;
359716fd348SMartin Matuska 	file = malloc(fsize);
360716fd348SMartin Matuska 	if (file == NULL) {
361716fd348SMartin Matuska 		rc = ENOMEM;
362716fd348SMartin Matuska 		ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
363716fd348SMartin Matuska 		    PATH_MAX);
364716fd348SMartin Matuska 		goto out;
365716fd348SMartin Matuska 	}
366716fd348SMartin Matuska 
367716fd348SMartin Matuska 	(void) gettimeofday(&start, NULL);
368716fd348SMartin Matuska 
369716fd348SMartin Matuska 	for (i = 1; i <= files; i++) {
370716fd348SMartin Matuska 		if (snprintf(file, fsize, "%s/file-%d", path, i) >= fsize) {
371716fd348SMartin Matuska 			rc = EINVAL;
372716fd348SMartin Matuska 			ERROR("Error %d: path too long\n", rc);
373716fd348SMartin Matuska 			goto out;
374716fd348SMartin Matuska 		}
375716fd348SMartin Matuska 
376716fd348SMartin Matuska 		if (nth && ((i % nth) == 0))
377716fd348SMartin Matuska 			fprintf(stdout, "create: %s\n", file);
378716fd348SMartin Matuska 
379716fd348SMartin Matuska 		rc = unlink(file);
380716fd348SMartin Matuska 		if ((rc == -1) && (errno != ENOENT)) {
381716fd348SMartin Matuska 			ERROR("Error %d: unlink(%s)\n", errno, file);
382716fd348SMartin Matuska 			rc = errno;
383716fd348SMartin Matuska 			goto out;
384716fd348SMartin Matuska 		}
385716fd348SMartin Matuska 
386716fd348SMartin Matuska 		rc = open(file, O_CREAT, 0644);
387716fd348SMartin Matuska 		if (rc == -1) {
388716fd348SMartin Matuska 			ERROR("Error %d: open(%s, O_CREATE, 0644)\n",
389716fd348SMartin Matuska 			    errno, file);
390716fd348SMartin Matuska 			rc = errno;
391716fd348SMartin Matuska 			goto out;
392716fd348SMartin Matuska 		}
393716fd348SMartin Matuska 
394716fd348SMartin Matuska 		rc = close(rc);
395716fd348SMartin Matuska 		if (rc == -1) {
396716fd348SMartin Matuska 			ERROR("Error %d: close(%d)\n", errno, rc);
397716fd348SMartin Matuska 			rc = errno;
398716fd348SMartin Matuska 			goto out;
399716fd348SMartin Matuska 		}
400716fd348SMartin Matuska 	}
401716fd348SMartin Matuska 
402716fd348SMartin Matuska 	(void) gettimeofday(&stop, NULL);
403716fd348SMartin Matuska 	seconds = timeval_sub_seconds(&stop, &start);
404716fd348SMartin Matuska 	fprintf(stdout, "create:   %f seconds %f creates/second\n",
405716fd348SMartin Matuska 	    seconds, files / seconds);
406716fd348SMartin Matuska 
407716fd348SMartin Matuska 	rc = post_hook("post");
408716fd348SMartin Matuska out:
409716fd348SMartin Matuska 	if (file)
410716fd348SMartin Matuska 		free(file);
411716fd348SMartin Matuska 
412716fd348SMartin Matuska 	return (rc);
413716fd348SMartin Matuska }
414716fd348SMartin Matuska 
415716fd348SMartin Matuska static int
get_random_bytes(char * buf,size_t bytes)416716fd348SMartin Matuska get_random_bytes(char *buf, size_t bytes)
417716fd348SMartin Matuska {
418716fd348SMartin Matuska 	int rand;
419716fd348SMartin Matuska 	ssize_t bytes_read = 0;
420716fd348SMartin Matuska 
421716fd348SMartin Matuska 	rand = open("/dev/urandom", O_RDONLY);
422716fd348SMartin Matuska 
423716fd348SMartin Matuska 	if (rand < 0)
424716fd348SMartin Matuska 		return (rand);
425716fd348SMartin Matuska 
426716fd348SMartin Matuska 	while (bytes_read < bytes) {
427716fd348SMartin Matuska 		ssize_t rc = read(rand, buf + bytes_read, bytes - bytes_read);
428716fd348SMartin Matuska 		if (rc < 0)
429716fd348SMartin Matuska 			break;
430716fd348SMartin Matuska 		bytes_read += rc;
431716fd348SMartin Matuska 	}
432716fd348SMartin Matuska 
433716fd348SMartin Matuska 	(void) close(rand);
434716fd348SMartin Matuska 
435716fd348SMartin Matuska 	return (bytes_read);
436716fd348SMartin Matuska }
437716fd348SMartin Matuska 
438716fd348SMartin Matuska static int
setxattrs(void)439716fd348SMartin Matuska setxattrs(void)
440716fd348SMartin Matuska {
441716fd348SMartin Matuska 	int i, j, rnd_size = size, shift, rc = 0;
442716fd348SMartin Matuska 	char name[XATTR_NAME_MAX];
443716fd348SMartin Matuska 	char *value = NULL;
444716fd348SMartin Matuska 	char *file = NULL;
445716fd348SMartin Matuska 	struct timeval start, stop;
446716fd348SMartin Matuska 	double seconds;
447716fd348SMartin Matuska 	size_t fsize;
448716fd348SMartin Matuska 
449716fd348SMartin Matuska 	value = malloc(XATTR_SIZE_MAX);
450716fd348SMartin Matuska 	if (value == NULL) {
451716fd348SMartin Matuska 		rc = ENOMEM;
452716fd348SMartin Matuska 		ERROR("Error %d: malloc(%d) bytes for xattr value\n", rc,
453716fd348SMartin Matuska 		    XATTR_SIZE_MAX);
454716fd348SMartin Matuska 		goto out;
455716fd348SMartin Matuska 	}
456716fd348SMartin Matuska 
457716fd348SMartin Matuska 	fsize = PATH_MAX;
458716fd348SMartin Matuska 	file = malloc(fsize);
459716fd348SMartin Matuska 	if (file == NULL) {
460716fd348SMartin Matuska 		rc = ENOMEM;
461716fd348SMartin Matuska 		ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
462716fd348SMartin Matuska 		    PATH_MAX);
463716fd348SMartin Matuska 		goto out;
464716fd348SMartin Matuska 	}
465716fd348SMartin Matuska 
466716fd348SMartin Matuska 	(void) gettimeofday(&start, NULL);
467716fd348SMartin Matuska 
468716fd348SMartin Matuska 	for (i = 1; i <= files; i++) {
469716fd348SMartin Matuska 		if (snprintf(file, fsize, "%s/file-%d", path, i) >= fsize) {
470716fd348SMartin Matuska 			rc = EINVAL;
471716fd348SMartin Matuska 			ERROR("Error %d: path too long\n", rc);
472716fd348SMartin Matuska 			goto out;
473716fd348SMartin Matuska 		}
474716fd348SMartin Matuska 
475716fd348SMartin Matuska 		if (nth && ((i % nth) == 0))
476716fd348SMartin Matuska 			fprintf(stdout, "setxattr: %s\n", file);
477716fd348SMartin Matuska 
478716fd348SMartin Matuska 		for (j = 1; j <= xattrs; j++) {
479716fd348SMartin Matuska 			if (size_is_random)
480716fd348SMartin Matuska 				rnd_size = (random() % (size - 16)) + 16;
481716fd348SMartin Matuska 
482716fd348SMartin Matuska 			(void) sprintf(name, "user.%d", j);
483716fd348SMartin Matuska 			shift = sprintf(value, "size=%d ", rnd_size);
484716fd348SMartin Matuska 			memcpy(value + shift, xattrbytes,
485716fd348SMartin Matuska 			    sizeof (xattrbytes) - shift);
486716fd348SMartin Matuska 
487716fd348SMartin Matuska 			rc = lsetxattr(file, name, value, rnd_size, 0);
488716fd348SMartin Matuska 			if (rc == -1) {
489716fd348SMartin Matuska 				ERROR("Error %d: lsetxattr(%s, %s, ..., %d)\n",
490716fd348SMartin Matuska 				    errno, file, name, rnd_size);
491716fd348SMartin Matuska 				goto out;
492716fd348SMartin Matuska 			}
493716fd348SMartin Matuska 		}
494716fd348SMartin Matuska 	}
495716fd348SMartin Matuska 
496716fd348SMartin Matuska 	(void) gettimeofday(&stop, NULL);
497716fd348SMartin Matuska 	seconds = timeval_sub_seconds(&stop, &start);
498716fd348SMartin Matuska 	fprintf(stdout, "setxattr: %f seconds %f setxattrs/second\n",
499716fd348SMartin Matuska 	    seconds, (files * xattrs) / seconds);
500716fd348SMartin Matuska 
501716fd348SMartin Matuska 	rc = post_hook("post");
502716fd348SMartin Matuska out:
503716fd348SMartin Matuska 	if (file)
504716fd348SMartin Matuska 		free(file);
505716fd348SMartin Matuska 
506716fd348SMartin Matuska 	if (value)
507716fd348SMartin Matuska 		free(value);
508716fd348SMartin Matuska 
509716fd348SMartin Matuska 	return (rc);
510716fd348SMartin Matuska }
511716fd348SMartin Matuska 
512716fd348SMartin Matuska static int
getxattrs(void)513716fd348SMartin Matuska getxattrs(void)
514716fd348SMartin Matuska {
515716fd348SMartin Matuska 	int i, j, rnd_size, shift, rc = 0;
516716fd348SMartin Matuska 	char name[XATTR_NAME_MAX];
517716fd348SMartin Matuska 	char *verify_value = NULL;
518a0b956f5SMartin Matuska 	const char *verify_string;
519716fd348SMartin Matuska 	char *value = NULL;
520a0b956f5SMartin Matuska 	const char *value_string;
521716fd348SMartin Matuska 	char *file = NULL;
522716fd348SMartin Matuska 	struct timeval start, stop;
523716fd348SMartin Matuska 	double seconds;
524716fd348SMartin Matuska 	size_t fsize;
525716fd348SMartin Matuska 
526716fd348SMartin Matuska 	verify_value = malloc(XATTR_SIZE_MAX);
527716fd348SMartin Matuska 	if (verify_value == NULL) {
528716fd348SMartin Matuska 		rc = ENOMEM;
529716fd348SMartin Matuska 		ERROR("Error %d: malloc(%d) bytes for xattr verify\n", rc,
530716fd348SMartin Matuska 		    XATTR_SIZE_MAX);
531716fd348SMartin Matuska 		goto out;
532716fd348SMartin Matuska 	}
533716fd348SMartin Matuska 
534716fd348SMartin Matuska 	value = malloc(XATTR_SIZE_MAX);
535716fd348SMartin Matuska 	if (value == NULL) {
536716fd348SMartin Matuska 		rc = ENOMEM;
537716fd348SMartin Matuska 		ERROR("Error %d: malloc(%d) bytes for xattr value\n", rc,
538716fd348SMartin Matuska 		    XATTR_SIZE_MAX);
539716fd348SMartin Matuska 		goto out;
540716fd348SMartin Matuska 	}
541716fd348SMartin Matuska 
542716fd348SMartin Matuska 	verify_string = value_is_random ? "<random>" : verify_value;
543716fd348SMartin Matuska 	value_string = value_is_random ? "<random>" : value;
544716fd348SMartin Matuska 
545716fd348SMartin Matuska 	fsize = PATH_MAX;
546716fd348SMartin Matuska 	file = malloc(fsize);
547716fd348SMartin Matuska 
548716fd348SMartin Matuska 	if (file == NULL) {
549716fd348SMartin Matuska 		rc = ENOMEM;
550716fd348SMartin Matuska 		ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
551716fd348SMartin Matuska 		    PATH_MAX);
552716fd348SMartin Matuska 		goto out;
553716fd348SMartin Matuska 	}
554716fd348SMartin Matuska 
555716fd348SMartin Matuska 	(void) gettimeofday(&start, NULL);
556716fd348SMartin Matuska 
557716fd348SMartin Matuska 	for (i = 1; i <= files; i++) {
558716fd348SMartin Matuska 		if (snprintf(file, fsize, "%s/file-%d", path, i) >= fsize) {
559716fd348SMartin Matuska 			rc = EINVAL;
560716fd348SMartin Matuska 			ERROR("Error %d: path too long\n", rc);
561716fd348SMartin Matuska 			goto out;
562716fd348SMartin Matuska 		}
563716fd348SMartin Matuska 
564716fd348SMartin Matuska 		if (nth && ((i % nth) == 0))
565716fd348SMartin Matuska 			fprintf(stdout, "getxattr: %s\n", file);
566716fd348SMartin Matuska 
567716fd348SMartin Matuska 		for (j = 1; j <= xattrs; j++) {
568716fd348SMartin Matuska 			(void) sprintf(name, "user.%d", j);
569716fd348SMartin Matuska 
570716fd348SMartin Matuska 			rc = lgetxattr(file, name, value, XATTR_SIZE_MAX);
571716fd348SMartin Matuska 			if (rc == -1) {
572716fd348SMartin Matuska 				ERROR("Error %d: lgetxattr(%s, %s, ..., %d)\n",
573716fd348SMartin Matuska 				    errno, file, name, XATTR_SIZE_MAX);
574716fd348SMartin Matuska 				goto out;
575716fd348SMartin Matuska 			}
576716fd348SMartin Matuska 
577716fd348SMartin Matuska 			if (!verify)
578716fd348SMartin Matuska 				continue;
579716fd348SMartin Matuska 
580716fd348SMartin Matuska 			sscanf(value, "size=%d [a-z]", &rnd_size);
581716fd348SMartin Matuska 			shift = sprintf(verify_value, "size=%d ",
582716fd348SMartin Matuska 			    rnd_size);
583716fd348SMartin Matuska 			memcpy(verify_value + shift, xattrbytes,
584716fd348SMartin Matuska 			    sizeof (xattrbytes) - shift);
585716fd348SMartin Matuska 
586716fd348SMartin Matuska 			if (rnd_size != rc ||
587716fd348SMartin Matuska 			    memcmp(verify_value, value, rnd_size)) {
588716fd348SMartin Matuska 				ERROR("Error %d: verify failed\n "
589716fd348SMartin Matuska 				    "verify: %s\n value:  %s\n", EINVAL,
590716fd348SMartin Matuska 				    verify_string, value_string);
591716fd348SMartin Matuska 				rc = 1;
592716fd348SMartin Matuska 				goto out;
593716fd348SMartin Matuska 			}
594716fd348SMartin Matuska 		}
595716fd348SMartin Matuska 	}
596716fd348SMartin Matuska 
597716fd348SMartin Matuska 	(void) gettimeofday(&stop, NULL);
598716fd348SMartin Matuska 	seconds = timeval_sub_seconds(&stop, &start);
599716fd348SMartin Matuska 	fprintf(stdout, "getxattr: %f seconds %f getxattrs/second\n",
600716fd348SMartin Matuska 	    seconds, (files * xattrs) / seconds);
601716fd348SMartin Matuska 
602716fd348SMartin Matuska 	rc = post_hook("post");
603716fd348SMartin Matuska out:
604716fd348SMartin Matuska 	if (file)
605716fd348SMartin Matuska 		free(file);
606716fd348SMartin Matuska 
607716fd348SMartin Matuska 	if (value)
608716fd348SMartin Matuska 		free(value);
609716fd348SMartin Matuska 
610716fd348SMartin Matuska 	if (verify_value)
611716fd348SMartin Matuska 		free(verify_value);
612716fd348SMartin Matuska 
613716fd348SMartin Matuska 	return (rc);
614716fd348SMartin Matuska }
615716fd348SMartin Matuska 
616716fd348SMartin Matuska static int
unlink_files(void)617716fd348SMartin Matuska unlink_files(void)
618716fd348SMartin Matuska {
619716fd348SMartin Matuska 	int i, rc;
620716fd348SMartin Matuska 	char *file = NULL;
621716fd348SMartin Matuska 	struct timeval start, stop;
622716fd348SMartin Matuska 	double seconds;
623716fd348SMartin Matuska 	size_t fsize;
624716fd348SMartin Matuska 
625716fd348SMartin Matuska 	fsize = PATH_MAX;
626716fd348SMartin Matuska 	file = malloc(fsize);
627716fd348SMartin Matuska 	if (file == NULL) {
628716fd348SMartin Matuska 		rc = ENOMEM;
629716fd348SMartin Matuska 		ERROR("Error %d: malloc(%d) bytes for file name\n",
630716fd348SMartin Matuska 		    rc, PATH_MAX);
631716fd348SMartin Matuska 		goto out;
632716fd348SMartin Matuska 	}
633716fd348SMartin Matuska 
634716fd348SMartin Matuska 	(void) gettimeofday(&start, NULL);
635716fd348SMartin Matuska 
636716fd348SMartin Matuska 	for (i = 1; i <= files; i++) {
637716fd348SMartin Matuska 		if (snprintf(file, fsize, "%s/file-%d", path, i) >= fsize) {
638716fd348SMartin Matuska 			rc = EINVAL;
639716fd348SMartin Matuska 			ERROR("Error %d: path too long\n", rc);
640716fd348SMartin Matuska 			goto out;
641716fd348SMartin Matuska 		}
642716fd348SMartin Matuska 
643716fd348SMartin Matuska 		if (nth && ((i % nth) == 0))
644716fd348SMartin Matuska 			fprintf(stdout, "unlink: %s\n", file);
645716fd348SMartin Matuska 
646716fd348SMartin Matuska 		rc = unlink(file);
647716fd348SMartin Matuska 		if ((rc == -1) && (errno != ENOENT)) {
648716fd348SMartin Matuska 			ERROR("Error %d: unlink(%s)\n", errno, file);
649716fd348SMartin Matuska 			free(file);
650716fd348SMartin Matuska 			return (errno);
651716fd348SMartin Matuska 		}
652716fd348SMartin Matuska 	}
653716fd348SMartin Matuska 
654716fd348SMartin Matuska 	(void) gettimeofday(&stop, NULL);
655716fd348SMartin Matuska 	seconds = timeval_sub_seconds(&stop, &start);
656716fd348SMartin Matuska 	fprintf(stdout, "unlink:   %f seconds %f unlinks/second\n",
657716fd348SMartin Matuska 	    seconds, files / seconds);
658716fd348SMartin Matuska 
659716fd348SMartin Matuska 	rc = post_hook("post");
660716fd348SMartin Matuska out:
661716fd348SMartin Matuska 	if (file)
662716fd348SMartin Matuska 		free(file);
663716fd348SMartin Matuska 
664716fd348SMartin Matuska 	return (rc);
665716fd348SMartin Matuska }
666716fd348SMartin Matuska 
667716fd348SMartin Matuska int
main(int argc,char ** argv)668716fd348SMartin Matuska main(int argc, char **argv)
669716fd348SMartin Matuska {
670716fd348SMartin Matuska 	int rc;
671716fd348SMartin Matuska 
672716fd348SMartin Matuska 	rc = parse_args(argc, argv);
673716fd348SMartin Matuska 	if (rc)
674716fd348SMartin Matuska 		return (rc);
675716fd348SMartin Matuska 
676716fd348SMartin Matuska 	if (value_is_random) {
677716fd348SMartin Matuska 		size_t rndsz = sizeof (xattrbytes);
678716fd348SMartin Matuska 
679716fd348SMartin Matuska 		rc = get_random_bytes(xattrbytes, rndsz);
680716fd348SMartin Matuska 		if (rc < rndsz) {
681716fd348SMartin Matuska 			ERROR("Error %d: get_random_bytes() wanted %zd "
682716fd348SMartin Matuska 			    "got %d\n", errno, rndsz, rc);
683716fd348SMartin Matuska 			return (rc);
684716fd348SMartin Matuska 		}
685716fd348SMartin Matuska 	} else {
686716fd348SMartin Matuska 		memset(xattrbytes, 'x', sizeof (xattrbytes));
687716fd348SMartin Matuska 	}
688716fd348SMartin Matuska 
689716fd348SMartin Matuska 	if (phase == PHASE_ALL || phase == PHASE_CREATE) {
690716fd348SMartin Matuska 		rc = create_files();
691716fd348SMartin Matuska 		if (rc)
692716fd348SMartin Matuska 			return (rc);
693716fd348SMartin Matuska 	}
694716fd348SMartin Matuska 
695716fd348SMartin Matuska 	if (phase == PHASE_ALL || phase == PHASE_SETXATTR) {
696716fd348SMartin Matuska 		rc = setxattrs();
697716fd348SMartin Matuska 		if (rc)
698716fd348SMartin Matuska 			return (rc);
699716fd348SMartin Matuska 	}
700716fd348SMartin Matuska 
701716fd348SMartin Matuska 	if (phase == PHASE_ALL || phase == PHASE_GETXATTR) {
702716fd348SMartin Matuska 		rc = getxattrs();
703716fd348SMartin Matuska 		if (rc)
704716fd348SMartin Matuska 			return (rc);
705716fd348SMartin Matuska 	}
706716fd348SMartin Matuska 
707716fd348SMartin Matuska 	if (!keep_files && (phase == PHASE_ALL || phase == PHASE_UNLINK)) {
708716fd348SMartin Matuska 		rc = unlink_files();
709716fd348SMartin Matuska 		if (rc)
710716fd348SMartin Matuska 			return (rc);
711716fd348SMartin Matuska 	}
712716fd348SMartin Matuska 
713716fd348SMartin Matuska 	return (0);
714716fd348SMartin Matuska }
715