[BACK]Return to fsstress.c CVS log [TXT][DIR] Up to [Development] / xfs-cmds / xfstests / ltp

File: [Development] / xfs-cmds / xfstests / ltp / fsstress.c (download)

Revision 1.7, Tue Oct 25 06:37:03 2005 UTC (11 years, 11 months ago) by tes.longdrop.melbourne.sgi.com
Branch: MAIN
Changes since 1.6: +135 -33 lines

Add comments, diganostics, pass back some errors from funcs.
Merge of master-melb:xfs-cmds:24197a by kenmcd.

  When tracking down an error msg from fsstress, I had no idea what
  was going on. So I have added a bunch of comments to the code
  and added some more diagnostics (in verbose mode). Have also passed
  back some failures which weren't directly before.
  Hopefully this will not change the ops which are called for
  a given rand-seed run.

/*
 * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it would be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * Further, this software is distributed without any warranty that it is
 * free of the rightful claim of any third person regarding infringement
 * or the like.  Any license provided herein, whether implied or
 * otherwise, applies only to this software file.  Patent licenses, if
 * any, provided herein do not apply to combinations of this program with
 * other software, or any other product whatsoever.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write the Free Software Foundation, Inc., 59
 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
 * 
 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
 * Mountain View, CA  94043, or:
 * 
 * http://www.sgi.com 
 * 
 * For further information regarding this notice, see: 
 * 
 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
 */

#include "global.h"

#ifdef HAVE_ATTR_XATTR_H
#include <attr/xattr.h>
#endif

#include <math.h>
#define XFS_ERRTAG_MAX		17
#define XFS_IDMODULO_MAX	32
#define XFS_PROJIDMODULO_MAX	16

/* was (getpagesize()*32) BUT want it to be same
 * on all platforms
 */
#define FILELEN_MAX		(32*4096)

typedef enum {
	OP_ALLOCSP,
	OP_ATTR_REMOVE,
	OP_ATTR_SET,
	OP_BULKSTAT,
	OP_BULKSTAT1,
	OP_CHOWN,
	OP_CHPROJ,
	OP_CREAT,
	OP_DREAD,
	OP_DWRITE,
	OP_FDATASYNC,
	OP_FREESP,
	OP_FSYNC,
	OP_GETDENTS,
	OP_LINK,
	OP_MKDIR,
	OP_MKNOD,
	OP_READ,
	OP_READLINK,
	OP_RENAME,
	OP_RESVSP,
	OP_RMDIR,
	OP_STAT,
	OP_SYMLINK,
	OP_SYNC,
	OP_TRUNCATE,
	OP_UNLINK,
	OP_UNRESVSP,
	OP_WRITE,
	OP_LAST
} opty_t;

typedef void (*opfnc_t)(int, long);

typedef struct opdesc {
	opty_t	op;
	char	*name;
	opfnc_t	func;
	int	freq;
	int	iswrite;
} opdesc_t;

typedef struct fent {
	int	id;
	int	parent;
} fent_t;

typedef struct flist {
	int	nfiles;
	int	nslots;
	int	tag;
	fent_t	*fents;
} flist_t;

typedef struct pathname {
	int	len;
	char	*path;
} pathname_t;

#define	FT_DIR	0
#define	FT_DIRm	(1 << FT_DIR)
#define	FT_REG	1
#define	FT_REGm	(1 << FT_REG)
#define	FT_SYM	2
#define	FT_SYMm	(1 << FT_SYM)
#define	FT_DEV	3
#define	FT_DEVm	(1 << FT_DEV)
#define	FT_RTF	4
#define	FT_RTFm	(1 << FT_RTF)
#define	FT_nft	5
#define	FT_ANYm	((1 << FT_nft) - 1)
#define	FT_REGFILE	(FT_REGm | FT_RTFm)
#define	FT_NOTDIR	(FT_ANYm & ~FT_DIRm)

#define	FLIST_SLOT_INCR	16
#define	NDCACHE	64

#define	MAXFSIZE	((1ULL << 63) - 1ULL)
#define	MAXFSIZE32	((1ULL << 40) - 1ULL)

void	allocsp_f(int, long);
void	attr_remove_f(int, long);
void	attr_set_f(int, long);
void	bulkstat_f(int, long);
void	bulkstat1_f(int, long);
void	chown_f(int, long);
void	chproj_f(int, long);
void	creat_f(int, long);
void	dread_f(int, long);
void	dwrite_f(int, long);
void	fdatasync_f(int, long);
void	freesp_f(int, long);
void	fsync_f(int, long);
void	getdents_f(int, long);
void	link_f(int, long);
void	mkdir_f(int, long);
void	mknod_f(int, long);
void	read_f(int, long);
void	readlink_f(int, long);
void	rename_f(int, long);
void	resvsp_f(int, long);
void	rmdir_f(int, long);
void	stat_f(int, long);
void	symlink_f(int, long);
void	sync_f(int, long);
void	truncate_f(int, long);
void	unlink_f(int, long);
void	unresvsp_f(int, long);
void	write_f(int, long);

