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 
43 typedef 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 
83 typedef void (*opfnc_t) (int, long);
84 
85 typedef 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 
94 typedef struct fent {
95 	int id;
96 	int parent;
97 } fent_t;
98 
99 typedef struct flist {
100 	int nfiles;
101 	int nslots;
102 	int tag;
103 	fent_t *fents;
104 } flist_t;
105 
106 typedef 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 
132 void allocsp_f(int, long);
133 void attr_remove_f(int, long);
134 void attr_set_f(int, long);
135 void bulkstat_f(int, long);
136 void bulkstat1_f(int, long);
137 void chown_f(int, long);
138 void creat_f(int, long);
139 void dread_f(int, long);
140 void dwrite_f(int, long);
141 void fdatasync_f(int, long);
142 void freesp_f(int, long);
143 void fsync_f(int, long);
144 void getdents_f(int, long);
145 void link_f(int, long);
146 void mkdir_f(int, long);
147 void mknod_f(int, long);
148 void read_f(int, long);
149 void readlink_f(int, long);
150 void rename_f(int, long);
151 void resvsp_f(int, long);
152 void rmdir_f(int, long);
153 void stat_f(int, long);
154 void symlink_f(int, long);
155 void sync_f(int, long);
156 void truncate_f(int, long);
157 void unlink_f(int, long);
158 void unresvsp_f(int, long);
159 void write_f(int, long);
160 
161 opdesc_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 
200 flist_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 
208 int dcache[NDCACHE];
209 int errrange;
210 int errtag;
211 opty_t *freq_table;
212 int freq_table_size;
213 #ifndef NO_XFS
214 xfs_fsop_geom_t geom;
215 #endif
216 char *homedir;
217 int *ilist;
218 int ilistlen;
219 off64_t maxfsize;
220 char *myprog;
221 int namerand;
222 int nameseq;
223 int nops;
224 int nproc = 1;
225 int operations = 1;
226 int procid;
227 int rtpct;
228 unsigned long seed = 0;
229 ino_t top_ino;
230 int verbose = 0;
231 #ifndef NO_XFS
232 int no_xfs = 0;
233 #else
234 int no_xfs = 1;
235 #endif
236 sig_atomic_t should_stop = 0;
237 
238 void add_to_flist(int, int, int);
239 void append_pathname(pathname_t *, char *);
240 #ifndef NO_XFS
241 int attr_list_path(pathname_t *, char *, const int, int, attrlist_cursor_t *);
242 int attr_remove_path(pathname_t *, const char *, int);
243 int attr_set_path(pathname_t *, const char *, const char *, const int, int);
244 #endif
245 void check_cwd(void);
246 int creat_path(pathname_t *, mode_t);
247 void dcache_enter(int, int);
248 void dcache_init(void);
249 fent_t *dcache_lookup(int);
250 void dcache_purge(int);
251 void del_from_flist(int, int);
252 int dirid_to_name(char *, int);
253 void doproc(void);
254 void fent_to_name(pathname_t *, flist_t *, fent_t *);
255 void fix_parent(int, int);
256 void free_pathname(pathname_t *);
257 int generate_fname(fent_t *, int, pathname_t *, int *, int *);
258 int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
259 void init_pathname(pathname_t *);
260 int lchown_path(pathname_t *, uid_t, gid_t);
261 int link_path(pathname_t *, pathname_t *);
262 int lstat64_path(pathname_t *, struct stat64 *);
263 void make_freq_table(void);
264 int mkdir_path(pathname_t *, mode_t);
265 int mknod_path(pathname_t *, mode_t, dev_t);
266 void namerandpad(int, char *, int);
267 int open_path(pathname_t *, int);
268 DIR *opendir_path(pathname_t *);
269 void process_freq(char *);
270 int readlink_path(pathname_t *, char *, size_t);
271 int rename_path(pathname_t *, pathname_t *);
272 int rmdir_path(pathname_t *);
273 void separate_pathname(pathname_t *, char *, pathname_t *);
274 void show_ops(int, char *);
275 int stat64_path(pathname_t *, struct stat64 *);
276 int symlink_path(const char *, pathname_t *);
277 int truncate64_path(pathname_t *, off64_t);
278 int unlink_path(pathname_t *);
279 void usage(void);
280 void write_freq(void);
281 void zero_freq(void);
282 
sg_handler(int signum)283 void sg_handler(int signum)
284 {
285 	should_stop = 1;
286 }
287 
main(int argc,char ** argv)288 int 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 
add_to_flist(int ft,int id,int parent)557 void 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 
append_pathname(pathname_t * name,char * str)572 void 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
591 int
attr_list_path(pathname_t * name,char * buffer,const int buffersize,int flags,attrlist_cursor_t * cursor)592 attr_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 
attr_remove_path(pathname_t * name,const char * attrname,int flags)612 int 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 
630 int
attr_set_path(pathname_t * name,const char * attrname,const char * attrvalue,const int valuelength,int flags)631 attr_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 
check_cwd(void)652 void 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 
creat_path(pathname_t * name,mode_t mode)666 int 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 
dcache_enter(int dirid,int slot)684 void dcache_enter(int dirid, int slot)
685 {
686 	dcache[dirid % NDCACHE] = slot;
687 }
688 
dcache_init(void)689 void dcache_init(void)
690 {
691 	int i;
692 
693 	for (i = 0; i < NDCACHE; i++)
694 		dcache[i] = -1;
695 }
696 
dcache_lookup(int dirid)697 fent_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 
dcache_purge(int dirid)708 void 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 
del_from_flist(int ft,int slot)717 void 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 
dirid_to_fent(int dirid)732 fent_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 
doproc(void)750 void 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 
fent_to_name(pathname_t * name,flist_t * flp,fent_t * fep)791 void 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 
fix_parent(int oldid,int newid)809 void 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 
free_pathname(pathname_t * name)824 void 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 
generate_fname(fent_t * fep,int ft,pathname_t * name,int * idp,int * v)833 int 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 
860 int
get_fname(int which,long r,pathname_t * name,flist_t ** flpp,fent_t ** fepp,int * v)861 get_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 
init_pathname(pathname_t * name)914 void init_pathname(pathname_t * name)
915 {
916 	name->len = 0;
917 	name->path = NULL;
918 }
919 
lchown_path(pathname_t * name,uid_t owner,gid_t group)920 int 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 
link_path(pathname_t * name1,pathname_t * name2)938 int 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 
lstat64_path(pathname_t * name,struct stat64 * sbuf)992 int 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 
make_freq_table(void)1010 void 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 
mkdir_path(pathname_t * name,mode_t mode)1026 int 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 
mknod_path(pathname_t * name,mode_t mode,dev_t dev)1044 int 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 
namerandpad(int id,char * buf,int i)1062 void 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 
open_path(pathname_t * name,int oflag)1082 int 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 
opendir_path(pathname_t * name)1100 DIR *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 
process_freq(char * arg)1118 void 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 
readlink_path(pathname_t * name,char * lbuf,size_t lbufsiz)1139 int 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 
rename_path(pathname_t * name1,pathname_t * name2)1159 int 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 
rmdir_path(pathname_t * name)1213 int 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 
separate_pathname(pathname_t * name,char * buf,pathname_t * newname)1231 void 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 
show_ops(int flag,char * lead_str)1249 void 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 
stat64_path(pathname_t * name,struct stat64 * sbuf)1285 int 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 
symlink_path(const char * name1,pathname_t * name)1303 int 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 
truncate64_path(pathname_t * name,off64_t length)1326 int 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 
unlink_path(pathname_t * name)1344 int 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 
usage(void)1362 void 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 
write_freq(void)1400 void 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 
zero_freq(void)1410 void 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 
allocsp_f(int opno,long r)1420 void 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 
attr_remove_f(int opno,long r)1471 void 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 
attr_set_f(int opno,long r)1540 void 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 
bulkstat_f(int opno,long r)1571 void 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 
bulkstat1_f(int opno,long r)1602 void 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 
chown_f(int opno,long r)1659 void 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 
creat_f(int opno,long r)1680 void 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 
setdirect(int fd)1744 int 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 
dread_f(int opno,long r)1768 void 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 
dwrite_f(int opno,long r)1869 void 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 
fdatasync_f(int opno,long r)1962 void 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
freesp_f(int opno,long r)1995 void 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 
fsync_f(int opno,long r)2048 void 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 
getdents_f(int opno,long r)2079 void 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 
link_f(int opno,long r)2105 void 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 
mkdir_f(int opno,long r)2153 void 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 
mknod_f(int opno,long r)2188 void 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 
read_f(int opno,long r)2223 void 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 
readlink_f(int opno,long r)2282 void 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 
rename_f(int opno,long r)2303 void 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
resvsp_f(int opno,long r)2360 void 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 
rmdir_f(int opno,long r)2413 void 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 
stat_f(int opno,long r)2436 void 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 
symlink_f(int opno,long r)2457 void 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 */
sync_f(int opno,long r)2504 void sync_f(int opno, long r)
2505 {
2506 	sync();
2507 	if (verbose)
2508 		printf("%d/%d: sync\n", procid, opno);
2509 }
2510 
truncate_f(int opno,long r)2511 void 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 
unlink_f(int opno,long r)2547 void 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
unresvsp_f(int opno,long r)2572 void 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 
write_f(int opno,long r)2625 void 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