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