opdesc_t	ops[] = {
	{ OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 },
	{ OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 },
	{ OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 },
	{ OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0 },
	{ OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0 },
	{ OP_CHOWN, "chown", chown_f, 3, 1 },
	{ OP_CHPROJ, "chproj", chproj_f, 1, 1 },
	{ OP_CREAT, "creat", creat_f, 4, 1 },
	{ OP_DREAD, "dread", dread_f, 4, 0 },
	{ OP_DWRITE, "dwrite", dwrite_f, 4, 1 },
	{ OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 },
	{ OP_FREESP, "freesp", freesp_f, 1, 1 },
	{ OP_FSYNC, "fsync", fsync_f, 1, 1 },
	{ OP_GETDENTS, "getdents", getdents_f, 1, 0 },
	{ OP_LINK, "link", link_f, 1, 1 },
	{ OP_MKDIR, "mkdir", mkdir_f, 2, 1 },
	{ OP_MKNOD, "mknod", mknod_f, 2, 1 },
	{ OP_READ, "read", read_f, 1, 0 },
	{ OP_READLINK, "readlink", readlink_f, 1, 0 },
	{ OP_RENAME, "rename", rename_f, 2, 1 },
	{ OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
	{ OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
	{ OP_STAT, "stat", stat_f, 1, 0 },
	{ OP_SYMLINK, "symlink", symlink_f, 2, 1 },
	{ OP_SYNC, "sync", sync_f, 1, 0 },
	{ OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
	{ OP_UNLINK, "unlink", unlink_f, 1, 1 },
	{ OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1 },
	{ OP_WRITE, "write", write_f, 4, 1 },
}, *ops_end;

flist_t	flist[FT_nft] = {
	{ 0, 0, 'd', NULL },
	{ 0, 0, 'f', NULL },
	{ 0, 0, 'l', NULL },
	{ 0, 0, 'c', NULL },
	{ 0, 0, 'r', NULL },
};

int		dcache[NDCACHE];
int		errrange;
int		errtag;
opty_t		*freq_table;
int		freq_table_size;
xfs_fsop_geom_t	geom;
char		*homedir;
int		*ilist;
int		ilistlen;
off64_t		maxfsize;
char		*myprog;
int		namerand;
int		nameseq;
int		nops;
int		nproc = 1;
int		operations = 1;
unsigned int	idmodulo = XFS_IDMODULO_MAX;
int		procid;
int		rtpct;
unsigned long	seed = 0;
ino_t		top_ino;
int		verbose = 0;

void	add_to_flist(int, int, int);
void	append_pathname(pathname_t *, char *);
#ifdef HAVE_LIBATTR
int	attr_list_path(pathname_t *, char *, const int, int);
#else
int	attr_list_path(pathname_t *, char *, const int, int, attrlist_cursor_t *);
#endif
int	attr_remove_path(pathname_t *, const char *, int);
int	attr_set_path(pathname_t *, const char *, const char *, const int, int);
void	check_cwd(void);
int	creat_path(pathname_t *, mode_t);
void	dcache_enter(int, int);
void	dcache_init(void);
fent_t	*dcache_lookup(int);
void	dcache_purge(int);
void	del_from_flist(int, int);
int	dirid_to_name(char *, int);
void	doproc(void);
int	fent_to_name(pathname_t *, flist_t *, fent_t *);
void	fix_parent(int, int);
void	free_pathname(pathname_t *);
int	generate_fname(fent_t *, int, pathname_t *, int *, int *);
int	get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
void	init_pathname(pathname_t *);
int	lchown_path(pathname_t *, uid_t, gid_t);
int	link_path(pathname_t *, pathname_t *);
int	lstat64_path(pathname_t *, struct stat64 *);
void	make_freq_table(void);
int	mkdir_path(pathname_t *, mode_t);
int	mknod_path(pathname_t *, mode_t, dev_t);
void	namerandpad(int, char *, int);
int	open_path(pathname_t *, int);
DIR	*opendir_path(pathname_t *);
void	process_freq(char *);
int	readlink_path(pathname_t *, char *, size_t);
int	rename_path(pathname_t *, pathname_t *);
int	rmdir_path(pathname_t *);
void	separate_pathname(pathname_t *, char *, pathname_t *);
void	show_ops(int, char *);
int	stat64_path(pathname_t *, struct stat64 *);
int	symlink_path(const char *, pathname_t *);
int	truncate64_path(pathname_t *, off64_t);
int	unlink_path(pathname_t *);
void	usage(void);
void	write_freq(void);
void	zero_freq(void);

int main(int argc, char **argv)
{
	char		buf[10];
	int		c;
	char		*dirname = NULL;
	int		fd;
	int		i;
	int		j;
	char		*p;
	int		stat;
	struct timeval	t;
	ptrdiff_t	srval;
	int             nousage = 0;
	xfs_error_injection_t	        err_inj;

	errrange = errtag = 0;
	umask(0);
	nops = sizeof(ops) / sizeof(ops[0]);
	ops_end = &ops[nops];
	myprog = argv[0];
	while ((c = getopt(argc, argv, "d:e:f:i:m:n:p:rs:vwzHS")) != -1) {
		switch (c) {
		case 'd':
			dirname = optarg;
			break;
		case 'e':
			sscanf(optarg, "%d", &errtag);
			if (errtag < 0) {
				errtag = -errtag;
				errrange = 1;
			} else if (errtag == 0)
				errtag = -1;
			if (errtag >= XFS_ERRTAG_MAX) {
				fprintf(stderr,
					"error tag %d too large (max %d)\n",
					errtag, XFS_ERRTAG_MAX - 1);
				exit(1);
			}
			break;
		case 'f':
			process_freq(optarg);
			break;
		case 'i':
			ilist = realloc(ilist, ++ilistlen * sizeof(*ilist));
			ilist[ilistlen - 1] = strtol(optarg, &p, 16);
			break;
		case 'm':
			idmodulo = strtoul(optarg, NULL, 0);
			if (idmodulo > XFS_IDMODULO_MAX) {
				fprintf(stderr,
					"chown modulo %d too big (max %d)\n",
					idmodulo, XFS_IDMODULO_MAX);
				exit(1);
			}
			break;
		case 'n':
			operations = atoi(optarg);
			break;
		case 'p':
			nproc = atoi(optarg);
			break;
		case 'r':
			namerand = 1;
			break;
		case 's':
			seed = strtoul(optarg, NULL, 0);
			break;
		case 'v':
			verbose = 1;
			break;
		case 'w':
			write_freq();
			break;
		case 'z':
			zero_freq();
			break;
		case 'S':
			show_ops(0, NULL);
			printf("\n");
                        nousage=1;
			break;
		case '?':
			fprintf(stderr, "%s - invalid parameters\n",
				myprog);
			/* fall through */
		case 'H':
			usage();
			exit(1);
		}
	}
        
        if (!dirname) {
            /* no directory specified */
            if (!nousage) usage();
            exit(1);
        }
        
	(void)mkdir(dirname, 0777);
	if (chdir(dirname) < 0) {
		perror(dirname);
		exit(1);
	}
	sprintf(buf, "fss%x", (unsigned int)getpid());
	fd = creat(buf, 0666);
	if (lseek64(fd, (off64_t)(MAXFSIZE32 + 1ULL), SEEK_SET) < 0)
		maxfsize = (off64_t)MAXFSIZE32;
	else
		maxfsize = (off64_t)MAXFSIZE;
	make_freq_table();
	dcache_init();
	setlinebuf(stdout);
	if (!seed) {
		gettimeofday(&t, (void *)NULL);
		seed = (int)t.tv_sec ^ (int)t.tv_usec;
		printf("seed = %ld\n", seed);
	}
	i = xfsctl(buf, fd, XFS_IOC_FSGEOMETRY, &geom);
	if (i >= 0 && geom.rtblocks)
		rtpct = MIN(MAX(geom.rtblocks * 100 /
				(geom.rtblocks + geom.datablocks), 1), 99);
	else
		rtpct = 0;
	if (errtag != 0) {
		if (errrange == 0) {
			if (errtag <= 0) {
				srandom(seed);
				j = random() % 100;

				for (i = 0; i < j; i++)
					(void) random();

				errtag = (random() % (XFS_ERRTAG_MAX-1)) + 1;
			}
		} else {
			srandom(seed);
			j = random() % 100;

			for (i = 0; i < j; i++)
				(void) random();

			errtag += (random() % (XFS_ERRTAG_MAX - errtag));
		}
		printf("Injecting failure on tag #%d\n", errtag);
		err_inj.errtag = errtag;
		err_inj.fd = fd;
		srval = xfsctl(buf, fd, XFS_IOC_ERROR_INJECTION, &err_inj);
		if (srval < -1) {
			perror("fsstress - XFS_SYSSGI error injection call");
			close(fd);
			unlink(buf);
			exit(1);
		}
	} else
		close(fd);
	for (i = 0; i < nproc; i++) {
		if (fork() == 0) {
			procid = i;
			doproc();
			return 0;
		}
	}
	while (wait(&stat) > 0)
		continue;
	if (errtag != 0) {
		err_inj.errtag = 0;
		err_inj.fd = fd;
		srval = xfsctl(buf, fd, XFS_IOC_ERROR_CLEARALL, &err_inj);
		if (srval != 0) {
			fprintf(stderr, "Bad ej clear on %s fd=%d (%d).\n",
				buf, fd, errno);
			perror("xfsctl(XFS_IOC_ERROR_CLEARALL)");
			close(fd);
			exit(1);
		}
		close(fd);
	}

	unlink(buf);
	return 0;
}

void
add_to_flist(int ft, int id, int parent)
{
	fent_t	*fep;
	flist_t	*ftp;

	ftp = &flist[ft];
	if (ftp->nfiles == ftp->nslots) {
		ftp->nslots += FLIST_SLOT_INCR;
		ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t));
	}
	fep = &ftp->fents[ftp->nfiles++];
	fep->id = id;
	fep->parent = parent;
}

void
append_pathname(pathname_t *name, char *str)
{
	int	len;

	len = strlen(str);
#ifdef DEBUG
	/* attempting to append to a dir a zero length path */
	if (len && *str == '/' && name->len == 0) {
		fprintf(stderr, "fsstress: append_pathname failure\n");
		chdir(homedir);
		abort();
		/* NOTREACHED */
	}
#endif
	name->path = realloc(name->path, name->len + 1 + len);
	strcpy(&name->path[name->len], str);
	name->len += len;
}

int
attr_list_path(pathname_t *name,
	       char *buffer,
	       const int buffersize,
	       int flags
#ifndef HAVE_LIBATTR
	       , attrlist_cursor_t *cursor
#endif
	       )
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

#ifdef ATTR_DONTFOLLOW
	if (flags != ATTR_DONTFOLLOW) {
		errno = EINVAL;
		return -1;
	}
#endif

#ifdef HAVE_LIBATTR
	rval = llistxattr(name->path, buffer, buffersize);
#else
	rval = attr_list(name->path, buffer, buffersize, flags, cursor);
#endif
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
#ifdef HAVE_LIBATTR
		rval = attr_list_path(&newname, buffer, buffersize, flags);
#else
		rval = attr_list_path(&newname, buffer, buffersize, flags, cursor);
#endif
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

int
attr_remove_path(pathname_t *name, const char *attrname, int flags)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = attr_remove(name->path, attrname, flags);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = attr_remove_path(&newname, attrname, flags);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

int
attr_set_path(pathname_t *name, const char *attrname, const char *attrvalue,
	      const int valuelength, int flags)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = attr_set(name->path, attrname, attrvalue, valuelength, flags);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = attr_set_path(&newname, attrname, attrvalue, valuelength,
			flags);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

void
check_cwd(void)
{
#ifdef DEBUG
	struct stat64	statbuf;

	if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino)
		return;
	chdir(homedir);
	fprintf(stderr, "fsstress: check_cwd failure\n");
	abort();
	/* NOTREACHED */
#endif
}

