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