xref: /dragonfly/test/stress/fsstress/fsstress.c (revision e1acdbad)
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32 /*
33  * $DragonFly: src/test/stress/fsstress/fsstress.c,v 1.1 2004/05/07 17:51:02 dillon Exp $
34  */
35 
36 #include "global.h"
37 
38 #define XFS_ERRTAG_MAX		17
39 
40 typedef enum {
41 #ifndef NO_XFS
42 	OP_ALLOCSP,
43 	OP_ATTR_REMOVE,
44 	OP_ATTR_SET,
45 	OP_BULKSTAT,
46 	OP_BULKSTAT1,
47 #endif
48 	OP_CHOWN,
49 	OP_CREAT,
50 	OP_DREAD,
51 	OP_DWRITE,
52 	OP_FDATASYNC,
53 #ifndef NO_XFS
54 	OP_FREESP,
55 #endif
56 	OP_FSYNC,
57 	OP_GETDENTS,
58 	OP_LINK,
59 	OP_MKDIR,
60 	OP_MKNOD,
61 	OP_READ,
62 	OP_READLINK,
63 	OP_RENAME,
64 #ifndef NO_XFS
65 	OP_RESVSP,
66 #endif
67 	OP_RMDIR,
68 	OP_STAT,
69 	OP_SYMLINK,
70 	OP_SYNC,
71 	OP_TRUNCATE,
72 	OP_UNLINK,
73 #ifndef NO_XFS
74 	OP_UNRESVSP,
75 #endif
76 	OP_WRITE,
77 	OP_LAST
78 } opty_t;
79 
80 typedef void (*opfnc_t)(int, long);
81 
82 typedef struct opdesc {
83 	opty_t	op;
84 	char	*name;
85 	opfnc_t	func;
86 	int	freq;
87 	int	iswrite;
88 	int	isxfs;
89 } opdesc_t;
90 
91 typedef struct fent {
92 	int	id;
93 	int	parent;
94 } fent_t;
95 
96 typedef struct flist {
97 	int	nfiles;
98 	int	nslots;
99 	int	tag;
100 	fent_t	*fents;
101 } flist_t;
102 
103 typedef struct pathname {
104 	int	len;
105 	char	*path;
106 } pathname_t;
107 
108 #define	FT_DIR	0
109 #define	FT_DIRm	(1 << FT_DIR)
110 #define	FT_REG	1
111 #define	FT_REGm	(1 << FT_REG)
112 #define	FT_SYM	2
113 #define	FT_SYMm	(1 << FT_SYM)
114 #define	FT_DEV	3
115 #define	FT_DEVm	(1 << FT_DEV)
116 #define	FT_RTF	4
117 #define	FT_RTFm	(1 << FT_RTF)
118 #define	FT_nft	5
119 #define	FT_ANYm	((1 << FT_nft) - 1)
120 #define	FT_REGFILE	(FT_REGm | FT_RTFm)
121 #define	FT_NOTDIR	(FT_ANYm & ~FT_DIRm)
122 
123 #define	FLIST_SLOT_INCR	16
124 #define	NDCACHE	64
125 
126 #define	MAXFSIZE	((1ULL << 63) - 1ULL)
127 #define	MAXFSIZE32	((1ULL << 40) - 1ULL)
128 
129 void	allocsp_f(int, long);
130 void	attr_remove_f(int, long);
131 void	attr_set_f(int, long);
132 void	bulkstat_f(int, long);
133 void	bulkstat1_f(int, long);
134 void	chown_f(int, long);
135 void	creat_f(int, long);
136 void	dread_f(int, long);
137 void	dwrite_f(int, long);
138 void	fdatasync_f(int, long);
139 void	freesp_f(int, long);
140 void	fsync_f(int, long);
141 void	getdents_f(int, long);
142 void	link_f(int, long);
143 void	mkdir_f(int, long);
144 void	mknod_f(int, long);
145 void	read_f(int, long);
146 void	readlink_f(int, long);
147 void	rename_f(int, long);
148 void	resvsp_f(int, long);
149 void	rmdir_f(int, long);
150 void	stat_f(int, long);
151 void	symlink_f(int, long);
152 void	sync_f(int, long);
153 void	truncate_f(int, long);
154 void	unlink_f(int, long);
155 void	unresvsp_f(int, long);
156 void	write_f(int, long);
157 
158 opdesc_t	ops[] = {
159 #ifndef NO_XFS
160 	{ OP_ALLOCSP, "allocsp", allocsp_f, 1, 1, 1 },
161 	{ OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1, 1 },
162 	{ OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1, 1 },
163 	{ OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0, 1 },
164 	{ OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0, 1 },
165 #endif
166 	{ OP_CHOWN, "chown", chown_f, 3, 1 },
167 	{ OP_CREAT, "creat", creat_f, 4, 1 },
168 	{ OP_DREAD, "dread", dread_f, 4, 0 },
169 	{ OP_DWRITE, "dwrite", dwrite_f, 4, 1 },
170 	{ OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 },
171 #ifndef NO_XFS
172 	{ OP_FREESP, "freesp", freesp_f, 1, 1, 1 },
173 #endif
174 	{ OP_FSYNC, "fsync", fsync_f, 1, 1 },
175 	{ OP_GETDENTS, "getdents", getdents_f, 1, 0 },
176 	{ OP_LINK, "link", link_f, 1, 1 },
177 	{ OP_MKDIR, "mkdir", mkdir_f, 2, 1 },
178 	{ OP_MKNOD, "mknod", mknod_f, 2, 1 },
179 	{ OP_READ, "read", read_f, 1, 0 },
180 	{ OP_READLINK, "readlink", readlink_f, 1, 0 },
181 	{ OP_RENAME, "rename", rename_f, 2, 1 },
182 #ifndef NO_XFS
183 	{ OP_RESVSP, "resvsp", resvsp_f, 1, 1, 1 },
184 #endif
185 	{ OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
186 	{ OP_STAT, "stat", stat_f, 1, 0 },
187 	{ OP_SYMLINK, "symlink", symlink_f, 2, 1 },
188 	{ OP_SYNC, "sync", sync_f, 1, 0 },
189 	{ OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
190 	{ OP_UNLINK, "unlink", unlink_f, 1, 1 },
191 #ifndef NO_XFS
192 	{ OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1, 1 },
193 #endif
194 	{ OP_WRITE, "write", write_f, 4, 1 },
195 }, *ops_end;
196 
197 flist_t	flist[FT_nft] = {
198 	{ 0, 0, 'd', NULL },
199 	{ 0, 0, 'f', NULL },
200 	{ 0, 0, 'l', NULL },
201 	{ 0, 0, 'c', NULL },
202 	{ 0, 0, 'r', NULL },
203 };
204 
205 int		dcache[NDCACHE];
206 int		errrange;
207 int		errtag;
208 opty_t		*freq_table;
209 int		freq_table_size;
210 #ifndef NO_XFS
211 xfs_fsop_geom_t	geom;
212 #endif
213 char		*homedir;
214 int		*ilist;
215 int		ilistlen;
216 off64_t		maxfsize;
217 char		*myprog;
218 int		namerand;
219 int		nameseq;
220 int		nops;
221 int		nproc = 1;
222 int		operations = 1;
223 int		procid;
224 int		rtpct;
225 unsigned long	seed = 0;
226 ino_t		top_ino;
227 int		verbose = 0;
228 #ifndef NO_XFS
229 int no_xfs = 0;
230 #else
231 int no_xfs = 1;
232 #endif
233 
234 void	add_to_flist(int, int, int);
235 void	append_pathname(pathname_t *, char *);
236 #ifndef NO_XFS
237 int	attr_list_path(pathname_t *, char *, const int, int,
238 		       attrlist_cursor_t *);
239 int	attr_remove_path(pathname_t *, const char *, int);
240 int	attr_set_path(pathname_t *, const char *, const char *, const int, int);
241 #endif
242 void	check_cwd(void);
243 int	creat_path(pathname_t *, mode_t);
244 void	dcache_enter(int, int);
245 void	dcache_init(void);
246 fent_t	*dcache_lookup(int);
247 void	dcache_purge(int);
248 void	del_from_flist(int, int);
249 int	dirid_to_name(char *, int);
250 void	doproc(void);
251 void	fent_to_name(pathname_t *, flist_t *, fent_t *);
252 void	fix_parent(int, int);
253 void	free_pathname(pathname_t *);
254 int	generate_fname(fent_t *, int, pathname_t *, int *, int *);
255 int	get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
256 void	init_pathname(pathname_t *);
257 int	lchown_path(pathname_t *, uid_t, gid_t);
258 int	link_path(pathname_t *, pathname_t *);
259 int	lstat64_path(pathname_t *, struct stat64 *);
260 void	make_freq_table(void);
261 int	mkdir_path(pathname_t *, mode_t);
262 int	mknod_path(pathname_t *, mode_t, dev_t);
263 void	namerandpad(int, char *, int);
264 int	open_path(pathname_t *, int);
265 DIR	*opendir_path(pathname_t *);
266 void	process_freq(char *);
267 int	readlink_path(pathname_t *, char *, size_t);
268 int	rename_path(pathname_t *, pathname_t *);
269 int	rmdir_path(pathname_t *);
270 void	separate_pathname(pathname_t *, char *, pathname_t *);
271 void	show_ops(int, char *);
272 int	stat64_path(pathname_t *, struct stat64 *);
273 int	symlink_path(const char *, pathname_t *);
274 int	truncate64_path(pathname_t *, off64_t);
275 int	unlink_path(pathname_t *);
276 void	usage(void);
277 void	write_freq(void);
278 void	zero_freq(void);
279 
280 int main(int argc, char **argv)
281 {
282 	char		buf[10];
283 	int		c;
284 	char		*dirname = NULL;
285 	int		fd;
286 	int		i;
287 #ifndef NO_XFS
288 	int		j;
289 	ptrdiff_t	srval;
290 #endif
291 	char		*p;
292 	int		stat;
293 	struct timeval	t;
294         int             nousage=0;
295 #ifndef NO_XFS
296 	xfs_error_injection_t	err_inj;
297 #endif
298 
299 	errrange = errtag = 0;
300 	umask(0);
301 	nops = sizeof(ops) / sizeof(ops[0]);
302 	ops_end = &ops[nops];
303 	myprog = argv[0];
304 	while ((c = getopt(argc, argv, "d:e:f:i:n:p:rs:vwzHSX")) != -1) {
305 		switch (c) {
306 		case 'd':
307 			dirname = optarg;
308 			break;
309 		case 'e':
310 			sscanf(optarg, "%d", &errtag);
311 			if (errtag < 0) {
312 				errtag = -errtag;
313 				errrange = 1;
314 			} else if (errtag == 0)
315 				errtag = -1;
316 			if (errtag >= XFS_ERRTAG_MAX) {
317 				fprintf(stderr,
318 					"error tag %d too large (max %d)\n",
319 					errtag, XFS_ERRTAG_MAX - 1);
320 				exit(1);
321 			}
322 			break;
323 		case 'f':
324 			process_freq(optarg);
325 			break;
326 		case 'i':
327 			ilist = realloc(ilist, ++ilistlen * sizeof(*ilist));
328 			ilist[ilistlen - 1] = strtol(optarg, &p, 16);
329 			break;
330 		case 'n':
331 			operations = atoi(optarg);
332 			break;
333 		case 'p':
334 			nproc = atoi(optarg);
335 			break;
336 		case 'r':
337 			namerand = 1;
338 			break;
339 		case 's':
340 			seed = strtoul(optarg, NULL, 0);
341 			break;
342 		case 'v':
343 			verbose = 1;
344 			break;
345 		case 'w':
346 			write_freq();
347 			break;
348 		case 'z':
349 			zero_freq();
350 			break;
351 		case 'S':
352 			show_ops(0, NULL);
353 			printf("\n");
354                         nousage=1;
355 			break;
356 		case '?':
357 			fprintf(stderr, "%s - invalid parameters\n",
358 				myprog);
359 			/* fall through */
360 		case 'H':
361 			usage();
362 			exit(1);
363 		case 'X':
364 			no_xfs = 1;
365 			break;
366 		}
367 	}
368 
369 	if (no_xfs && errtag) {
370 		fprintf(stderr, "error injection only works on XFS\n");
371 		exit(1);
372 	}
373 
374 	if (no_xfs) {
375 		int i;
376 		for (i = 0; ops+i < ops_end; ++i) {
377 			if (ops[i].isxfs)
378 				ops[i].freq = 0;
379 		}
380 	}
381 
382         if (!dirname) {
383             /* no directory specified */
384             if (!nousage) usage();
385             exit(1);
386         }
387 
388 	(void)mkdir(dirname, 0777);
389 	if (chdir(dirname) < 0) {
390 		perror(dirname);
391 		exit(1);
392 	}
393 	sprintf(buf, "fss%x", getpid());
394 	fd = creat(buf, 0666);
395 	if (lseek64(fd, (off64_t)(MAXFSIZE32 + 1ULL), SEEK_SET) < 0)
396 		maxfsize = (off64_t)MAXFSIZE32;
397 	else
398 		maxfsize = (off64_t)MAXFSIZE;
399 	make_freq_table();
400 	dcache_init();
401 	setlinebuf(stdout);
402 	if (!seed) {
403 		gettimeofday(&t, (void *)NULL);
404 		seed = (int)t.tv_sec ^ (int)t.tv_usec;
405 		printf("seed = %ld\n", seed);
406 	}
407 #ifndef NO_XFS
408 	if (!no_xfs) {
409 	i = ioctl(fd, XFS_IOC_FSGEOMETRY, &geom);
410 	if (i >= 0 && geom.rtblocks)
411 		rtpct = MIN(MAX(geom.rtblocks * 100 /
412 				(geom.rtblocks + geom.datablocks), 1), 99);
413 	else
414 		rtpct = 0;
415 	}
416 	if (errtag != 0) {
417 		if (errrange == 0) {
418 			if (errtag <= 0) {
419 				srandom(seed);
420 				j = random() % 100;
421 
422 				for (i = 0; i < j; i++)
423 					(void) random();
424 
425 				errtag = (random() % (XFS_ERRTAG_MAX-1)) + 1;
426 			}
427 		} else {
428 			srandom(seed);
429 			j = random() % 100;
430 
431 			for (i = 0; i < j; i++)
432 				(void) random();
433 
434 			errtag += (random() % (XFS_ERRTAG_MAX - errtag));
435 		}
436 		printf("Injecting failure on tag #%d\n", errtag);
437 		err_inj.errtag = errtag;
438 		err_inj.fd = fd;
439 		srval = ioctl(fd, XFS_IOC_ERROR_INJECTION, &err_inj);
440 		if (srval < -1) {
441 			perror("fsstress - XFS_SYSSGI error injection call");
442 			close(fd);
443 			unlink(buf);
444 			exit(1);
445 		}
446 	} else
447 #endif
448 		close(fd);
449 	unlink(buf);
450 	if (nproc == 1) {
451 		procid = 0;
452 		doproc();
453 	} else {
454 		for (i = 0; i < nproc; i++) {
455 			if (fork() == 0) {
456 				procid = i;
457 				doproc();
458 				return 0;
459 			}
460 		}
461 		while (wait(&stat) > 0)
462 			continue;
463 	}
464 #ifndef NO_XFS
465 	if (errtag != 0) {
466 		err_inj.errtag = 0;
467 		err_inj.fd = fd;
468 		if((srval = ioctl(fd, XFS_IOC_ERROR_CLEARALL, &err_inj)) != 0) {
469 			fprintf(stderr, "Bad ej clear on %d (%d).\n", fd, errno);
470 			perror("fsstress - XFS_SYSSGI clear error injection call");
471 			close(fd);
472 			exit(1);
473 		}
474 		close(fd);
475 	}
476 #endif
477 
478 	return 0;
479 }
480 
481 void
482 add_to_flist(int ft, int id, int parent)
483 {
484 	fent_t	*fep;
485 	flist_t	*ftp;
486 
487 	ftp = &flist[ft];
488 	if (ftp->nfiles == ftp->nslots) {
489 		ftp->nslots += FLIST_SLOT_INCR;
490 		ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t));
491 	}
492 	fep = &ftp->fents[ftp->nfiles++];
493 	fep->id = id;
494 	fep->parent = parent;
495 }
496 
497 void
498 append_pathname(pathname_t *name, char *str)
499 {
500 	int	len;
501 
502 	len = strlen(str);
503 #ifdef DEBUG
504 	if (len && *str == '/' && name->len == 0) {
505 		fprintf(stderr, "fsstress: append_pathname failure\n");
506 		chdir(homedir);
507 		abort();
508 		/* NOTREACHED */
509 	}
510 #endif
511 	name->path = realloc(name->path, name->len + 1 + len);
512 	strcpy(&name->path[name->len], str);
513 	name->len += len;
514 }
515 
516 #ifndef NO_XFS
517 int
518 attr_list_path(pathname_t *name, char *buffer, const int buffersize, int flags,
519 	       attrlist_cursor_t *cursor)
520 {
521 	char		buf[MAXNAMELEN];
522 	pathname_t	newname;
523 	int		rval;
524 
525 	rval = attr_list(name->path, buffer, buffersize, flags, cursor);
526 	if (rval >= 0 || errno != ENAMETOOLONG)
527 		return rval;
528 	separate_pathname(name, buf, &newname);
529 	if (chdir(buf) == 0) {
530 		rval = attr_list_path(&newname, buffer, buffersize, flags,
531 			cursor);
532 		chdir("..");
533 	}
534 	free_pathname(&newname);
535 	return rval;
536 }
537 
538 int
539 attr_remove_path(pathname_t *name, const char *attrname, int flags)
540 {
541 	char		buf[MAXNAMELEN];
542 	pathname_t	newname;
543 	int		rval;
544 
545 	rval = attr_remove(name->path, attrname, flags);
546 	if (rval >= 0 || errno != ENAMETOOLONG)
547 		return rval;
548 	separate_pathname(name, buf, &newname);
549 	if (chdir(buf) == 0) {
550 		rval = attr_remove_path(&newname, attrname, flags);
551 		chdir("..");
552 	}
553 	free_pathname(&newname);
554 	return rval;
555 }
556 
557 int
558 attr_set_path(pathname_t *name, const char *attrname, const char *attrvalue,
559 	      const int valuelength, int flags)
560 {
561 	char		buf[MAXNAMELEN];
562 	pathname_t	newname;
563 	int		rval;
564 
565 	rval = attr_set(name->path, attrname, attrvalue, valuelength, flags);
566 	if (rval >= 0 || errno != ENAMETOOLONG)
567 		return rval;
568 	separate_pathname(name, buf, &newname);
569 	if (chdir(buf) == 0) {
570 		rval = attr_set_path(&newname, attrname, attrvalue, valuelength,
571 			flags);
572 		chdir("..");
573 	}
574 	free_pathname(&newname);
575 	return rval;
576 }
577 #endif
578 
579 void
580 check_cwd(void)
581 {
582 #ifdef DEBUG
583 	struct stat64	statbuf;
584 
585 	if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino)
586 		return;
587 	chdir(homedir);
588 	fprintf(stderr, "fsstress: check_cwd failure\n");
589 	abort();
590 	/* NOTREACHED */
591 #endif
592 }
593 
594 int
595 creat_path(pathname_t *name, mode_t mode)
596 {
597 	char		buf[MAXNAMELEN];
598 	pathname_t	newname;
599 	int		rval;
600 
601 	rval = creat(name->path, mode);
602 	if (rval >= 0 || errno != ENAMETOOLONG)
603 		return rval;
604 	separate_pathname(name, buf, &newname);
605 	if (chdir(buf) == 0) {
606 		rval = creat_path(&newname, mode);
607 		chdir("..");
608 	}
609 	free_pathname(&newname);
610 	return rval;
611 }
612 
613 void
614 dcache_enter(int dirid, int slot)
615 {
616 	dcache[dirid % NDCACHE] = slot;
617 }
618 
619 void
620 dcache_init(void)
621 {
622 	int	i;
623 
624 	for (i = 0; i < NDCACHE; i++)
625 		dcache[i] = -1;
626 }
627 
628 fent_t *
629 dcache_lookup(int dirid)
630 {
631 	fent_t	*fep;
632 	int	i;
633 
634 	i = dcache[dirid % NDCACHE];
635 	if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
636 		return fep;
637 	return NULL;
638 }
639 
640 void
641 dcache_purge(int dirid)
642 {
643 	int	*dcp;
644 
645 	dcp = &dcache[dirid % NDCACHE];
646 	if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
647 		*dcp = -1;
648 }
649 
650 void
651 del_from_flist(int ft, int slot)
652 {
653 	flist_t	*ftp;
654 
655 	ftp = &flist[ft];
656 	if (ft == FT_DIR)
657 		dcache_purge(ftp->fents[slot].id);
658 	if (slot != ftp->nfiles - 1) {
659 		if (ft == FT_DIR)
660 			dcache_purge(ftp->fents[ftp->nfiles - 1].id);
661 		ftp->fents[slot] = ftp->fents[--ftp->nfiles];
662 	} else
663 		ftp->nfiles--;
664 }
665 
666 fent_t *
667 dirid_to_fent(int dirid)
668 {
669 	fent_t	*efep;
670 	fent_t	*fep;
671 	flist_t	*flp;
672 
673 	if ((fep = dcache_lookup(dirid)))
674 		return fep;
675 	flp = &flist[FT_DIR];
676 	for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
677 		if (fep->id == dirid) {
678 			dcache_enter(dirid, fep - flp->fents);
679 			return fep;
680 		}
681 	}
682 	return NULL;
683 }
684 
685 void
686 doproc(void)
687 {
688 	struct stat64	statbuf;
689 	char		buf[10];
690 	int		opno;
691 	int		rval;
692 	opdesc_t	*p;
693 
694 	sprintf(buf, "p%x", procid);
695 	(void)mkdir(buf, 0777);
696 	if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) {
697 		perror(buf);
698 		_exit(1);
699 	}
700 	top_ino = statbuf.st_ino;
701 	homedir = getcwd(NULL, -1);
702 	seed += procid;
703 	srandom(seed);
704 	if (namerand)
705 		namerand = random();
706 	for (opno = 0; opno < operations; opno++) {
707 		p = &ops[freq_table[random() % freq_table_size]];
708 		if ((unsigned long)p->func < 4096) abort();
709 
710 
711 		p->func(opno, random());
712 		/*
713 		 * test for forced shutdown by stat'ing the test
714 		 * directory.  If this stat returns EIO, assume
715 		 * the forced shutdown happened.
716 		 */
717 		if (errtag != 0 && opno % 100 == 0)  {
718 			rval = stat64(".", &statbuf);
719 			if (rval == EIO)  {
720 				fprintf(stderr, "Detected EIO\n");
721 				return;
722 			}
723 		}
724 	}
725 }
726 
727 void
728 fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
729 {
730 	char	buf[MAXNAMELEN];
731 	int	i;
732 	fent_t	*pfep;
733 
734 	if (fep == NULL)
735 		return;
736 	if (fep->parent != -1) {
737 		pfep = dirid_to_fent(fep->parent);
738 		fent_to_name(name, &flist[FT_DIR], pfep);
739 		append_pathname(name, "/");
740 	}
741 	i = sprintf(buf, "%c%x", flp->tag, fep->id);
742 	namerandpad(fep->id, buf, i);
743 	append_pathname(name, buf);
744 }
745 
746 void
747 fix_parent(int oldid, int newid)
748 {
749 	fent_t	*fep;
750 	flist_t	*flp;
751 	int	i;
752 	int	j;
753 
754 	for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
755 		for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
756 			if (fep->parent == oldid)
757 				fep->parent = newid;
758 		}
759 	}
760 }
761 
762 void
763 free_pathname(pathname_t *name)
764 {
765 	if (name->path) {
766 		free(name->path);
767 		name->path = NULL;
768 		name->len = 0;
769 	}
770 }
771 
772 int
773 generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
774 {
775 	char	buf[MAXNAMELEN];
776 	flist_t	*flp;
777 	int	id;
778 	int	j;
779 	int	len;
780 
781 	flp = &flist[ft];
782 	len = sprintf(buf, "%c%x", flp->tag, id = nameseq++);
783 	namerandpad(id, buf, len);
784 	if (fep) {
785 		fent_to_name(name, &flist[FT_DIR], fep);
786 		append_pathname(name, "/");
787 	}
788 	append_pathname(name, buf);
789 	*idp = id;
790 	*v = verbose;
791 	for (j = 0; !*v && j < ilistlen; j++) {
792 		if (ilist[j] == id) {
793 			*v = 1;
794 			break;
795 		}
796 	}
797 	return 1;
798 }
799 
800 int
801 get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
802 	  int *v)
803 {
804 	int	c;
805 	fent_t	*fep;
806 	flist_t	*flp;
807 	int	i;
808 	int	j;
809 	int	x;
810 
811 	for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) {
812 		if (which & (1 << i))
813 			c += flp->nfiles;
814 	}
815 	if (c == 0) {
816 		if (flpp)
817 			*flpp = NULL;
818 		if (fepp)
819 			*fepp = NULL;
820 		*v = verbose;
821 		return 0;
822 	}
823 	x = (int)(r % c);
824 	for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) {
825 		if (which & (1 << i)) {
826 			if (x < c + flp->nfiles) {
827 				fep = &flp->fents[x - c];
828 				if (name)
829 					fent_to_name(name, flp, fep);
830 				if (flpp)
831 					*flpp = flp;
832 				if (fepp)
833 					*fepp = fep;
834 				*v = verbose;
835 				for (j = 0; !*v && j < ilistlen; j++) {
836 					if (ilist[j] == fep->id) {
837 						*v = 1;
838 						break;
839 					}
840 				}
841 				return 1;
842 			}
843 			c += flp->nfiles;
844 		}
845 	}
846 #ifdef DEBUG
847 	fprintf(stderr, "fsstress: get_fname failure\n");
848 	abort();
849 #endif
850         return -1;
851 	/* NOTREACHED */
852 }
853 
854 void
855 init_pathname(pathname_t *name)
856 {
857 	name->len = 0;
858 	name->path = NULL;
859 }
860 
861 int
862 lchown_path(pathname_t *name, uid_t owner, gid_t group)
863 {
864 	char		buf[MAXNAMELEN];
865 	pathname_t	newname;
866 	int		rval;
867 
868 	rval = lchown(name->path, owner, group);
869 	if (rval >= 0 || errno != ENAMETOOLONG)
870 		return rval;
871 	separate_pathname(name, buf, &newname);
872 	if (chdir(buf) == 0) {
873 		rval = lchown_path(&newname, owner, group);
874 		chdir("..");
875 	}
876 	free_pathname(&newname);
877 	return rval;
878 }
879 
880 int
881 link_path(pathname_t *name1, pathname_t *name2)
882 {
883 	char		buf1[MAXNAMELEN];
884 	char		buf2[MAXNAMELEN];
885 	int		down1;
886 	pathname_t	newname1;
887 	pathname_t	newname2;
888 	int		rval;
889 
890 	rval = link(name1->path, name2->path);
891 	if (rval >= 0 || errno != ENAMETOOLONG)
892 		return rval;
893 	separate_pathname(name1, buf1, &newname1);
894 	separate_pathname(name2, buf2, &newname2);
895 	if (strcmp(buf1, buf2) == 0) {
896 		if (chdir(buf1) == 0) {
897 			rval = link_path(&newname1, &newname2);
898 			chdir("..");
899 		}
900 	} else {
901 		if (strcmp(buf1, "..") == 0)
902 			down1 = 0;
903 		else if (strcmp(buf2, "..") == 0)
904 			down1 = 1;
905 		else if (strlen(buf1) == 0)
906 			down1 = 0;
907 		else if (strlen(buf2) == 0)
908 			down1 = 1;
909 		else
910 			down1 = MAX(newname1.len, 3 + name2->len) <=
911 				MAX(3 + name1->len, newname2.len);
912 		if (down1) {
913 			free_pathname(&newname2);
914 			append_pathname(&newname2, "../");
915 			append_pathname(&newname2, name2->path);
916 			if (chdir(buf1) == 0) {
917 				rval = link_path(&newname1, &newname2);
918 				chdir("..");
919 			}
920 		} else {
921 			free_pathname(&newname1);
922 			append_pathname(&newname1, "../");
923 			append_pathname(&newname1, name1->path);
924 			if (chdir(buf2) == 0) {
925 				rval = link_path(&newname1, &newname2);
926 				chdir("..");
927 			}
928 		}
929 	}
930 	free_pathname(&newname1);
931 	free_pathname(&newname2);
932 	return rval;
933 }
934 
935 int
936 lstat64_path(pathname_t *name, struct stat64 *sbuf)
937 {
938 	char		buf[MAXNAMELEN];
939 	pathname_t	newname;
940 	int		rval;
941 
942 	rval = lstat64(name->path, sbuf);
943 	if (rval >= 0 || errno != ENAMETOOLONG)
944 		return rval;
945 	separate_pathname(name, buf, &newname);
946 	if (chdir(buf) == 0) {
947 		rval = lstat64_path(&newname, sbuf);
948 		chdir("..");
949 	}
950 	free_pathname(&newname);
951 	return rval;
952 }
953 
954 void
955 make_freq_table(void)
956 {
957 	int		f;
958 	int		i;
959 	opdesc_t	*p;
960 
961 	for (p = ops, f = 0; p < ops_end; p++)
962 		f += p->freq;
963 	freq_table = malloc(f * sizeof(*freq_table));
964 	freq_table_size = f;
965 	for (p = ops, i = 0; p < ops_end; p++) {
966 		for (f = 0; f < p->freq; f++, i++)
967 			freq_table[i] = p->op;
968 	}
969 }
970 
971 int
972 mkdir_path(pathname_t *name, mode_t mode)
973 {
974 	char		buf[MAXNAMELEN];
975 	pathname_t	newname;
976 	int		rval;
977 
978 	rval = mkdir(name->path, mode);
979 	if (rval >= 0 || errno != ENAMETOOLONG)
980 		return rval;
981 	separate_pathname(name, buf, &newname);
982 	if (chdir(buf) == 0) {
983 		rval = mkdir_path(&newname, mode);
984 		chdir("..");
985 	}
986 	free_pathname(&newname);
987 	return rval;
988 }
989 
990 int
991 mknod_path(pathname_t *name, mode_t mode, dev_t dev)
992 {
993 	char		buf[MAXNAMELEN];
994 	pathname_t	newname;
995 	int		rval;
996 
997 	rval = mknod(name->path, mode, dev);
998 	if (rval >= 0 || errno != ENAMETOOLONG)
999 		return rval;
1000 	separate_pathname(name, buf, &newname);
1001 	if (chdir(buf) == 0) {
1002 		rval = mknod_path(&newname, mode, dev);
1003 		chdir("..");
1004 	}
1005 	free_pathname(&newname);
1006 	return rval;
1007 }
1008 
1009 void
1010 namerandpad(int id, char *buf, int i)
1011 {
1012 	int		bucket;
1013 	static int	buckets[] =
1014 				{ 2, 4, 8, 16, 32, 64, 128, MAXNAMELEN - 1 };
1015 	int		padlen;
1016 	int		padmod;
1017 
1018 	if (namerand == 0)
1019 		return;
1020 	bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0]));
1021 	padmod = buckets[bucket] + 1 - i;
1022 	if (padmod <= 0)
1023 		return;
1024 	padlen = (id ^ namerand) % padmod;
1025 	if (padlen) {
1026 		memset(&buf[i], 'X', padlen);
1027 		buf[i + padlen] = '\0';
1028 	}
1029 }
1030 
1031 int
1032 open_path(pathname_t *name, int oflag)
1033 {
1034 	char		buf[MAXNAMELEN];
1035 	pathname_t	newname;
1036 	int		rval;
1037 
1038 	rval = open(name->path, oflag);
1039 	if (rval >= 0 || errno != ENAMETOOLONG)
1040 		return rval;
1041 	separate_pathname(name, buf, &newname);
1042 	if (chdir(buf) == 0) {
1043 		rval = open_path(&newname, oflag);
1044 		chdir("..");
1045 	}
1046 	free_pathname(&newname);
1047 	return rval;
1048 }
1049 
1050 DIR *
1051 opendir_path(pathname_t *name)
1052 {
1053 	char		buf[MAXNAMELEN];
1054 	pathname_t	newname;
1055 	DIR		*rval;
1056 
1057 	rval = opendir(name->path);
1058 	if (rval || errno != ENAMETOOLONG)
1059 		return rval;
1060 	separate_pathname(name, buf, &newname);
1061 	if (chdir(buf) == 0) {
1062 		rval = opendir_path(&newname);
1063 		chdir("..");
1064 	}
1065 	free_pathname(&newname);
1066 	return rval;
1067 }
1068 
1069 void
1070 process_freq(char *arg)
1071 {
1072 	opdesc_t	*p;
1073 	char		*s;
1074 
1075 	s = strchr(arg, '=');
1076 	if (s == NULL) {
1077 		fprintf(stderr, "bad argument '%s'\n", arg);
1078 		exit(1);
1079 	}
1080 	*s++ = '\0';
1081 	for (p = ops; p < ops_end; p++) {
1082 		if (strcmp(arg, p->name) == 0) {
1083 			p->freq = atoi(s);
1084 			return;
1085 		}
1086 	}
1087 	fprintf(stderr, "can't find op type %s for -f\n", arg);
1088 	exit(1);
1089 }
1090 
1091 int
1092 readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz)
1093 {
1094 	char		buf[MAXNAMELEN];
1095 	pathname_t	newname;
1096 	int		rval;
1097 
1098 	rval = readlink(name->path, lbuf, lbufsiz);
1099 	if (rval >= 0 || errno != ENAMETOOLONG)
1100 		return rval;
1101 	separate_pathname(name, buf, &newname);
1102 	if (chdir(buf) == 0) {
1103 		rval = readlink_path(&newname, lbuf, lbufsiz);
1104 		chdir("..");
1105 	}
1106 	free_pathname(&newname);
1107 	return rval;
1108 }
1109 
1110 int
1111 rename_path(pathname_t *name1, pathname_t *name2)
1112 {
1113 	char		buf1[MAXNAMELEN];
1114 	char		buf2[MAXNAMELEN];
1115 	int		down1;
1116 	pathname_t	newname1;
1117 	pathname_t	newname2;
1118 	int		rval;
1119 
1120 	rval = rename(name1->path, name2->path);
1121 	if (rval >= 0 || errno != ENAMETOOLONG)
1122 		return rval;
1123 	separate_pathname(name1, buf1, &newname1);
1124 	separate_pathname(name2, buf2, &newname2);
1125 	if (strcmp(buf1, buf2) == 0) {
1126 		if (chdir(buf1) == 0) {
1127 			rval = rename_path(&newname1, &newname2);
1128 			chdir("..");
1129 		}
1130 	} else {
1131 		if (strcmp(buf1, "..") == 0)
1132 			down1 = 0;
1133 		else if (strcmp(buf2, "..") == 0)
1134 			down1 = 1;
1135 		else if (strlen(buf1) == 0)
1136 			down1 = 0;
1137 		else if (strlen(buf2) == 0)
1138 			down1 = 1;
1139 		else
1140 			down1 = MAX(newname1.len, 3 + name2->len) <=
1141 				MAX(3 + name1->len, newname2.len);
1142 		if (down1) {
1143 			free_pathname(&newname2);
1144 			append_pathname(&newname2, "../");
1145 			append_pathname(&newname2, name2->path);
1146 			if (chdir(buf1) == 0) {
1147 				rval = rename_path(&newname1, &newname2);
1148 				chdir("..");
1149 			}
1150 		} else {
1151 			free_pathname(&newname1);
1152 			append_pathname(&newname1, "../");
1153 			append_pathname(&newname1, name1->path);
1154 			if (chdir(buf2) == 0) {
1155 				rval = rename_path(&newname1, &newname2);
1156 				chdir("..");
1157 			}
1158 		}
1159 	}
1160 	free_pathname(&newname1);
1161 	free_pathname(&newname2);
1162 	return rval;
1163 }
1164 
1165 int
1166 rmdir_path(pathname_t *name)
1167 {
1168 	char		buf[MAXNAMELEN];
1169 	pathname_t	newname;
1170 	int		rval;
1171 
1172 	rval = rmdir(name->path);
1173 	if (rval >= 0 || errno != ENAMETOOLONG)
1174 		return rval;
1175 	separate_pathname(name, buf, &newname);
1176 	if (chdir(buf) == 0) {
1177 		rval = rmdir_path(&newname);
1178 		chdir("..");
1179 	}
1180 	free_pathname(&newname);
1181 	return rval;
1182 }
1183 
1184 void
1185 separate_pathname(pathname_t *name, char *buf, pathname_t *newname)
1186 {
1187 	char	*slash;
1188 
1189 	init_pathname(newname);
1190 	slash = strchr(name->path, '/');
1191 	if (slash == NULL) {
1192 		buf[0] = '\0';
1193 		return;
1194 	}
1195 	*slash = '\0';
1196 	strcpy(buf, name->path);
1197 	*slash = '/';
1198 	append_pathname(newname, slash + 1);
1199 }
1200 
1201 #define WIDTH 80
1202 
1203 void
1204 show_ops(int flag, char *lead_str)
1205 {
1206 	opdesc_t	*p;
1207 
1208         if (flag<0) {
1209                 /* print in list form */
1210                 int             x = WIDTH;
1211 
1212 	        for (p = ops; p < ops_end; p++) {
1213 			if (lead_str != NULL && x+strlen(p->name)>=WIDTH-5)
1214 				x=printf("%s%s", (p==ops)?"":"\n", lead_str);
1215                         x+=printf("%s ", p->name);
1216                 }
1217                 printf("\n");
1218         } else {
1219 	        int		f;
1220 	        for (f = 0, p = ops; p < ops_end; p++)
1221 		        f += p->freq;
1222 
1223 	        if (f == 0)
1224 		        flag = 1;
1225 
1226 	        for (p = ops; p < ops_end; p++) {
1227 		        if (flag != 0 || p->freq > 0) {
1228 			        if (lead_str != NULL)
1229 				        printf("%s", lead_str);
1230 			        printf("%20s %d/%d %s\n",
1231 			        p->name, p->freq, f,
1232 			        (p->iswrite == 0) ? " " : "write op");
1233 		        }
1234                 }
1235 	}
1236 }
1237 
1238 int
1239 stat64_path(pathname_t *name, struct stat64 *sbuf)
1240 {
1241 	char		buf[MAXNAMELEN];
1242 	pathname_t	newname;
1243 	int		rval;
1244 
1245 	rval = stat64(name->path, sbuf);
1246 	if (rval >= 0 || errno != ENAMETOOLONG)
1247 		return rval;
1248 	separate_pathname(name, buf, &newname);
1249 	if (chdir(buf) == 0) {
1250 		rval = stat64_path(&newname, sbuf);
1251 		chdir("..");
1252 	}
1253 	free_pathname(&newname);
1254 	return rval;
1255 }
1256 
1257 int
1258 symlink_path(const char *name1, pathname_t *name)
1259 {
1260 	char		buf[MAXNAMELEN];
1261 	pathname_t	newname;
1262 	int		rval;
1263 
1264         if (!strcmp(name1, name->path)) {
1265             printf("yikes! %s %s\n", name1, name->path);
1266             return 0;
1267         }
1268 
1269 	rval = symlink(name1, name->path);
1270 	if (rval >= 0 || errno != ENAMETOOLONG)
1271 		return rval;
1272 	separate_pathname(name, buf, &newname);
1273 	if (chdir(buf) == 0) {
1274 		rval = symlink_path(name1, &newname);
1275 		chdir("..");
1276 	}
1277 	free_pathname(&newname);
1278 	return rval;
1279 }
1280 
1281 int
1282 truncate64_path(pathname_t *name, off64_t length)
1283 {
1284 	char		buf[MAXNAMELEN];
1285 	pathname_t	newname;
1286 	int		rval;
1287 
1288 	rval = truncate64(name->path, length);
1289 	if (rval >= 0 || errno != ENAMETOOLONG)
1290 		return rval;
1291 	separate_pathname(name, buf, &newname);
1292 	if (chdir(buf) == 0) {
1293 		rval = truncate64_path(&newname, length);
1294 		chdir("..");
1295 	}
1296 	free_pathname(&newname);
1297 	return rval;
1298 }
1299 
1300 int
1301 unlink_path(pathname_t *name)
1302 {
1303 	char		buf[MAXNAMELEN];
1304 	pathname_t	newname;
1305 	int		rval;
1306 
1307 	rval = unlink(name->path);
1308 	if (rval >= 0 || errno != ENAMETOOLONG)
1309 		return rval;
1310 	separate_pathname(name, buf, &newname);
1311 	if (chdir(buf) == 0) {
1312 		rval = unlink_path(&newname);
1313 		chdir("..");
1314 	}
1315 	free_pathname(&newname);
1316 	return rval;
1317 }
1318 
1319 void
1320 usage(void)
1321 {
1322 	printf("Usage: %s -H   or\n", myprog);
1323 	printf("       %s [-d dir][-e errtg][-f op_name=freq][-n nops]\n",
1324 		myprog);
1325 	printf("          [-p nproc][-r len][-s seed][-v][-w][-z][-S]\n");
1326 	printf("where\n");
1327 	printf("   -d dir           specifies the base directory for operations\n");
1328 	printf("   -e errtg         specifies error injection stuff\n");
1329 	printf("   -f op_name=freq  changes the frequency of option name to freq\n");
1330 	printf("                    the valid operation names are:\n");
1331 	show_ops(-1, "                        ");
1332 	printf("   -n nops          specifies the no. of operations per process (default 1)\n");
1333 	printf("   -p nproc         specifies the no. of processes (default 1)\n");
1334 	printf("   -r               specifies random name padding\n");
1335 	printf("   -s seed          specifies the seed for the random generator (default random)\n");
1336 	printf("   -v               specifies verbose mode\n");
1337 	printf("   -w               zeros frequencies of non-write operations\n");
1338 	printf("   -z               zeros frequencies of all operations\n");
1339 	printf("   -S               prints the table of operations (omitting zero frequency)\n");
1340 	printf("   -H               prints usage and exits\n");
1341 	printf("   -X               don't do anything XFS specific (default with -DNO_XFS)\n");
1342 }
1343 
1344 void
1345 write_freq(void)
1346 {
1347 	opdesc_t	*p;
1348 
1349 	for (p = ops; p < ops_end; p++) {
1350 		if (!p->iswrite)
1351 			p->freq = 0;
1352 	}
1353 }
1354 
1355 void
1356 zero_freq(void)
1357 {
1358 	opdesc_t	*p;
1359 
1360 	for (p = ops; p < ops_end; p++)
1361 		p->freq = 0;
1362 }
1363 
1364 #ifndef NO_XFS
1365 
1366 void
1367 allocsp_f(int opno, long r)
1368 {
1369 	int		e;
1370 	pathname_t	f;
1371 	int		fd;
1372 	struct flock64	fl;
1373 	__int64_t	lr;
1374 	off64_t		off;
1375 	struct stat64	stb;
1376 	int		v;
1377 
1378 	init_pathname(&f);
1379 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1380 		if (v)
1381 			printf("%d/%d: allocsp - no filename\n", procid, opno);
1382 		free_pathname(&f);
1383 		return;
1384 	}
1385 	fd = open_path(&f, O_RDWR);
1386 	e = fd < 0 ? errno : 0;
1387 	check_cwd();
1388 	if (fd < 0) {
1389 		if (v)
1390 			printf("%d/%d: allocsp - open %s failed %d\n",
1391 				procid, opno, f.path, e);
1392 		free_pathname(&f);
1393 		return;
1394 	}
1395 	if (fstat64(fd, &stb) < 0) {
1396 		if (v)
1397 			printf("%d/%d: allocsp - fstat64 %s failed %d\n",
1398 				procid, opno, f.path, errno);
1399 		free_pathname(&f);
1400 		close(fd);
1401 		return;
1402 	}
1403 	lr = ((__int64_t)random() << 32) + random();
1404 	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1405 	off %= maxfsize;
1406 	fl.l_whence = SEEK_SET;
1407 	fl.l_start = off;
1408 	fl.l_len = 0;
1409 	e = ioctl(fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
1410 	if (v)
1411 		printf("%d/%d: ioctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n",
1412 			procid, opno, f.path, off, e);
1413 	free_pathname(&f);
1414 	close(fd);
1415 }
1416 
1417 void
1418 attr_remove_f(int opno, long r)
1419 {
1420 	attrlist_ent_t		*aep;
1421 	attrlist_t		*alist;
1422 	char			*aname;
1423 	char			buf[4096];
1424 	attrlist_cursor_t	cursor;
1425 	int			e;
1426 	int			ent;
1427 	pathname_t		f;
1428 	int			total;
1429 	int			v;
1430 	int			which;
1431 
1432 	init_pathname(&f);
1433 	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1434 		append_pathname(&f, ".");
1435 	total = 0;
1436 	bzero(&cursor, sizeof(cursor));
1437 	do {
1438 		e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW,
1439 			&cursor);
1440 		check_cwd();
1441 		if (e)
1442 			break;
1443 		alist = (attrlist_t *)buf;
1444 		total += alist->al_count;
1445 	} while (alist->al_more);
1446 	if (total == 0) {
1447 		if (v)
1448 			printf("%d/%d: attr_remove - no attrs for %s\n",
1449 				procid, opno, f.path);
1450 		free_pathname(&f);
1451 		return;
1452 	}
1453 	which = (int)(random() % total);
1454 	bzero(&cursor, sizeof(cursor));
1455 	ent = 0;
1456 	aname = NULL;
1457 	do {
1458 		e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW,
1459 			&cursor);
1460 		check_cwd();
1461 		if (e)
1462 			break;
1463 		alist = (attrlist_t *)buf;
1464 		if (which < ent + alist->al_count) {
1465 			aep = (attrlist_ent_t *)
1466 				&buf[alist->al_offset[which - ent]];
1467 			aname = aep->a_name;
1468 			break;
1469 		}
1470 		ent += alist->al_count;
1471 	} while (alist->al_more);
1472 	if (aname == NULL) {
1473 		if (v)
1474 			printf(
1475 			"%d/%d: attr_remove - name %d not found at %s\n",
1476 				procid, opno, which, f.path);
1477 		free_pathname(&f);
1478 		return;
1479 	}
1480 	e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0;
1481 	check_cwd();
1482 	if (v)
1483 		printf("%d/%d: attr_remove %s %s %d\n",
1484 			procid, opno, f.path, aname, e);
1485 	free_pathname(&f);
1486 }
1487 
1488 void
1489 attr_set_f(int opno, long r)
1490 {
1491 	char		aname[10];
1492 	char		*aval;
1493 	int		e;
1494 	pathname_t	f;
1495 	int		len;
1496 	static int	lengths[] = { 10, 100, 1000, 10000 };
1497 	int		li;
1498 	int		v;
1499 
1500 	init_pathname(&f);
1501 	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1502 		append_pathname(&f, ".");
1503 	sprintf(aname, "a%x", nameseq++);
1504 	li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0])));
1505 	len = (int)(random() % lengths[li]);
1506 	if (len == 0)
1507 		len = 1;
1508 	aval = malloc(len);
1509 	memset(aval, nameseq & 0xff, len);
1510 	e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ?
1511 		errno : 0;
1512 	check_cwd();
1513 	free(aval);
1514 	if (v)
1515 		printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path,
1516 			aname, e);
1517 	free_pathname(&f);
1518 }
1519 
1520 void
1521 bulkstat_f(int opno, long r)
1522 {
1523 	int		count;
1524 	int		fd;
1525 	__uint64_t	last;
1526 	int		nent;
1527 	xfs_bstat_t	*t;
1528 	__int64_t	total;
1529         xfs_fsop_bulkreq_t bsr;
1530 
1531 	last = 0;
1532 	nent = (r % 999) + 2;
1533 	t = malloc(nent * sizeof(*t));
1534 	fd = open(".", O_RDONLY);
1535 	total = 0;
1536 
1537         bsr.lastip=&last;
1538         bsr.icount=nent;
1539         bsr.ubuffer=t;
1540         bsr.ocount=&count;
1541 
1542 	while (ioctl(fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
1543 		total += count;
1544 	free(t);
1545 	if (verbose)
1546 		printf("%d/%d: bulkstat nent %d total %lld\n",
1547 			procid, opno, nent, total);
1548 	close(fd);
1549 }
1550 
1551 void
1552 bulkstat1_f(int opno, long r)
1553 {
1554 	int		e;
1555 	pathname_t	f;
1556 	int		fd;
1557 	int		good;
1558 	__uint64_t	ino;
1559 	struct stat64	s;
1560 	xfs_bstat_t	t;
1561 	int		v;
1562         xfs_fsop_bulkreq_t bsr;
1563 
1564 
1565 	good = random() & 1;
1566 	if (good) {
1567                /* use an inode we know exists */
1568 		init_pathname(&f);
1569 		if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1570 			append_pathname(&f, ".");
1571 		ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino;
1572 		check_cwd();
1573 		free_pathname(&f);
1574 	} else {
1575                 /*
1576                  * pick a random inode
1577                  *
1578                  * note this can generate kernel warning messages
1579                  * since bulkstat_one will read the disk block that
1580                  * would contain a given inode even if that disk
1581                  * block doesn't contain inodes.
1582                  *
1583                  * this is detected later, but not until after the
1584                  * warning is displayed.
1585                  *
1586                  * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0"
1587                  *
1588                  */
1589 		ino = (ino64_t)r;
1590 		v = verbose;
1591 	}
1592 	fd = open(".", O_RDONLY);
1593 
1594         bsr.lastip=&ino;
1595         bsr.icount=1;
1596         bsr.ubuffer=&t;
1597         bsr.ocount=NULL;
1598 
1599 	e = ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
1600 	if (v)
1601 		printf("%d/%d: bulkstat1 %s ino %lld %d\n",
1602                     procid, opno, good?"real":"random", (int64_t)ino, e);
1603 	close(fd);
1604 }
1605 
1606 #endif
1607 
1608 void
1609 chown_f(int opno, long r)
1610 {
1611 	int		e;
1612 	pathname_t	f;
1613 	int		nbits;
1614 	uid_t		u;
1615 	int		v;
1616 
1617 	init_pathname(&f);
1618 	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1619 		append_pathname(&f, ".");
1620 	u = (uid_t)random();
1621 	nbits = (int)(random() % 32);
1622 	u &= (1 << nbits) - 1;
1623 	e = lchown_path(&f, u, -1) < 0 ? errno : 0;
1624 	check_cwd();
1625 	if (v)
1626 		printf("%d/%d: chown %s %d %d\n", procid, opno, f.path, u, e);
1627 	free_pathname(&f);
1628 }
1629 
1630 void
1631 creat_f(int opno, long r)
1632 {
1633 	int		e;
1634 	int		e1;
1635 	int		extsize;
1636 	pathname_t	f;
1637 	int		fd;
1638 	fent_t		*fep;
1639 	int		id;
1640 	int		parid;
1641 	int		type;
1642 	int		v;
1643 	int		v1;
1644 	int esz=0;
1645 
1646 	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
1647 		parid = -1;
1648 	else
1649 		parid = fep->id;
1650 	init_pathname(&f);
1651 	type = rtpct ? ((random() % 100) > rtpct ? FT_REG : FT_RTF) : FT_REG;
1652 	if (type == FT_RTF)
1653 		extsize = (random() % 10) + 1;
1654 	else
1655 		extsize = 0;
1656 	e = generate_fname(fep, type, &f, &id, &v);
1657 	v |= v1;
1658 	if (!e) {
1659 		if (v) {
1660 			fent_to_name(&f, &flist[FT_DIR], fep);
1661 			printf("%d/%d: creat - no filename from %s\n",
1662 				procid, opno, f.path);
1663 		}
1664 		free_pathname(&f);
1665 		return;
1666 	}
1667 	fd = creat_path(&f, 0666);
1668 	e = fd < 0 ? errno : 0;
1669 	e1 = 0;
1670 	check_cwd();
1671 	esz = 0;
1672 	if (fd >= 0) {
1673 #ifndef NO_XFS
1674 		struct fsxattr	a;
1675 		if (extsize && ioctl(fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
1676 			a.fsx_xflags |= XFS_XFLAG_REALTIME;
1677 			a.fsx_extsize =
1678 				geom.rtextsize * geom.blocksize * extsize;
1679 			if (ioctl(fd, XFS_IOC_FSSETXATTR, &a) < 0)
1680 				e1 = errno;
1681 			esz = a.fsx_estsize;
1682 
1683 		}
1684 		add_to_flist(type, id, parid);
1685 #endif
1686 		close(fd);
1687 	}
1688 	if (v)
1689 		printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
1690 			esz, e, e1);
1691 	free_pathname(&f);
1692 }
1693 
1694 
1695 
1696 int
1697 setdirect(int fd)
1698 {
1699 	static int no_direct;
1700 	int flags;
1701 
1702 	if (no_direct)
1703 		return 0;
1704 
1705 	flags = fcntl(fd, F_GETFL, 0);
1706 	if (flags < 0)
1707 		return 0;
1708 
1709 	if (fcntl(fd, F_SETFL, flags|O_DIRECT)  < 0) {
1710 		if (no_xfs) {
1711 			no_direct = 1;
1712 			return 0;
1713 		}
1714 		printf("cannot set O_DIRECT: %s\n", strerror(errno));
1715 		return 0;
1716 	}
1717 
1718 	return 1;
1719 }
1720 
1721 void
1722 dread_f(int opno, long r)
1723 {
1724 	__int64_t	align;
1725 	char		*buf;
1726 	struct dioattr	diob;
1727 	int		e;
1728 	pathname_t	f;
1729 	int		fd;
1730 	size_t		len;
1731 	__int64_t	lr;
1732 	off64_t		off;
1733 	struct stat64	stb;
1734 	int		v;
1735 
1736 	init_pathname(&f);
1737 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1738 		if (v)
1739 			printf("%d/%d: dread - no filename\n", procid, opno);
1740 		free_pathname(&f);
1741 		return;
1742 	}
1743 	fd = open_path(&f, O_RDONLY);
1744 
1745 	if (!setdirect(fd)) {
1746 		return;
1747 	}
1748 
1749 	e = fd < 0 ? errno : 0;
1750 	check_cwd();
1751 	if (fd < 0) {
1752 		if (v)
1753 			printf("%d/%d: dread - open %s failed %d\n",
1754 				procid, opno, f.path, e);
1755 		free_pathname(&f);
1756 		return;
1757 	}
1758 	if (fstat64(fd, &stb) < 0) {
1759 		if (v)
1760 			printf("%d/%d: dread - fstat64 %s failed %d\n",
1761 				procid, opno, f.path, errno);
1762 		free_pathname(&f);
1763 		close(fd);
1764 		return;
1765 	}
1766 	if (stb.st_size == 0) {
1767 		if (v)
1768 			printf("%d/%d: dread - %s zero size\n", procid, opno,
1769 				f.path);
1770 		free_pathname(&f);
1771 		close(fd);
1772 		return;
1773 	}
1774 
1775 	if (no_xfs) {
1776 		diob.d_miniosz = stb.st_blksize;
1777 		diob.d_maxiosz = stb.st_blksize * 256;  /* good number ? */
1778 		diob.d_mem = stb.st_blksize;
1779 	}
1780 #ifndef NO_XFS
1781 	   else 	if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) {
1782 		if (v)
1783 			printf(
1784 			"%d/%d: dread - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n",
1785 				procid, opno, f.path, errno);
1786 		free_pathname(&f);
1787 		close(fd);
1788 		return;
1789 	}
1790 #endif
1791 	align = (__int64_t)diob.d_miniosz;
1792 	lr = ((__int64_t)random() << 32) + random();
1793 	off = (off64_t)(lr % stb.st_size);
1794 	off -= (off % align);
1795 	lseek64(fd, off, SEEK_SET);
1796 	len = (random() % (getpagesize() * 32)) + 1;
1797 	len -= (len % align);
1798 	if (len <= 0)
1799 		len = align;
1800 	else if (len > diob.d_maxiosz)
1801 		len = diob.d_maxiosz;
1802 	buf = memalign(diob.d_mem, len);
1803 	e = read(fd, buf, len) < 0 ? errno : 0;
1804 	free(buf);
1805 	if (v)
1806 		printf("%d/%d: dread %s [%lld,%d] %d\n",
1807 			procid, opno, f.path, off, len, e);
1808 	free_pathname(&f);
1809 	close(fd);
1810 }
1811 
1812 void
1813 dwrite_f(int opno, long r)
1814 {
1815 	__int64_t	align;
1816 	char		*buf;
1817 	struct dioattr	diob;
1818 	int		e;
1819 	pathname_t	f;
1820 	int		fd;
1821 	size_t		len;
1822 	__int64_t	lr;
1823 	off64_t		off;
1824 	struct stat64	stb;
1825 	int		v;
1826 
1827 	init_pathname(&f);
1828 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1829 		if (v)
1830 			printf("%d/%d: dwrite - no filename\n", procid, opno);
1831 		free_pathname(&f);
1832 		return;
1833 	}
1834 	fd = open_path(&f, O_WRONLY);
1835 	e = fd < 0 ? errno : 0;
1836 	check_cwd();
1837 	if (fd < 0) {
1838 		if (v)
1839 			printf("%d/%d: dwrite - open %s failed %d\n",
1840 				procid, opno, f.path, e);
1841 		free_pathname(&f);
1842 		return;
1843 	}
1844 
1845 	if (!setdirect(fd))
1846 		return;
1847 	if (fstat64(fd, &stb) < 0) {
1848 		if (v)
1849 			printf("%d/%d: dwrite - fstat64 %s failed %d\n",
1850 				procid, opno, f.path, errno);
1851 		free_pathname(&f);
1852 		close(fd);
1853 		return;
1854 	}
1855 	if (no_xfs) {
1856 		diob.d_miniosz = stb.st_blksize;
1857 		diob.d_maxiosz = stb.st_blksize * 256;  /* good number ? */
1858 		diob.d_mem = stb.st_blksize;
1859 	}
1860 #ifndef NO_XFS
1861 	else if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) {
1862 		if (v)
1863 			printf(
1864 			"%d/%d: dwrite - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n",
1865 				procid, opno, f.path, errno);
1866 		free_pathname(&f);
1867 		close(fd);
1868 		return;
1869 	}
1870 #endif
1871 	align = (__int64_t)diob.d_miniosz;
1872 	lr = ((__int64_t)random() << 32) + random();
1873 	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1874 	off -= (off % align);
1875 	lseek64(fd, off, SEEK_SET);
1876 	len = (random() % (getpagesize() * 32)) + 1;
1877 	len -= (len % align);
1878 	if (len <= 0)
1879 		len = align;
1880 	else if (len > diob.d_maxiosz)
1881 		len = diob.d_maxiosz;
1882 	buf = memalign(diob.d_mem, len);
1883 	off %= maxfsize;
1884 	lseek64(fd, off, SEEK_SET);
1885 	memset(buf, nameseq & 0xff, len);
1886 	e = write(fd, buf, len) < 0 ? errno : 0;
1887 	free(buf);
1888 	if (v)
1889 		printf("%d/%d: dwrite %s [%lld,%d] %d\n",
1890 			procid, opno, f.path, off, len, e);
1891 	free_pathname(&f);
1892 	close(fd);
1893 }
1894 
1895 void
1896 fdatasync_f(int opno, long r)
1897 {
1898 	int		e;
1899 	pathname_t	f;
1900 	int		fd;
1901 	int		v;
1902 
1903 	init_pathname(&f);
1904 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1905 		if (v)
1906 			printf("%d/%d: fdatasync - no filename\n",
1907 				procid, opno);
1908 		free_pathname(&f);
1909 		return;
1910 	}
1911 	fd = open_path(&f, O_WRONLY);
1912 	e = fd < 0 ? errno : 0;
1913 	check_cwd();
1914 	if (fd < 0) {
1915 		if (v)
1916 			printf("%d/%d: fdatasync - open %s failed %d\n",
1917 				procid, opno, f.path, e);
1918 		free_pathname(&f);
1919 		return;
1920 	}
1921 	e = fdatasync(fd) < 0 ? errno : 0;
1922 	if (v)
1923 		printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e);
1924 	free_pathname(&f);
1925 	close(fd);
1926 }
1927 
1928 #ifndef NO_XFS
1929 void
1930 freesp_f(int opno, long r)
1931 {
1932 	int		e;
1933 	pathname_t	f;
1934 	int		fd;
1935 	struct flock64	fl;
1936 	__int64_t	lr;
1937 	off64_t		off;
1938 	struct stat64	stb;
1939 	int		v;
1940 
1941 	init_pathname(&f);
1942 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1943 		if (v)
1944 			printf("%d/%d: freesp - no filename\n", procid, opno);
1945 		free_pathname(&f);
1946 		return;
1947 	}
1948 	fd = open_path(&f, O_RDWR);
1949 	e = fd < 0 ? errno : 0;
1950 	check_cwd();
1951 	if (fd < 0) {
1952 		if (v)
1953 			printf("%d/%d: freesp - open %s failed %d\n",
1954 				procid, opno, f.path, e);
1955 		free_pathname(&f);
1956 		return;
1957 	}
1958 	if (fstat64(fd, &stb) < 0) {
1959 		if (v)
1960 			printf("%d/%d: freesp - fstat64 %s failed %d\n",
1961 				procid, opno, f.path, errno);
1962 		free_pathname(&f);
1963 		close(fd);
1964 		return;
1965 	}
1966 	lr = ((__int64_t)random() << 32) + random();
1967 	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1968 	off %= maxfsize;
1969 	fl.l_whence = SEEK_SET;
1970 	fl.l_start = off;
1971 	fl.l_len = 0;
1972 	e = ioctl(fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
1973 	if (v)
1974 		printf("%d/%d: ioctl(XFS_IOC_FREESP64) %s %lld 0 %d\n",
1975 			procid, opno, f.path, off, e);
1976 	free_pathname(&f);
1977 	close(fd);
1978 }
1979 
1980 #endif
1981 
1982 void
1983 fsync_f(int opno, long r)
1984 {
1985 	int		e;
1986 	pathname_t	f;
1987 	int		fd;
1988 	int		v;
1989 
1990 	init_pathname(&f);
1991 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1992 		if (v)
1993 			printf("%d/%d: fsync - no filename\n", procid, opno);
1994 		free_pathname(&f);
1995 		return;
1996 	}
1997 	fd = open_path(&f, O_WRONLY);
1998 	e = fd < 0 ? errno : 0;
1999 	check_cwd();
2000 	if (fd < 0) {
2001 		if (v)
2002 			printf("%d/%d: fsync - open %s failed %d\n",
2003 				procid, opno, f.path, e);
2004 		free_pathname(&f);
2005 		return;
2006 	}
2007 	e = fsync(fd) < 0 ? errno : 0;
2008 	if (v)
2009 		printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e);
2010 	free_pathname(&f);
2011 	close(fd);
2012 }
2013 
2014 void
2015 getdents_f(int opno, long r)
2016 {
2017 	DIR		*dir;
2018 	pathname_t	f;
2019 	int		v;
2020 
2021 	init_pathname(&f);
2022 	if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
2023 		append_pathname(&f, ".");
2024 	dir = opendir_path(&f);
2025 	check_cwd();
2026 	if (dir == NULL) {
2027 		if (v)
2028 			printf("%d/%d: getdents - can't open %s\n",
2029 				procid, opno, f.path);
2030 		free_pathname(&f);
2031 		return;
2032 	}
2033 	while (readdir64(dir) != NULL)
2034 		continue;
2035 	if (v)
2036 		printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
2037 	free_pathname(&f);
2038 	closedir(dir);
2039 }
2040 
2041 void
2042 link_f(int opno, long r)
2043 {
2044 	int		e;
2045 	pathname_t	f;
2046 	fent_t		*fep;
2047 	flist_t		*flp;
2048 	int		id;
2049 	pathname_t	l;
2050 	int		parid;
2051 	int		v;
2052 	int		v1;
2053 
2054 	init_pathname(&f);
2055 	if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
2056 		if (v1)
2057 			printf("%d/%d: link - no file\n", procid, opno);
2058 		free_pathname(&f);
2059 		return;
2060 	}
2061 	if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
2062 		parid = -1;
2063 	else
2064 		parid = fep->id;
2065 	v |= v1;
2066 	init_pathname(&l);
2067 	e = generate_fname(fep, flp - flist, &l, &id, &v1);
2068 	v |= v1;
2069 	if (!e) {
2070 		if (v) {
2071 			fent_to_name(&l, &flist[FT_DIR], fep);
2072 			printf("%d/%d: link - no filename from %s\n",
2073 				procid, opno, l.path);
2074 		}
2075 		free_pathname(&l);
2076 		free_pathname(&f);
2077 		return;
2078 	}
2079 	e = link_path(&f, &l) < 0 ? errno : 0;
2080 	check_cwd();
2081 	if (e == 0)
2082 		add_to_flist(flp - flist, id, parid);
2083 	if (v)
2084 		printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
2085 			e);
2086 	free_pathname(&l);
2087 	free_pathname(&f);
2088 }
2089 
2090 void
2091 mkdir_f(int opno, long r)
2092 {
2093 	int		e;
2094 	pathname_t	f;
2095 	fent_t		*fep;
2096 	int		id;
2097 	int		parid;
2098 	int		v;
2099 	int		v1;
2100 
2101 	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2102 		parid = -1;
2103 	else
2104 		parid = fep->id;
2105 	init_pathname(&f);
2106 	e = generate_fname(fep, FT_DIR, &f, &id, &v1);
2107 	v |= v1;
2108 	if (!e) {
2109 		if (v) {
2110 			fent_to_name(&f, &flist[FT_DIR], fep);
2111 			printf("%d/%d: mkdir - no filename from %s\n",
2112 				procid, opno, f.path);
2113 		}
2114 		free_pathname(&f);
2115 		return;
2116 	}
2117 	e = mkdir_path(&f, 0777) < 0 ? errno : 0;
2118 	check_cwd();
2119 	if (e == 0)
2120 		add_to_flist(FT_DIR, id, parid);
2121 	if (v)
2122 		printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
2123 	free_pathname(&f);
2124 }
2125 
2126 void
2127 mknod_f(int opno, long r)
2128 {
2129 	int		e;
2130 	pathname_t	f;
2131 	fent_t		*fep;
2132 	int		id;
2133 	int		parid;
2134 	int		v;
2135 	int		v1;
2136 
2137 	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2138 		parid = -1;
2139 	else
2140 		parid = fep->id;
2141 	init_pathname(&f);
2142 	e = generate_fname(fep, FT_DEV, &f, &id, &v1);
2143 	v |= v1;
2144 	if (!e) {
2145 		if (v) {
2146 			fent_to_name(&f, &flist[FT_DIR], fep);
2147 			printf("%d/%d: mknod - no filename from %s\n",
2148 				procid, opno, f.path);
2149 		}
2150 		free_pathname(&f);
2151 		return;
2152 	}
2153 	e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
2154 	check_cwd();
2155 	if (e == 0)
2156 		add_to_flist(FT_DEV, id, parid);
2157 	if (v)
2158 		printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
2159 	free_pathname(&f);
2160 }
2161 
2162 void
2163 read_f(int opno, long r)
2164 {
2165 	char		*buf;
2166 	int		e;
2167 	pathname_t	f;
2168 	int		fd;
2169 	size_t		len;
2170 	__int64_t	lr;
2171 	off64_t		off;
2172 	struct stat64	stb;
2173 	int		v;
2174 
2175 	init_pathname(&f);
2176 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2177 		if (v)
2178 			printf("%d/%d: read - no filename\n", procid, opno);
2179 		free_pathname(&f);
2180 		return;
2181 	}
2182 	fd = open_path(&f, O_RDONLY);
2183 	e = fd < 0 ? errno : 0;
2184 	check_cwd();
2185 	if (fd < 0) {
2186 		if (v)
2187 			printf("%d/%d: read - open %s failed %d\n",
2188 				procid, opno, f.path, e);
2189 		free_pathname(&f);
2190 		return;
2191 	}
2192 	if (fstat64(fd, &stb) < 0) {
2193 		if (v)
2194 			printf("%d/%d: read - fstat64 %s failed %d\n",
2195 				procid, opno, f.path, errno);
2196 		free_pathname(&f);
2197 		close(fd);
2198 		return;
2199 	}
2200 	if (stb.st_size == 0) {
2201 		if (v)
2202 			printf("%d/%d: read - %s zero size\n", procid, opno,
2203 				f.path);
2204 		free_pathname(&f);
2205 		close(fd);
2206 		return;
2207 	}
2208 	lr = ((__int64_t)random() << 32) + random();
2209 	off = (off64_t)(lr % stb.st_size);
2210 	lseek64(fd, off, SEEK_SET);
2211 	len = (random() % (getpagesize() * 32)) + 1;
2212 	buf = malloc(len);
2213 	e = read(fd, buf, len) < 0 ? errno : 0;
2214 	free(buf);
2215 	if (v)
2216 		printf("%d/%d: read %s [%lld,%d] %d\n",
2217 			procid, opno, f.path, off, len, e);
2218 	free_pathname(&f);
2219 	close(fd);
2220 }
2221 
2222 void
2223 readlink_f(int opno, long r)
2224 {
2225 	char		buf[PATH_MAX];
2226 	int		e;
2227 	pathname_t	f;
2228 	int		v;
2229 
2230 	init_pathname(&f);
2231 	if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
2232 		if (v)
2233 			printf("%d/%d: readlink - no filename\n", procid, opno);
2234 		free_pathname(&f);
2235 		return;
2236 	}
2237 	e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
2238 	check_cwd();
2239 	if (v)
2240 		printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e);
2241 	free_pathname(&f);
2242 }
2243 
2244 void
2245 rename_f(int opno, long r)
2246 {
2247 	fent_t		*dfep;
2248 	int		e;
2249 	pathname_t	f;
2250 	fent_t		*fep;
2251 	flist_t		*flp;
2252 	int		id;
2253 	pathname_t	newf;
2254 	int		oldid;
2255 	int		parid;
2256 	int		v;
2257 	int		v1;
2258 
2259 	init_pathname(&f);
2260 	if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
2261 		if (v1)
2262 			printf("%d/%d: rename - no filename\n", procid, opno);
2263 		free_pathname(&f);
2264 		return;
2265 	}
2266 	if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
2267 		parid = -1;
2268 	else
2269 		parid = dfep->id;
2270 	v |= v1;
2271 	init_pathname(&newf);
2272 	e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
2273 	v |= v1;
2274 	if (!e) {
2275 		if (v) {
2276 			fent_to_name(&f, &flist[FT_DIR], dfep);
2277 			printf("%d/%d: rename - no filename from %s\n",
2278 				procid, opno, f.path);
2279 		}
2280 		free_pathname(&newf);
2281 		free_pathname(&f);
2282 		return;
2283 	}
2284 	e = rename_path(&f, &newf) < 0 ? errno : 0;
2285 	check_cwd();
2286 	if (e == 0) {
2287 		if (flp - flist == FT_DIR) {
2288 			oldid = fep->id;
2289 			fix_parent(oldid, id);
2290 		}
2291 		del_from_flist(flp - flist, fep - flp->fents);
2292 		add_to_flist(flp - flist, id, parid);
2293 	}
2294 	if (v)
2295 		printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
2296 			newf.path, e);
2297 	free_pathname(&newf);
2298 	free_pathname(&f);
2299 }
2300 
2301 #ifndef NO_XFS
2302 void
2303 resvsp_f(int opno, long r)
2304 {
2305 	int		e;
2306 	pathname_t	f;
2307 	int		fd;
2308 	struct flock64	fl;
2309 	__int64_t	lr;
2310 	off64_t		off;
2311 	struct stat64	stb;
2312 	int		v;
2313 
2314 	init_pathname(&f);
2315 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2316 		if (v)
2317 			printf("%d/%d: resvsp - no filename\n", procid, opno);
2318 		free_pathname(&f);
2319 		return;
2320 	}
2321 	fd = open_path(&f, O_RDWR);
2322 	e = fd < 0 ? errno : 0;
2323 	check_cwd();
2324 	if (fd < 0) {
2325 		if (v)
2326 			printf("%d/%d: resvsp - open %s failed %d\n",
2327 				procid, opno, f.path, e);
2328 		free_pathname(&f);
2329 		return;
2330 	}
2331 	if (fstat64(fd, &stb) < 0) {
2332 		if (v)
2333 			printf("%d/%d: resvsp - fstat64 %s failed %d\n",
2334 				procid, opno, f.path, errno);
2335 		free_pathname(&f);
2336 		close(fd);
2337 		return;
2338 	}
2339 	lr = ((__int64_t)random() << 32) + random();
2340 	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2341 	off %= maxfsize;
2342 	fl.l_whence = SEEK_SET;
2343 	fl.l_start = off;
2344 	fl.l_len = (off64_t)(random() % (1024 * 1024));
2345 	e = ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
2346 	if (v)
2347 		printf("%d/%d: ioctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n",
2348 			procid, opno, f.path, off, fl.l_len, e);
2349 	free_pathname(&f);
2350 	close(fd);
2351 }
2352 #endif
2353 
2354 void
2355 rmdir_f(int opno, long r)
2356 {
2357 	int		e;
2358 	pathname_t	f;
2359 	fent_t		*fep;
2360 	int		v;
2361 
2362 	init_pathname(&f);
2363 	if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
2364 		if (v)
2365 			printf("%d/%d: rmdir - no directory\n", procid, opno);
2366 		free_pathname(&f);
2367 		return;
2368 	}
2369 	e = rmdir_path(&f) < 0 ? errno : 0;
2370 	check_cwd();
2371 	if (e == 0)
2372 		del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
2373 	if (v)
2374 		printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e);
2375 	free_pathname(&f);
2376 }
2377 
2378 void
2379 stat_f(int opno, long r)
2380 {
2381 	int		e;
2382 	pathname_t	f;
2383 	struct stat64	stb;
2384 	int		v;
2385 
2386 	init_pathname(&f);
2387 	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
2388 		if (v)
2389 			printf("%d/%d: stat - no entries\n", procid, opno);
2390 		free_pathname(&f);
2391 		return;
2392 	}
2393 	e = lstat64_path(&f, &stb) < 0 ? errno : 0;
2394 	check_cwd();
2395 	if (v)
2396 		printf("%d/%d: stat %s %d\n", procid, opno, f.path, e);
2397 	free_pathname(&f);
2398 }
2399 
2400 void
2401 symlink_f(int opno, long r)
2402 {
2403 	int		e;
2404 	pathname_t	f;
2405 	fent_t		*fep;
2406 	int		i;
2407 	int		id;
2408 	int		len;
2409 	int		parid;
2410 	int		v;
2411 	int		v1;
2412 	char		*val;
2413 
2414 	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2415 		parid = -1;
2416 	else
2417 		parid = fep->id;
2418 	init_pathname(&f);
2419 	e = generate_fname(fep, FT_SYM, &f, &id, &v1);
2420 	v |= v1;
2421 	if (!e) {
2422 		if (v) {
2423 			fent_to_name(&f, &flist[FT_DIR], fep);
2424 			printf("%d/%d: symlink - no filename from %s\n",
2425 				procid, opno, f.path);
2426 		}
2427 		free_pathname(&f);
2428 		return;
2429 	}
2430 	len = (int)(random() % PATH_MAX);
2431 	val = malloc(len + 1);
2432 	if (len)
2433 		memset(val, 'x', len);
2434 	val[len] = '\0';
2435 	for (i = 10; i < len - 1; i += 10)
2436 		val[i] = '/';
2437 	e = symlink_path(val, &f) < 0 ? errno : 0;
2438 	check_cwd();
2439 	if (e == 0)
2440 		add_to_flist(FT_SYM, id, parid);
2441 	free(val);
2442 	if (v)
2443 		printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
2444 	free_pathname(&f);
2445 }
2446 
2447 /* ARGSUSED */
2448 void
2449 sync_f(int opno, long r)
2450 {
2451 	sync();
2452 	if (verbose)
2453 		printf("%d/%d: sync\n", procid, opno);
2454 }
2455 
2456 void
2457 truncate_f(int opno, long r)
2458 {
2459 	int		e;
2460 	pathname_t	f;
2461 	__int64_t	lr;
2462 	off64_t		off;
2463 	struct stat64	stb;
2464 	int		v;
2465 
2466 	init_pathname(&f);
2467 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2468 		if (v)
2469 			printf("%d/%d: truncate - no filename\n", procid, opno);
2470 		free_pathname(&f);
2471 		return;
2472 	}
2473 	e = stat64_path(&f, &stb) < 0 ? errno : 0;
2474 	check_cwd();
2475 	if (e > 0) {
2476 		if (v)
2477 			printf("%d/%d: truncate - stat64 %s failed %d\n",
2478 				procid, opno, f.path, e);
2479 		free_pathname(&f);
2480 		return;
2481 	}
2482 	lr = ((__int64_t)random() << 32) + random();
2483 	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2484 	off %= maxfsize;
2485 	e = truncate64_path(&f, off) < 0 ? errno : 0;
2486 	check_cwd();
2487 	if (v)
2488 		printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path,
2489 			off, e);
2490 	free_pathname(&f);
2491 }
2492 
2493 void
2494 unlink_f(int opno, long r)
2495 {
2496 	int		e;
2497 	pathname_t	f;
2498 	fent_t		*fep;
2499 	flist_t		*flp;
2500 	int		v;
2501 
2502 	init_pathname(&f);
2503 	if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
2504 		if (v)
2505 			printf("%d/%d: unlink - no file\n", procid, opno);
2506 		free_pathname(&f);
2507 		return;
2508 	}
2509 	e = unlink_path(&f) < 0 ? errno : 0;
2510 	check_cwd();
2511 	if (e == 0)
2512 		del_from_flist(flp - flist, fep - flp->fents);
2513 	if (v)
2514 		printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e);
2515 	free_pathname(&f);
2516 }
2517 
2518 #ifndef NO_XFS
2519 void
2520 unresvsp_f(int opno, long r)
2521 {
2522 	int		e;
2523 	pathname_t	f;
2524 	int		fd;
2525 	struct flock64	fl;
2526 	__int64_t	lr;
2527 	off64_t		off;
2528 	struct stat64	stb;
2529 	int		v;
2530 
2531 	init_pathname(&f);
2532 	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2533 		if (v)
2534 			printf("%d/%d: unresvsp - no filename\n", procid, opno);
2535 		free_pathname(&f);
2536 		return;
2537 	}
2538 	fd = open_path(&f, O_RDWR);
2539 	e = fd < 0 ? errno : 0;
2540 	check_cwd();
2541 	if (fd < 0) {
2542 		if (v)
2543 			printf("%d/%d: unresvsp - open %s failed %d\n",
2544 				procid, opno, f.path, e);
2545 		free_pathname(&f);
2546 		return;
2547 	}
2548 	if (fstat64(fd, &stb) < 0) {
2549 		if (v)
2550 			printf("%d/%d: unresvsp - fstat64 %s failed %d\n",
2551 				procid, opno, f.path, errno);
2552 		free_pathname(&f);
2553 		close(fd);
2554 		return;
2555 	}
2556 	lr = ((__int64_t)random() << 32) + random();
2557 	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2558 	off %= maxfsize;
2559 	fl.l_whence = SEEK_SET;
2560 	fl.l_start = off;
2561 	fl.l_len = (off64_t)(random() % (1 << 20));
2562 	e = ioctl(fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
2563 	if (v)
2564 		printf("%d/%d: ioctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n",
2565 			procid, opno, f.path, off, fl.l_len, e);
2566 	free_pathname(&f);
2567 	close(fd);
2568 }
2569 #endif
2570 
2571 void
2572 write_f(int opno, long r)
2573 {
2574 	char		*buf;
2575 	int		e;
2576 	pathname_t	f;
2577 	int		fd;
2578 	size_t		len;
2579 	__int64_t	lr;
2580 	off64_t		off;
2581 	struct stat64	stb;
2582 	int		v;
2583 
2584 	init_pathname(&f);
2585 	if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
2586 		if (v)
2587 			printf("%d/%d: write - no filename\n", procid, opno);
2588 		free_pathname(&f);
2589 		return;
2590 	}
2591 	fd = open_path(&f, O_WRONLY);
2592 	e = fd < 0 ? errno : 0;
2593 	check_cwd();
2594 	if (fd < 0) {
2595 		if (v)
2596 			printf("%d/%d: write - open %s failed %d\n",
2597 				procid, opno, f.path, e);
2598 		free_pathname(&f);
2599 		return;
2600 	}
2601 	if (fstat64(fd, &stb) < 0) {
2602 		if (v)
2603 			printf("%d/%d: write - fstat64 %s failed %d\n",
2604 				procid, opno, f.path, errno);
2605 		free_pathname(&f);
2606 		close(fd);
2607 		return;
2608 	}
2609 	lr = ((__int64_t)random() << 32) + random();
2610 	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2611 	off %= maxfsize;
2612 	lseek64(fd, off, SEEK_SET);
2613 	len = (random() % (getpagesize() * 32)) + 1;
2614 	buf = malloc(len);
2615 	memset(buf, nameseq & 0xff, len);
2616 	e = write(fd, buf, len) < 0 ? errno : 0;
2617 	free(buf);
2618 	if (v)
2619 		printf("%d/%d: write %s [%lld,%d] %d\n",
2620 			procid, opno, f.path, off, len, e);
2621 	free_pathname(&f);
2622 	close(fd);
2623 }
2624