int
creat_path(pathname_t *name, mode_t mode)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = creat(name->path, mode);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = creat_path(&newname, mode);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

void
dcache_enter(int dirid, int slot)
{
	dcache[dirid % NDCACHE] = slot;
}

void
dcache_init(void)
{
	int	i;

	for (i = 0; i < NDCACHE; i++)
		dcache[i] = -1;
}

fent_t *
dcache_lookup(int dirid)
{
	fent_t	*fep;
	int	i;

	i = dcache[dirid % NDCACHE];
	if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
		return fep;
	return NULL;
}

void
dcache_purge(int dirid)
{
	int	*dcp;

	dcp = &dcache[dirid % NDCACHE];
	if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
		*dcp = -1;
}

/*
 * Delete the item from the list by
 * moving last entry over the deleted one;
 * unless deleted entry is the last one.
 * Input: which file list array and which slot in array
 */
void
del_from_flist(int ft, int slot)
{
	flist_t	*ftp;

	ftp = &flist[ft];
	if (ft == FT_DIR)
		dcache_purge(ftp->fents[slot].id);
	if (slot != ftp->nfiles - 1) {
		if (ft == FT_DIR)
			dcache_purge(ftp->fents[ftp->nfiles - 1].id);
		ftp->fents[slot] = ftp->fents[--ftp->nfiles];
	} else
		ftp->nfiles--;
}

fent_t *
dirid_to_fent(int dirid)
{
	fent_t	*efep;
	fent_t	*fep;
	flist_t	*flp;

	if ((fep = dcache_lookup(dirid)))
		return fep;
	flp = &flist[FT_DIR];
	for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
		if (fep->id == dirid) {
			dcache_enter(dirid, fep - flp->fents);
			return fep;
		}
	}
	return NULL;
}

void
doproc(void)
{
	struct stat64	statbuf;
	char		buf[10];
	int		opno;
	int		rval;
	opdesc_t	*p;

	sprintf(buf, "p%x", procid);
	(void)mkdir(buf, 0777);
	if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) {
		perror(buf);
		_exit(1);
	}
	top_ino = statbuf.st_ino;
	homedir = getcwd(NULL, -1);
	seed += procid;
	srandom(seed);
	if (namerand)
		namerand = random();
	for (opno = 0; opno < operations; opno++) {
		p = &ops[freq_table[random() % freq_table_size]];
		p->func(opno, random());
		/*
		 * test for forced shutdown by stat'ing the test
		 * directory.  If this stat returns EIO, assume
		 * the forced shutdown happened.
		 */
		if (errtag != 0 && opno % 100 == 0)  {
			rval = stat64(".", &statbuf);
			if (rval == EIO)  {
				fprintf(stderr, "Detected EIO\n");
				return;
			}
		}
	}
}

/*
 * build up a pathname going thru the file entry and all
 * its parent entries
 * Return 0 on error, 1 on success;
 */
int
fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
{
	char	buf[MAXNAMELEN];
	int	i;
	fent_t	*pfep;
	int	e;

	if (fep == NULL)
		return 0;

	/* build up parent directory name */
	if (fep->parent != -1) {
		pfep = dirid_to_fent(fep->parent);
#ifdef DEBUG
		if (pfep == NULL) {
			fprintf(stderr, "%d: fent-id = %d: can't find parent id: %d\n",
				procid, fep->id, fep->parent);
		} 
#endif
		if (pfep == NULL)
			return 0;
		e = fent_to_name(name, &flist[FT_DIR], pfep);
		if (!e)
			return 0;
		append_pathname(name, "/");
	}

	i = sprintf(buf, "%c%x", flp->tag, fep->id);
	namerandpad(fep->id, buf, i);
	append_pathname(name, buf);
	return 1;
}

void
fix_parent(int oldid, int newid)
{
	fent_t	*fep;
	flist_t	*flp;
	int	i;
	int	j;

	for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
		for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
			if (fep->parent == oldid)
				fep->parent = newid;
		}
	}
}

void
free_pathname(pathname_t *name)
{
	if (name->path) {
		free(name->path);
		name->path = NULL;
		name->len = 0;
	}
}

/*
 * Generate a filename of type ft.
 * If we have a fep which should be a directory then use it
 * as the parent path for this new filename i.e. prepend with it.
 */
int
generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
{
	char	buf[MAXNAMELEN];
	flist_t	*flp;
	int	id;
	int	j;
	int	len;
	int	e;

	/* create name */
	flp = &flist[ft];
	len = sprintf(buf, "%c%x", flp->tag, id = nameseq++);
	namerandpad(id, buf, len);

	/* prepend fep parent dir-name to it */
	if (fep) {
		e = fent_to_name(name, &flist[FT_DIR], fep);
		if (!e)
			return 0;
		append_pathname(name, "/");
	}
	append_pathname(name, buf);

	*idp = id;
	*v = verbose;
	for (j = 0; !*v && j < ilistlen; j++) {
		if (ilist[j] == id) {
			*v = 1;
			break;
		}
	}
	return 1;
}

