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