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