/*
 * Get file 
 * Input: "which" to choose the file-types eg. non-directory
 * Input: "r" to choose which file
 * Output: file-list, file-entry, name for the chosen file.
 * Output: verbose if chosen file is on the ilist.
 */
int
get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
	  int *v)
{
	int	totalsum = 0; /* total number of matching files */
	int	partialsum = 0; /* partial sum of matching files */
	fent_t	*fep;
	flist_t	*flp;
	int	i;
	int	j;
	int	x;
	int	e = 1; /* success */

	/*
	 * go thru flist and add up number of files for each
	 * category that matches with <which>.
	 */
	for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
		if (which & (1 << i))
			totalsum += flp->nfiles;
	}
	if (totalsum == 0) {
		if (flpp)
			*flpp = NULL;
		if (fepp)
			*fepp = NULL;
		*v = verbose;
		return 0;
	}

	/*
	 * Now we have possible matches between 0..totalsum-1.
	 * And we use r to help us choose which one we want,
	 * which when bounded by totalsum becomes x.
	 */ 
	x = (int)(r % totalsum);
	for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
		if (which & (1 << i)) {
			if (x < partialsum + flp->nfiles) {

				/* found the matching file entry */
				fep = &flp->fents[x - partialsum];

				/* fill-in what we were asked for */
				if (name) {
					e = fent_to_name(name, flp, fep);
#ifdef DEBUG
					if (!e) {
						fprintf(stderr, "%d: failed to get path for entry:"
								" id=%d,parent=%d\n", 	
							procid, fep->id, fep->parent);
					}
#endif
				}
				if (flpp)
					*flpp = flp;
				if (fepp)
					*fepp = fep;

				/* turn on verbose if its an ilisted file */
				*v = verbose;
				for (j = 0; !*v && j < ilistlen; j++) {
					if (ilist[j] == fep->id) {
						*v = 1;
						break;
					}
				}
				return e;
			}
			partialsum += flp->nfiles;
		}
	}
#ifdef DEBUG
	fprintf(stderr, "fsstress: get_fname failure\n");
	abort();
#endif
        return 0;
}

void
init_pathname(pathname_t *name)
{
	name->len = 0;
	name->path = NULL;
}

int
lchown_path(pathname_t *name, uid_t owner, gid_t group)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = lchown(name->path, owner, group);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = lchown_path(&newname, owner, group);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

int
link_path(pathname_t *name1, pathname_t *name2)
{
	char		buf1[MAXNAMELEN];
	char		buf2[MAXNAMELEN];
	int		down1;
	pathname_t	newname1;
	pathname_t	newname2;
	int		rval;

	rval = link(name1->path, name2->path);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name1, buf1, &newname1);
	separate_pathname(name2, buf2, &newname2);
	if (strcmp(buf1, buf2) == 0) {
		if (chdir(buf1) == 0) {
			rval = link_path(&newname1, &newname2);
			chdir("..");
		}
	} else {
		if (strcmp(buf1, "..") == 0)
			down1 = 0;
		else if (strcmp(buf2, "..") == 0)
			down1 = 1;
		else if (strlen(buf1) == 0)
			down1 = 0;
		else if (strlen(buf2) == 0)
			down1 = 1;
		else
			down1 = MAX(newname1.len, 3 + name2->len) <=
				MAX(3 + name1->len, newname2.len);
		if (down1) {
			free_pathname(&newname2);
			append_pathname(&newname2, "../");
			append_pathname(&newname2, name2->path);
			if (chdir(buf1) == 0) {
				rval = link_path(&newname1, &newname2);
				chdir("..");
			}
		} else {
			free_pathname(&newname1);
			append_pathname(&newname1, "../");
			append_pathname(&newname1, name1->path);
			if (chdir(buf2) == 0) {
				rval = link_path(&newname1, &newname2);
				chdir("..");
			}
		}
	}
	free_pathname(&newname1);
	free_pathname(&newname2);
	return rval;
}

int
lstat64_path(pathname_t *name, struct stat64 *sbuf)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = lstat64(name->path, sbuf);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = lstat64_path(&newname, sbuf);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

void
make_freq_table(void)
{
	int		f;
	int		i;
	opdesc_t	*p;

	for (p = ops, f = 0; p < ops_end; p++)
		f += p->freq;
	freq_table = malloc(f * sizeof(*freq_table));
	freq_table_size = f;
	for (p = ops, i = 0; p < ops_end; p++) {
		for (f = 0; f < p->freq; f++, i++)
			freq_table[i] = p->op;
	}
}

int
mkdir_path(pathname_t *name, mode_t mode)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = mkdir(name->path, mode);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = mkdir_path(&newname, mode);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

int
mknod_path(pathname_t *name, mode_t mode, dev_t dev)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = mknod(name->path, mode, dev);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = mknod_path(&newname, mode, dev);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

void
namerandpad(int id, char *buf, int i)
{
	int		bucket;
	static int	buckets[] =
				{ 2, 4, 8, 16, 32, 64, 128, MAXNAMELEN - 1 };
	int		padlen;
	int		padmod;

	if (namerand == 0)
		return;
	bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0]));
	padmod = buckets[bucket] + 1 - i;
	if (padmod <= 0)
		return;
	padlen = (id ^ namerand) % padmod;
	if (padlen) {
		memset(&buf[i], 'X', padlen);
		buf[i + padlen] = '\0';
	}
}

int
open_path(pathname_t *name, int oflag)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = open(name->path, oflag);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = open_path(&newname, oflag);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

DIR *
opendir_path(pathname_t *name)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	DIR		*rval;

	rval = opendir(name->path);
	if (rval || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = opendir_path(&newname);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

void
process_freq(char *arg)
{
	opdesc_t	*p;
	char		*s;

	s = strchr(arg, '=');
	if (s == NULL) {
		fprintf(stderr, "bad argument '%s'\n", arg);
		exit(1);
	}
	*s++ = '\0';
	for (p = ops; p < ops_end; p++) {
		if (strcmp(arg, p->name) == 0) {
			p->freq = atoi(s);
			return;
		}
	}
	fprintf(stderr, "can't find op type %s for -f\n", arg);
	exit(1);
}

int
readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = readlink(name->path, lbuf, lbufsiz);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = readlink_path(&newname, lbuf, lbufsiz);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

int
rename_path(pathname_t *name1, pathname_t *name2)
{
	char		buf1[MAXNAMELEN];
	char		buf2[MAXNAMELEN];
	int		down1;
	pathname_t	newname1;
	pathname_t	newname2;
	int		rval;

	rval = rename(name1->path, name2->path);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name1, buf1, &newname1);
	separate_pathname(name2, buf2, &newname2);
	if (strcmp(buf1, buf2) == 0) {
		if (chdir(buf1) == 0) {
			rval = rename_path(&newname1, &newname2);
			chdir("..");
		}
	} else {
		if (strcmp(buf1, "..") == 0)
			down1 = 0;
		else if (strcmp(buf2, "..") == 0)
			down1 = 1;
		else if (strlen(buf1) == 0)
			down1 = 0;
		else if (strlen(buf2) == 0)
			down1 = 1;
		else
			down1 = MAX(newname1.len, 3 + name2->len) <=
				MAX(3 + name1->len, newname2.len);
		if (down1) {
			free_pathname(&newname2);
			append_pathname(&newname2, "../");
			append_pathname(&newname2, name2->path);
			if (chdir(buf1) == 0) {
				rval = rename_path(&newname1, &newname2);
				chdir("..");
			}
		} else {
			free_pathname(&newname1);
			append_pathname(&newname1, "../");
			append_pathname(&newname1, name1->path);
			if (chdir(buf2) == 0) {
				rval = rename_path(&newname1, &newname2);
				chdir("..");
			}
		}
	}
	free_pathname(&newname1);
	free_pathname(&newname2);
	return rval;
}

int
rmdir_path(pathname_t *name)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = rmdir(name->path);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = rmdir_path(&newname);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

void
separate_pathname(pathname_t *name, char *buf, pathname_t *newname)
{
	char	*slash;

	init_pathname(newname);
	slash = strchr(name->path, '/');
	if (slash == NULL) {
		buf[0] = '\0';
		return;
	}
	*slash = '\0';
	strcpy(buf, name->path);
	*slash = '/';
	append_pathname(newname, slash + 1);
}

#define WIDTH 80

void
show_ops(int flag, char *lead_str)
{
	opdesc_t	*p;

        if (flag<0) {
                /* print in list form */
                int             x = WIDTH;
                
	        for (p = ops; p < ops_end; p++) {
			if (lead_str != NULL && x+strlen(p->name)>=WIDTH-5)
				x=printf("%s%s", (p==ops)?"":"\n", lead_str);
                        x+=printf("%s ", p->name);
                }
                printf("\n");
        } else {
	        int		f;
	        for (f = 0, p = ops; p < ops_end; p++)
		        f += p->freq;

	        if (f == 0)
		        flag = 1;

	        for (p = ops; p < ops_end; p++) {
		        if (flag != 0 || p->freq > 0) {
			        if (lead_str != NULL)
				        printf("%s", lead_str);
			        printf("%20s %d/%d %s\n",
			        p->name, p->freq, f,
			        (p->iswrite == 0) ? " " : "write op");
		        }
                }
	}
}

int
stat64_path(pathname_t *name, struct stat64 *sbuf)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = stat64(name->path, sbuf);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = stat64_path(&newname, sbuf);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

int
symlink_path(const char *name1, pathname_t *name)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;
        
        if (!strcmp(name1, name->path)) {
            printf("yikes! %s %s\n", name1, name->path);
            return 0;
        }

	rval = symlink(name1, name->path);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = symlink_path(name1, &newname);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

int
truncate64_path(pathname_t *name, off64_t length)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = truncate64(name->path, length);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = truncate64_path(&newname, length);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

int
unlink_path(pathname_t *name)
{
	char		buf[MAXNAMELEN];
	pathname_t	newname;
	int		rval;

	rval = unlink(name->path);
	if (rval >= 0 || errno != ENAMETOOLONG)
		return rval;
	separate_pathname(name, buf, &newname);
	if (chdir(buf) == 0) {
		rval = unlink_path(&newname);
		chdir("..");
	}
	free_pathname(&newname);
	return rval;
}

void
usage(void)
{
	printf("Usage: %s -H   or\n", myprog);
	printf("       %s [-d dir][-e errtg][-f op_name=freq][-n nops]\n",
		myprog);
	printf("          [-p nproc][-r len][-s seed][-v][-w][-z][-S]\n");
	printf("where\n");
	printf("   -d dir           specifies the base directory for operations\n");
	printf("   -e errtg         specifies error injection stuff\n");
	printf("   -f op_name=freq  changes the frequency of option name to freq\n");
	printf("                    the valid operation names are:\n");
	printf("   -i filenum       get verbose output for this nth file object\n");
	show_ops(-1, "                        ");
	printf("   -m modulo        uid/gid modulo for chown/chgrp (default 32)\n");
	printf("   -n nops          specifies the no. of operations per process (default 1)\n");
	printf("   -p nproc         specifies the no. of processes (default 1)\n");
	printf("   -r               specifies random name padding\n");
	printf("   -s seed          specifies the seed for the random generator (default random)\n");
	printf("   -v               specifies verbose mode\n");
	printf("   -w               zeros frequencies of non-write operations\n");
	printf("   -z               zeros frequencies of all operations\n");
	printf("   -S               prints the table of operations (omitting zero frequency)\n");
	printf("   -H               prints usage and exits\n");
}

void
write_freq(void)
{
	opdesc_t	*p;

	for (p = ops; p < ops_end; p++) {
		if (!p->iswrite)
			p->freq = 0;
	}
}

void
zero_freq(void)
{
	opdesc_t	*p;

	for (p = ops; p < ops_end; p++)
		p->freq = 0;
}

void
allocsp_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	int		fd;
	struct xfs_flock64	fl;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: allocsp - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_RDWR);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: allocsp - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	if (fstat64(fd, &stb) < 0) {
		if (v)
			printf("%d/%d: allocsp - fstat64 %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
	off %= maxfsize;
	fl.l_whence = SEEK_SET;
	fl.l_start = off;
	fl.l_len = 0;
	e = xfsctl(f.path, fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
	if (v)
		printf("%d/%d: xfsctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n",
			procid, opno, f.path, (long long)off, e);
	free_pathname(&f);
	close(fd);
}

void
attr_remove_f(int opno, long r)
{
	attrlist_ent_t		*aep;
	attrlist_t		*alist;
	char			*aname;
	char			buf[4096];
#ifndef HAVE_LIBATTR
	attrlist_cursor_t	cursor;
#endif
	int			e;
	int			ent;
	pathname_t		f;
	int			total;
	int			v;
	int			which;

	init_pathname(&f);
	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
		append_pathname(&f, ".");
	total = 0;
#ifndef HAVE_LIBATTR
	bzero(&cursor, sizeof(cursor));
#endif
	do {
		bzero(buf, sizeof(buf));
#ifdef HAVE_LIBATTR
		e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW);
#else
		e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, &cursor);
#endif
		check_cwd();
		if (e)
			break;
		alist = (attrlist_t *)buf;
		total += alist->al_count;
	} while (alist->al_more);
	if (total == 0) {
		if (v)
			printf("%d/%d: attr_remove - no attrs for %s\n",
				procid, opno, f.path);
		free_pathname(&f);
		return;
	}
	which = (int)(random() % total);
#ifndef HAVE_LIBATTR
	bzero(&cursor, sizeof(cursor));
#endif
	ent = 0;
	aname = NULL;
	do {
		bzero(buf, sizeof(buf));
#ifdef HAVE_LIBATTR
		e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW);
#else
		e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, &cursor);
#endif
		check_cwd();
		if (e)
			break;
		alist = (attrlist_t *)buf;
		if (which < ent + alist->al_count) {
			aep = (attrlist_ent_t *)
				&buf[alist->al_offset[which - ent]];
			aname = aep->a_name;
			break;
		}
		ent += alist->al_count;
	} while (alist->al_more);
	if (aname == NULL) {
		if (v)
			printf(
			"%d/%d: attr_remove - name %d not found at %s\n",	
				procid, opno, which, f.path);
		free_pathname(&f);
		return;
	}
	e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0;
	check_cwd();
	if (v)
		printf("%d/%d: attr_remove %s %s %d\n",
			procid, opno, f.path, aname, e);
	free_pathname(&f);
}

void
attr_set_f(int opno, long r)
{
	char		aname[10];
	char		*aval;
	int		e;
	pathname_t	f;
	int		len;
	static int	lengths[] = { 10, 100, 1000, 10000 };
	int		li;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
		append_pathname(&f, ".");
	sprintf(aname, "a%x", nameseq++);
	li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0])));
	len = (int)(random() % lengths[li]);
	if (len == 0)
		len = 1;
	aval = malloc(len);
	memset(aval, nameseq & 0xff, len);
	e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ?
		errno : 0;
	check_cwd();
	free(aval);
	if (v)
		printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path,
			aname, e);
	free_pathname(&f);
}

void
bulkstat_f(int opno, long r)
{
	int		count;
	int		fd;
	__uint64_t	last;
	int		nent;
	xfs_bstat_t	*t;
	__int64_t	total;
        xfs_fsop_bulkreq_t bsr;

	last = 0;
	nent = (r % 999) + 2;
	t = malloc(nent * sizeof(*t));
	fd = open(".", O_RDONLY);
	total = 0;
    
        bsr.lastip=&last;
        bsr.icount=nent;
        bsr.ubuffer=t;
        bsr.ocount=&count;
            
	while (xfsctl(".", fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
		total += count;
	free(t);
	if (verbose)
		printf("%d/%d: bulkstat nent %d total %lld\n",
			procid, opno, nent, (long long)total);
	close(fd);
}

void
bulkstat1_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	int		fd;
	int		good;
	__uint64_t	ino;
	struct stat64	s;
	xfs_bstat_t	t;
	int		v;
        xfs_fsop_bulkreq_t bsr;
        

	good = random() & 1;
	if (good) {
               /* use an inode we know exists */
		init_pathname(&f);
		if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
			append_pathname(&f, ".");
		ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino;
		check_cwd();
		free_pathname(&f);
	} else {
                /* 
                 * pick a random inode 
                 *
                 * note this can generate kernel warning messages
                 * since bulkstat_one will read the disk block that
                 * would contain a given inode even if that disk
                 * block doesn't contain inodes.
                 *
                 * this is detected later, but not until after the
                 * warning is displayed.
                 *
                 * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0"
                 *
                 */
		ino = (ino64_t)r;
		v = verbose;
	}
	fd = open(".", O_RDONLY);
        
        bsr.lastip=&ino;
        bsr.icount=1;
        bsr.ubuffer=&t;
        bsr.ocount=NULL;
        
	e = xfsctl(".", fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
	if (v)
		printf("%d/%d: bulkstat1 %s ino %lld %d\n", 
                    procid, opno, good?"real":"random", (long long)ino, e);
	close(fd);
}

void
chown_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	int		nbits;
	uid_t		u;
	gid_t		g;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
		append_pathname(&f, ".");
	u = (uid_t)random();
	g = (gid_t)random();
	nbits = (int)(random() % idmodulo);
	u &= (1 << nbits) - 1;
	g &= (1 << nbits) - 1;
	e = lchown_path(&f, u, g) < 0 ? errno : 0;
	check_cwd();
	if (v)
		printf("%d/%d: chown %s %d/%d %d\n", procid, opno, f.path, (int)u, (int)g, e);
	free_pathname(&f);
}

void
chproj_f(int opno, long r)
{
#if !defined(__sgi__)
	struct fsxattr	fsx;
#endif
	int		fd;
	int		e;
	pathname_t	f;
	int		nbits;
	uint		p;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
		append_pathname(&f, ".");
	fd = open_path(&f, O_RDWR);
	e = fd < 0 ? errno : 0;
	check_cwd();

	p = (uid_t)random();
	e = MIN(idmodulo, XFS_PROJIDMODULO_MAX);
	nbits = (int)(random() % e);
	p &= (1 << nbits) - 1;
#if defined(__sgi__)
	e = fchproj(fd, p);
#else
	if ((e = xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &fsx)) == 0) {
		fsx.fsx_projid = p;
		e = xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &fsx);
	}
#endif
	if (v)
		printf("%d/%d: chproj %s %u %d\n", procid, opno, f.path, p, e);
	free_pathname(&f);
	close(fd);
}

void
creat_f(int opno, long r)
{
	struct fsxattr	a;
	int		e;
	int		e1;
	int		extsize;
	pathname_t	f;
	int		fd;
	fent_t		*fep;
	int		id;
	int		parid;
	int		type;
	int		v;
	int		v1;

	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
		parid = -1;
	else
		parid = fep->id;
	init_pathname(&f);
	type = rtpct ? ((random() % 100) > rtpct ? FT_REG : FT_RTF) : FT_REG;
	if (type == FT_RTF)
		extsize = (random() % 10) + 1;
	else
		extsize = 0;
	e = generate_fname(fep, type, &f, &id, &v);
	v |= v1;
	if (!e) {
		if (v) {
			(void)fent_to_name(&f, &flist[FT_DIR], fep);
			printf("%d/%d: creat - no filename from %s\n",
				procid, opno, f.path);
		}
		free_pathname(&f);
		return;
	}
	fd = creat_path(&f, 0666);
	e = fd < 0 ? errno : 0;
	e1 = 0;
	check_cwd();
	if (fd >= 0) {
		if (extsize &&
		    xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
			a.fsx_xflags |= XFS_XFLAG_REALTIME;
			a.fsx_extsize =
				geom.rtextsize * geom.blocksize * extsize;
			if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
				e1 = errno;
		}
		add_to_flist(type, id, parid);
		close(fd);
	}
	if (v) {
		printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
			extsize ? a.fsx_extsize : 0, e, e1);
		printf("%d/%d: creat add id=%d,parent=%d\n", procid, opno, id, parid);
	}
	free_pathname(&f);
}

void
dread_f(int opno, long r)
{
	__int64_t	align;
	char		*buf;
	struct dioattr	diob;
	int		e;
	pathname_t	f;
	int		fd;
	size_t		len;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: dread - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_RDONLY|O_DIRECT);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: dread - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	if (fstat64(fd, &stb) < 0) {
		if (v)
			printf("%d/%d: dread - fstat64 %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	if (stb.st_size == 0) {
		if (v)
			printf("%d/%d: dread - %s zero size\n", procid, opno,
				f.path);
		free_pathname(&f);
		close(fd);
		return;
	}
	if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
		if (v)
			printf(
			"%d/%d: dread - xfsctl(XFS_IOC_DIOINFO) %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	align = (__int64_t)diob.d_miniosz;
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % stb.st_size);
	off -= (off % align);
	lseek64(fd, off, SEEK_SET);
	len = (random() % FILELEN_MAX) + 1;
	len -= (len % align);
	if (len <= 0)
		len = align;
	else if (len > diob.d_maxiosz) 
		len = diob.d_maxiosz;
	buf = memalign(diob.d_mem, len);
	e = read(fd, buf, len) < 0 ? errno : 0;
	free(buf);
	if (v)
		printf("%d/%d: dread %s [%lld,%d] %d\n",
			procid, opno, f.path, (long long)off, (int)len, e);
	free_pathname(&f);
	close(fd);
}

void
dwrite_f(int opno, long r)
{
	__int64_t	align;
	char		*buf;
	struct dioattr	diob;
	int		e;
	pathname_t	f;
	int		fd;
	size_t		len;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: dwrite - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_WRONLY|O_DIRECT);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: dwrite - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	if (fstat64(fd, &stb) < 0) {
		if (v)
			printf("%d/%d: dwrite - fstat64 %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
		if (v)
			printf("%d/%d: dwrite - xfsctl(XFS_IOC_DIOINFO)"
				" %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	align = (__int64_t)diob.d_miniosz;
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
	off -= (off % align);
	lseek64(fd, off, SEEK_SET);
	len = (random() % FILELEN_MAX) + 1;
	len -= (len % align);
	if (len <= 0)
		len = align;
	else if (len > diob.d_maxiosz) 
		len = diob.d_maxiosz;
	buf = memalign(diob.d_mem, len);
	off %= maxfsize;
	lseek64(fd, off, SEEK_SET);
	memset(buf, nameseq & 0xff, len);
	e = write(fd, buf, len) < 0 ? errno : 0;
	free(buf);
	if (v)
		printf("%d/%d: dwrite %s [%lld,%d] %d\n",
			procid, opno, f.path, (long long)off, (int)len, e);
	free_pathname(&f);
	close(fd);
}

void
fdatasync_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	int		fd;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: fdatasync - no filename\n",
				procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_WRONLY);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: fdatasync - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	e = fdatasync(fd) < 0 ? errno : 0;
	if (v)
		printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e);
	free_pathname(&f);
	close(fd);
}

void
freesp_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	int		fd;
	struct xfs_flock64	fl;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: freesp - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_RDWR);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: freesp - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	if (fstat64(fd, &stb) < 0) {
		if (v)
			printf("%d/%d: freesp - fstat64 %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
	off %= maxfsize;
	fl.l_whence = SEEK_SET;
	fl.l_start = off;
	fl.l_len = 0;
	e = xfsctl(f.path, fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
	if (v)
		printf("%d/%d: xfsctl(XFS_IOC_FREESP64) %s %lld 0 %d\n",
			procid, opno, f.path, (long long)off, e);
	free_pathname(&f);
	close(fd);
}

void
fsync_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	int		fd;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: fsync - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_WRONLY);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: fsync - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	e = fsync(fd) < 0 ? errno : 0;
	if (v)
		printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e);
	free_pathname(&f);
	close(fd);
}

void
getdents_f(int opno, long r)
{
	DIR		*dir;
	pathname_t	f;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
		append_pathname(&f, ".");
	dir = opendir_path(&f);
	check_cwd();
	if (dir == NULL) {
		if (v)
			printf("%d/%d: getdents - can't open %s\n",
				procid, opno, f.path);
		free_pathname(&f);
		return;
	}
	while (readdir64(dir) != NULL)
		continue;
	if (v)
		printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
	free_pathname(&f);
	closedir(dir);
}

void
link_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	fent_t		*fep;
	flist_t		*flp;
	int		id;
	pathname_t	l;
	int		parid;
	int		v;
	int		v1;

	init_pathname(&f);
	if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
		if (v1)
			printf("%d/%d: link - no file\n", procid, opno);
		free_pathname(&f);
		return;
	}
	if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
		parid = -1;
	else
		parid = fep->id;
	v |= v1;
	init_pathname(&l);
	e = generate_fname(fep, flp - flist, &l, &id, &v1);
	v |= v1;
	if (!e) {
		if (v) {
			(void)fent_to_name(&l, &flist[FT_DIR], fep);
			printf("%d/%d: link - no filename from %s\n",
				procid, opno, l.path);
		}
		free_pathname(&l);
		free_pathname(&f);
		return;
	}
	e = link_path(&f, &l) < 0 ? errno : 0;
	check_cwd();
	if (e == 0)
		add_to_flist(flp - flist, id, parid);
	if (v) {
		printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
			e);
		printf("%d/%d: link add id=%d,parent=%d\n", procid, opno, id, parid);
	}
	free_pathname(&l);
	free_pathname(&f);
}

void
mkdir_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	fent_t		*fep;
	int		id;
	int		parid;
	int		v;
	int		v1;

	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
		parid = -1;
	else
		parid = fep->id;
	init_pathname(&f);
	e = generate_fname(fep, FT_DIR, &f, &id, &v1);
	v |= v1;
	if (!e) {
		if (v) {
			(void)fent_to_name(&f, &flist[FT_DIR], fep);
			printf("%d/%d: mkdir - no filename from %s\n",
				procid, opno, f.path);
		}
		free_pathname(&f);
		return;
	}
	e = mkdir_path(&f, 0777) < 0 ? errno : 0;
	check_cwd();
	if (e == 0)
		add_to_flist(FT_DIR, id, parid);
	if (v) {
		printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
		printf("%d/%d: mkdir add id=%d,parent=%d\n", procid, opno, id, parid);
	}
	free_pathname(&f);
}

void
mknod_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	fent_t		*fep;
	int		id;
	int		parid;
	int		v;
	int		v1;

	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
		parid = -1;
	else
		parid = fep->id;
	init_pathname(&f);
	e = generate_fname(fep, FT_DEV, &f, &id, &v1);
	v |= v1;
	if (!e) {
		if (v) {
			(void)fent_to_name(&f, &flist[FT_DIR], fep);
			printf("%d/%d: mknod - no filename from %s\n",
				procid, opno, f.path);
		}
		free_pathname(&f);
		return;
	}
	e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
	check_cwd();
	if (e == 0)
		add_to_flist(FT_DEV, id, parid);
	if (v) {
		printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
		printf("%d/%d: mknod add id=%d,parent=%d\n", procid, opno, id, parid);
	}
	free_pathname(&f);
}

void
read_f(int opno, long r)
{
	char		*buf;
	int		e;
	pathname_t	f;
	int		fd;
	size_t		len;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: read - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_RDONLY);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: read - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	if (fstat64(fd, &stb) < 0) {
		if (v)
			printf("%d/%d: read - fstat64 %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	if (stb.st_size == 0) {
		if (v)
			printf("%d/%d: read - %s zero size\n", procid, opno,
				f.path);
		free_pathname(&f);
		close(fd);
		return;
	}
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % stb.st_size);
	lseek64(fd, off, SEEK_SET);
	len = (random() % FILELEN_MAX) + 1;
	buf = malloc(len);
	e = read(fd, buf, len) < 0 ? errno : 0;
	free(buf);
	if (v)
		printf("%d/%d: read %s [%lld,%d] %d\n",
			procid, opno, f.path, (long long)off, (int)len, e);
	free_pathname(&f);
	close(fd);
}

void
readlink_f(int opno, long r)
{
	char		buf[PATH_MAX];
	int		e;
	pathname_t	f;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: readlink - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
	check_cwd();
	if (v)
		printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e);
	free_pathname(&f);
}

void
rename_f(int opno, long r)
{
	fent_t		*dfep;
	int		e;
	pathname_t	f;
	fent_t		*fep;
	flist_t		*flp;
	int		id;
	pathname_t	newf;
	int		oldid;
	int		parid;
	int		v;
	int		v1;

	/* get an existing path for the source of the rename */
	init_pathname(&f);
	if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
		if (v1)
			printf("%d/%d: rename - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}

	/* get an existing directory for the destination parent directory name */
	if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
		parid = -1;
	else
		parid = dfep->id;
	v |= v1;

	/* generate a new path using an existing parent directory in name */
	init_pathname(&newf);
	e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
	v |= v1;
	if (!e) {
		if (v) {
			(void)fent_to_name(&f, &flist[FT_DIR], dfep);
			printf("%d/%d: rename - no filename from %s\n",
				procid, opno, f.path);
		}
		free_pathname(&newf);
		free_pathname(&f);
		return;
	}
	e = rename_path(&f, &newf) < 0 ? errno : 0;
	check_cwd();
	if (e == 0) {
		if (flp - flist == FT_DIR) {
			oldid = fep->id;
			fix_parent(oldid, id);
		}
		del_from_flist(flp - flist, fep - flp->fents);
		add_to_flist(flp - flist, id, parid);
	}
	if (v) {
		printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
			newf.path, e);
		if (e == 0) {
			printf("%d/%d: rename del entry: id=%d,parent=%d\n",
				procid, opno, fep->id, fep->parent);
			printf("%d/%d: rename add entry: id=%d,parent=%d\n",
				procid, opno, id, parid);
		}
	}
	free_pathname(&newf);
	free_pathname(&f);
}

void
resvsp_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	int		fd;
	struct xfs_flock64	fl;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: resvsp - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_RDWR);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: resvsp - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	if (fstat64(fd, &stb) < 0) {
		if (v)
			printf("%d/%d: resvsp - fstat64 %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
	off %= maxfsize;
	fl.l_whence = SEEK_SET;
	fl.l_start = off;
	fl.l_len = (off64_t)(random() % (1024 * 1024));
	e = xfsctl(f.path, fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
	if (v)
		printf("%d/%d: xfsctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n",
			procid, opno, f.path,
			(long long)off, (long long)fl.l_len, e);
	free_pathname(&f);
	close(fd);
}

void
rmdir_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	fent_t		*fep;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
		if (v)
			printf("%d/%d: rmdir - no directory\n", procid, opno);
		free_pathname(&f);
		return;
	}
	e = rmdir_path(&f) < 0 ? errno : 0;
	check_cwd();
	if (e == 0)
		del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
	if (v) {
		printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e);
		if (e == 0)
			printf("%d/%d: rmdir del entry: id=%d,parent=%d\n",
				procid, opno, fep->id, fep->parent);
	}
	free_pathname(&f);
}

void
stat_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: stat - no entries\n", procid, opno);
		free_pathname(&f);
		return;
	}
	e = lstat64_path(&f, &stb) < 0 ? errno : 0;
	check_cwd();
	if (v)
		printf("%d/%d: stat %s %d\n", procid, opno, f.path, e);
	free_pathname(&f);
}

void
symlink_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	fent_t		*fep;
	int		i;
	int		id;
	int		len;
	int		parid;
	int		v;
	int		v1;
	char		*val;

	if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
		parid = -1;
	else
		parid = fep->id;
	init_pathname(&f);
	e = generate_fname(fep, FT_SYM, &f, &id, &v1);
	v |= v1;
	if (!e) {
		if (v) {
			(void)fent_to_name(&f, &flist[FT_DIR], fep);
			printf("%d/%d: symlink - no filename from %s\n",
				procid, opno, f.path);
		}
		free_pathname(&f);
		return;
	}
	len = (int)(random() % PATH_MAX);
	val = malloc(len + 1);
	if (len)
		memset(val, 'x', len);
	val[len] = '\0';
	for (i = 10; i < len - 1; i += 10)
		val[i] = '/';
	e = symlink_path(val, &f) < 0 ? errno : 0;
	check_cwd();
	if (e == 0)
		add_to_flist(FT_SYM, id, parid);
	free(val);
	if (v) {
		printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
		printf("%d/%d: symlink add id=%d,parent=%d\n", procid, opno, id, parid);
	}
	free_pathname(&f);
}

/* ARGSUSED */
void
sync_f(int opno, long r)
{
	sync();
	if (verbose)
		printf("%d/%d: sync\n", procid, opno);
}

void
truncate_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: truncate - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	e = stat64_path(&f, &stb) < 0 ? errno : 0;
	check_cwd();
	if (e > 0) {
		if (v)
			printf("%d/%d: truncate - stat64 %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
	off %= maxfsize;
	e = truncate64_path(&f, off) < 0 ? errno : 0;
	check_cwd();
	if (v)
		printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path,
			(long long)off, e);
	free_pathname(&f);
}

void
unlink_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	fent_t		*fep;
	flist_t		*flp;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
		if (v)
			printf("%d/%d: unlink - no file\n", procid, opno);
		free_pathname(&f);
		return;
	}
	e = unlink_path(&f) < 0 ? errno : 0;
	check_cwd();
	if (e == 0)
		del_from_flist(flp - flist, fep - flp->fents);
	if (v) {
		printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e);
		if (e == 0)
			printf("%d/%d: unlink del entry: id=%d,parent=%d\n",
				procid, opno, fep->id, fep->parent);
	}
	free_pathname(&f);
}

void
unresvsp_f(int opno, long r)
{
	int		e;
	pathname_t	f;
	int		fd;
	struct xfs_flock64	fl;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: unresvsp - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_RDWR);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: unresvsp - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	if (fstat64(fd, &stb) < 0) {
		if (v)
			printf("%d/%d: unresvsp - fstat64 %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
	off %= maxfsize;
	fl.l_whence = SEEK_SET;
	fl.l_start = off;
	fl.l_len = (off64_t)(random() % (1 << 20));
	e = xfsctl(f.path, fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
	if (v)
		printf("%d/%d: xfsctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n",
			procid, opno, f.path,
			(long long)off, (long long)fl.l_len, e);
	free_pathname(&f);
	close(fd);
}

void
write_f(int opno, long r)
{
	char		*buf;
	int		e;
	pathname_t	f;
	int		fd;
	size_t		len;
	__int64_t	lr;
	off64_t		off;
	struct stat64	stb;
	int		v;

	init_pathname(&f);
	if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
		if (v)
			printf("%d/%d: write - no filename\n", procid, opno);
		free_pathname(&f);
		return;
	}
	fd = open_path(&f, O_WRONLY);
	e = fd < 0 ? errno : 0;
	check_cwd();
	if (fd < 0) {
		if (v)
			printf("%d/%d: write - open %s failed %d\n",
				procid, opno, f.path, e);
		free_pathname(&f);
		return;
	}
	if (fstat64(fd, &stb) < 0) {
		if (v)
			printf("%d/%d: write - fstat64 %s failed %d\n",
				procid, opno, f.path, errno);
		free_pathname(&f);
		close(fd);
		return;
	}
	lr = ((__int64_t)random() << 32) + random();
	off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
	off %= maxfsize;
	lseek64(fd, off, SEEK_SET);
	len = (random() % FILELEN_MAX) + 1;
	buf = malloc(len);
	memset(buf, nameseq & 0xff, len);
	e = write(fd, buf, len) < 0 ? errno : 0;
	free(buf);
	if (v)
		printf("%d/%d: write %s [%lld,%d] %d\n",
			procid, opno, f.path, (long long)off, (int)len, e);
	free_pathname(&f);
	close(fd);
}