fsstress: cleanup flist with test directory together
[xfstests-dev.git] / ltp / fsstress.c
1 /*
2  * Copyright (c) 2000-2002 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include <linux/fs.h>
20 #include <setjmp.h>
21 #include "global.h"
22
23 #ifdef HAVE_ATTR_XATTR_H
24 #include <attr/xattr.h>
25 #endif
26 #ifdef HAVE_ATTR_ATTRIBUTES_H
27 #include <attr/attributes.h>
28 #endif
29 #ifdef HAVE_LINUX_FIEMAP_H
30 #include <linux/fiemap.h>
31 #endif
32 #ifndef HAVE_ATTR_LIST
33 #define attr_list(path, buf, size, flags, cursor) (errno = -ENOSYS, -1)
34 #endif
35 #ifdef HAVE_SYS_PRCTL_H
36 #include <sys/prctl.h>
37 #endif
38
39 #ifndef FS_IOC_GETFLAGS
40 #define FS_IOC_GETFLAGS                 _IOR('f', 1, long)
41 #endif
42 #ifndef FS_IOC_SETFLAGS
43 #define FS_IOC_SETFLAGS                 _IOW('f', 2, long)
44 #endif
45
46 #include <math.h>
47 #define XFS_ERRTAG_MAX          17
48 #define XFS_IDMODULO_MAX        31      /* user/group IDs (1 << x)  */
49 #define XFS_PROJIDMODULO_MAX    16      /* project IDs (1 << x)     */
50
51 #define FILELEN_MAX             (32*4096)
52
53 typedef enum {
54         OP_ALLOCSP,
55         OP_ATTR_REMOVE,
56         OP_ATTR_SET,
57         OP_BULKSTAT,
58         OP_BULKSTAT1,
59         OP_CHOWN,
60         OP_CREAT,
61         OP_DREAD,
62         OP_DWRITE,
63         OP_FALLOCATE,
64         OP_FDATASYNC,
65         OP_FIEMAP,
66         OP_FREESP,
67         OP_FSYNC,
68         OP_GETATTR,
69         OP_GETDENTS,
70         OP_LINK,
71         OP_MKDIR,
72         OP_MKNOD,
73         OP_MREAD,
74         OP_MWRITE,
75         OP_PUNCH,
76         OP_ZERO,
77         OP_COLLAPSE,
78         OP_INSERT,
79         OP_READ,
80         OP_READLINK,
81         OP_RENAME,
82         OP_RESVSP,
83         OP_RMDIR,
84         OP_SETATTR,
85         OP_SETXATTR,
86         OP_STAT,
87         OP_SYMLINK,
88         OP_SYNC,
89         OP_TRUNCATE,
90         OP_UNLINK,
91         OP_UNRESVSP,
92         OP_WRITE,
93         OP_LAST
94 } opty_t;
95
96 typedef void (*opfnc_t)(int, long);
97
98 typedef struct opdesc {
99         opty_t  op;
100         char    *name;
101         opfnc_t func;
102         int     freq;
103         int     iswrite;
104 } opdesc_t;
105
106 typedef struct fent {
107         int     id;
108         int     parent;
109 } fent_t;
110
111 typedef struct flist {
112         int     nfiles;
113         int     nslots;
114         int     tag;
115         fent_t  *fents;
116 } flist_t;
117
118 typedef struct pathname {
119         int     len;
120         char    *path;
121 } pathname_t;
122
123 struct print_flags {
124         unsigned long mask;
125         const char *name;
126 };
127
128 struct print_string {
129         char *buffer;
130         int len;
131         int max;
132 };
133
134 #define FT_DIR  0
135 #define FT_DIRm (1 << FT_DIR)
136 #define FT_REG  1
137 #define FT_REGm (1 << FT_REG)
138 #define FT_SYM  2
139 #define FT_SYMm (1 << FT_SYM)
140 #define FT_DEV  3
141 #define FT_DEVm (1 << FT_DEV)
142 #define FT_RTF  4
143 #define FT_RTFm (1 << FT_RTF)
144 #define FT_nft  5
145 #define FT_ANYm ((1 << FT_nft) - 1)
146 #define FT_REGFILE      (FT_REGm | FT_RTFm)
147 #define FT_NOTDIR       (FT_ANYm & ~FT_DIRm)
148
149 #define FLIST_SLOT_INCR 16
150 #define NDCACHE 64
151
152 #define MAXFSIZE        ((1ULL << 63) - 1ULL)
153 #define MAXFSIZE32      ((1ULL << 40) - 1ULL)
154
155 void    allocsp_f(int, long);
156 void    attr_remove_f(int, long);
157 void    attr_set_f(int, long);
158 void    bulkstat_f(int, long);
159 void    bulkstat1_f(int, long);
160 void    chown_f(int, long);
161 void    creat_f(int, long);
162 void    dread_f(int, long);
163 void    dwrite_f(int, long);
164 void    fallocate_f(int, long);
165 void    fdatasync_f(int, long);
166 void    fiemap_f(int, long);
167 void    freesp_f(int, long);
168 void    fsync_f(int, long);
169 void    getattr_f(int, long);
170 void    getdents_f(int, long);
171 void    link_f(int, long);
172 void    mkdir_f(int, long);
173 void    mknod_f(int, long);
174 void    mread_f(int, long);
175 void    mwrite_f(int, long);
176 void    punch_f(int, long);
177 void    zero_f(int, long);
178 void    collapse_f(int, long);
179 void    insert_f(int, long);
180 void    read_f(int, long);
181 void    readlink_f(int, long);
182 void    rename_f(int, long);
183 void    resvsp_f(int, long);
184 void    rmdir_f(int, long);
185 void    setattr_f(int, long);
186 void    setxattr_f(int, long);
187 void    stat_f(int, long);
188 void    symlink_f(int, long);
189 void    sync_f(int, long);
190 void    truncate_f(int, long);
191 void    unlink_f(int, long);
192 void    unresvsp_f(int, long);
193 void    write_f(int, long);
194
195 opdesc_t        ops[] = {
196      /* { OP_ENUM, "name", function, freq, iswrite }, */
197         { OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 },
198         { OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 },
199         { OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 },
200         { OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0 },
201         { OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0 },
202         { OP_CHOWN, "chown", chown_f, 3, 1 },
203         { OP_CREAT, "creat", creat_f, 4, 1 },
204         { OP_DREAD, "dread", dread_f, 4, 0 },
205         { OP_DWRITE, "dwrite", dwrite_f, 4, 1 },
206         { OP_FALLOCATE, "fallocate", fallocate_f, 1, 1 },
207         { OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 },
208         { OP_FIEMAP, "fiemap", fiemap_f, 1, 1 },
209         { OP_FREESP, "freesp", freesp_f, 1, 1 },
210         { OP_FSYNC, "fsync", fsync_f, 1, 1 },
211         { OP_GETATTR, "getattr", getattr_f, 1, 0 },
212         { OP_GETDENTS, "getdents", getdents_f, 1, 0 },
213         { OP_LINK, "link", link_f, 1, 1 },
214         { OP_MKDIR, "mkdir", mkdir_f, 2, 1 },
215         { OP_MKNOD, "mknod", mknod_f, 2, 1 },
216         { OP_MREAD, "mread", mread_f, 2, 0 },
217         { OP_MWRITE, "mwrite", mwrite_f, 2, 1 },
218         { OP_PUNCH, "punch", punch_f, 1, 1 },
219         { OP_ZERO, "zero", zero_f, 1, 1 },
220         { OP_COLLAPSE, "collapse", collapse_f, 1, 1 },
221         { OP_INSERT, "insert", insert_f, 1, 1 },
222         { OP_READ, "read", read_f, 1, 0 },
223         { OP_READLINK, "readlink", readlink_f, 1, 0 },
224         { OP_RENAME, "rename", rename_f, 2, 1 },
225         { OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
226         { OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
227         { OP_SETATTR, "setattr", setattr_f, 0, 1 },
228         { OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
229         { OP_STAT, "stat", stat_f, 1, 0 },
230         { OP_SYMLINK, "symlink", symlink_f, 2, 1 },
231         { OP_SYNC, "sync", sync_f, 1, 1 },
232         { OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
233         { OP_UNLINK, "unlink", unlink_f, 1, 1 },
234         { OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1 },
235         { OP_WRITE, "write", write_f, 4, 1 },
236 }, *ops_end;
237
238 flist_t flist[FT_nft] = {
239         { 0, 0, 'd', NULL },
240         { 0, 0, 'f', NULL },
241         { 0, 0, 'l', NULL },
242         { 0, 0, 'c', NULL },
243         { 0, 0, 'r', NULL },
244 };
245
246 int             dcache[NDCACHE];
247 int             errrange;
248 int             errtag;
249 opty_t          *freq_table;
250 int             freq_table_size;
251 xfs_fsop_geom_t geom;
252 char            *homedir;
253 int             *ilist;
254 int             ilistlen;
255 off64_t         maxfsize;
256 char            *myprog;
257 int             namerand;
258 int             nameseq;
259 int             nops;
260 int             nproc = 1;
261 int             operations = 1;
262 unsigned int    idmodulo = XFS_IDMODULO_MAX;
263 unsigned int    attr_mask = ~0;
264 int             procid;
265 int             rtpct;
266 unsigned long   seed = 0;
267 ino_t           top_ino;
268 int             cleanup = 0;
269 int             verbose = 0;
270 int             verifiable_log = 0;
271 sig_atomic_t    should_stop = 0;
272 sigjmp_buf      *sigbus_jmp = NULL;
273 char            *execute_cmd = NULL;
274 int             execute_freq = 1;
275 struct print_string     flag_str = {0};
276
277 void    add_to_flist(int, int, int);
278 void    append_pathname(pathname_t *, char *);
279 int     attr_list_path(pathname_t *, char *, const int, int, attrlist_cursor_t *);
280 int     attr_remove_path(pathname_t *, const char *, int);
281 int     attr_set_path(pathname_t *, const char *, const char *, const int, int);
282 void    check_cwd(void);
283 void    cleanup_flist(void);
284 int     creat_path(pathname_t *, mode_t);
285 void    dcache_enter(int, int);
286 void    dcache_init(void);
287 fent_t  *dcache_lookup(int);
288 void    dcache_purge(int);
289 void    del_from_flist(int, int);
290 int     dirid_to_name(char *, int);
291 void    doproc(void);
292 int     fent_to_name(pathname_t *, flist_t *, fent_t *);
293 void    fix_parent(int, int);
294 void    free_pathname(pathname_t *);
295 int     generate_fname(fent_t *, int, pathname_t *, int *, int *);
296 int     get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
297 void    init_pathname(pathname_t *);
298 int     lchown_path(pathname_t *, uid_t, gid_t);
299 int     link_path(pathname_t *, pathname_t *);
300 int     lstat64_path(pathname_t *, struct stat64 *);
301 void    make_freq_table(void);
302 int     mkdir_path(pathname_t *, mode_t);
303 int     mknod_path(pathname_t *, mode_t, dev_t);
304 void    namerandpad(int, char *, int);
305 int     open_path(pathname_t *, int);
306 DIR     *opendir_path(pathname_t *);
307 void    process_freq(char *);
308 int     readlink_path(pathname_t *, char *, size_t);
309 int     rename_path(pathname_t *, pathname_t *);
310 int     rmdir_path(pathname_t *);
311 void    separate_pathname(pathname_t *, char *, pathname_t *);
312 void    show_ops(int, char *);
313 int     stat64_path(pathname_t *, struct stat64 *);
314 int     symlink_path(const char *, pathname_t *);
315 int     truncate64_path(pathname_t *, off64_t);
316 int     unlink_path(pathname_t *);
317 void    usage(void);
318 void    write_freq(void);
319 void    zero_freq(void);
320
321 void sg_handler(int signum)
322 {
323         switch (signum) {
324         case SIGTERM:
325                 should_stop = 1;
326                 break;
327         case SIGBUS:
328                 /*
329                  * Only handle SIGBUS when mmap write to a hole and no
330                  * block can be allocated due to ENOSPC, abort otherwise.
331                  */
332                 if (sigbus_jmp) {
333                         siglongjmp(*sigbus_jmp, -1);
334                 } else {
335                         printf("Unknown SIGBUS is caught, Abort!\n");
336                         abort();
337                 }
338                 /* should not reach here */
339                 break;
340         default:
341                 break;
342         }
343 }
344
345 int main(int argc, char **argv)
346 {
347         char            buf[10];
348         int             c;
349         char            *dirname = NULL;
350         char            *logname = NULL;
351         char            rpath[PATH_MAX];
352         int             fd;
353         int             i;
354         int             j;
355         char            *p;
356         int             stat;
357         struct timeval  t;
358         ptrdiff_t       srval;
359         int             nousage = 0;
360         xfs_error_injection_t           err_inj;
361         struct sigaction action;
362         int             loops = 1;
363         const char      *allopts = "cd:e:f:i:l:m:M:n:o:p:rs:S:vVwx:X:zH";
364
365         errrange = errtag = 0;
366         umask(0);
367         nops = sizeof(ops) / sizeof(ops[0]);
368         ops_end = &ops[nops];
369         myprog = argv[0];
370         while ((c = getopt(argc, argv, allopts)) != -1) {
371                 switch (c) {
372                 case 'c':
373                         cleanup = 1;
374                         break;
375                 case 'd':
376                         dirname = optarg;
377                         break;
378                 case 'e':
379                         sscanf(optarg, "%d", &errtag);
380                         if (errtag < 0) {
381                                 errtag = -errtag;
382                                 errrange = 1;
383                         } else if (errtag == 0)
384                                 errtag = -1;
385                         if (errtag >= XFS_ERRTAG_MAX) {
386                                 fprintf(stderr,
387                                         "error tag %d too large (max %d)\n",
388                                         errtag, XFS_ERRTAG_MAX - 1);
389                                 exit(1);
390                         }
391                         break;
392                 case 'f':
393                         process_freq(optarg);
394                         break;
395                 case 'i':
396                         ilist = realloc(ilist, ++ilistlen * sizeof(*ilist));
397                         ilist[ilistlen - 1] = strtol(optarg, &p, 16);
398                         break;
399                 case 'm':
400                         idmodulo = strtoul(optarg, NULL, 0);
401                         if (idmodulo > XFS_IDMODULO_MAX) {
402                                 fprintf(stderr,
403                                         "chown modulo %d too big (max %d)\n",
404                                         idmodulo, XFS_IDMODULO_MAX);
405                                 exit(1);
406                         }
407                         break;
408                 case 'l':
409                         loops = atoi(optarg);
410                         break;
411                 case 'n':
412                         operations = atoi(optarg);
413                         break;
414                 case 'o':
415                         logname = optarg;
416                         break;
417
418                 case 'p':
419                         nproc = atoi(optarg);
420                         break;
421                 case 'r':
422                         namerand = 1;
423                         break;
424                 case 's':
425                         seed = strtoul(optarg, NULL, 0);
426                         break;
427                 case 'v':
428                         verbose = 1;
429                         break;
430                 case 'w':
431                         write_freq();
432                         break;
433                 case 'x':
434                         execute_cmd = optarg;
435                         break;
436                 case 'z':
437                         zero_freq();
438                         break;
439                 case 'M':
440                         attr_mask = strtoul(optarg, NULL, 0);
441                         break;
442                 case 'S':
443                         i = 0;
444                         if (optarg[0] == 'c')
445                                 i = 1;
446                         show_ops(i, NULL);
447                         printf("\n");
448                         nousage=1;
449                         break;
450                 case 'V':
451                         verifiable_log = 1;
452                         break;
453
454                 case 'X':
455                         execute_freq = strtoul(optarg, NULL, 0);
456                         break;
457                 case '?':
458                         fprintf(stderr, "%s - invalid parameters\n",
459                                 myprog);
460                         /* fall through */
461                 case 'H':
462                         usage();
463                         exit(1);
464                 }
465         }
466
467         if (!dirname) {
468             /* no directory specified */
469             if (!nousage) usage();
470             exit(1);
471         }
472
473         (void)mkdir(dirname, 0777);
474         if (logname && logname[0] != '/') {
475                 if (getcwd(rpath, sizeof(rpath)) < 0){
476                         perror("getcwd failed");
477                         exit(1);
478                 }
479         } else {
480                 rpath[0] = '\0';
481         }
482         if (chdir(dirname) < 0) {
483                 perror(dirname);
484                 exit(1);
485         }
486         if (logname) {
487                 char path[PATH_MAX];
488                 snprintf(path, sizeof(path), "%s/%s", rpath, logname);
489                 if (freopen(path, "a", stdout) == NULL) {
490                         perror("freopen logfile failed");
491                         exit(1);
492                 }
493         }
494         sprintf(buf, "fss%x", (unsigned int)getpid());
495         fd = creat(buf, 0666);
496         if (lseek64(fd, (off64_t)(MAXFSIZE32 + 1ULL), SEEK_SET) < 0)
497                 maxfsize = (off64_t)MAXFSIZE32;
498         else
499                 maxfsize = (off64_t)MAXFSIZE;
500         make_freq_table();
501         dcache_init();
502         setlinebuf(stdout);
503         if (!seed) {
504                 gettimeofday(&t, (void *)NULL);
505                 seed = (int)t.tv_sec ^ (int)t.tv_usec;
506                 printf("seed = %ld\n", seed);
507         }
508         i = xfsctl(buf, fd, XFS_IOC_FSGEOMETRY, &geom);
509         if (i >= 0 && geom.rtblocks)
510                 rtpct = MIN(MAX(geom.rtblocks * 100 /
511                                 (geom.rtblocks + geom.datablocks), 1), 99);
512         else
513                 rtpct = 0;
514         if (errtag != 0) {
515                 if (errrange == 0) {
516                         if (errtag <= 0) {
517                                 srandom(seed);
518                                 j = random() % 100;
519
520                                 for (i = 0; i < j; i++)
521                                         (void) random();
522
523                                 errtag = (random() % (XFS_ERRTAG_MAX-1)) + 1;
524                         }
525                 } else {
526                         srandom(seed);
527                         j = random() % 100;
528
529                         for (i = 0; i < j; i++)
530                                 (void) random();
531
532                         errtag += (random() % (XFS_ERRTAG_MAX - errtag));
533                 }
534                 printf("Injecting failure on tag #%d\n", errtag);
535                 err_inj.errtag = errtag;
536                 err_inj.fd = fd;
537                 srval = xfsctl(buf, fd, XFS_IOC_ERROR_INJECTION, &err_inj);
538                 if (srval < -1) {
539                         perror("fsstress - XFS_SYSSGI error injection call");
540                         close(fd);
541                         unlink(buf);
542                         exit(1);
543                 }
544         } else
545                 close(fd);
546
547         setpgid(0, 0);
548         action.sa_handler = sg_handler;
549         sigemptyset(&action.sa_mask);
550         action.sa_flags = 0;
551         if (sigaction(SIGTERM, &action, 0)) {
552                 perror("sigaction failed");
553                 exit(1);
554         }
555
556         for (i = 0; i < nproc; i++) {
557                 if (fork() == 0) {
558                         sigemptyset(&action.sa_mask);
559                         action.sa_handler = SIG_DFL;
560                         if (sigaction(SIGTERM, &action, 0))
561                                 return 1;
562                         action.sa_handler = sg_handler;
563                         if (sigaction(SIGBUS, &action, 0))
564                                 return 1;
565 #ifdef HAVE_SYS_PRCTL_H
566                         prctl(PR_SET_PDEATHSIG, SIGKILL);
567                         if (getppid() == 1) /* parent died already? */
568                                 return 0;
569 #endif
570                         if (logname) {
571                                 char path[PATH_MAX];
572                                 snprintf(path, sizeof(path), "%s/%s.%d",
573                                          rpath, logname, i);
574                                 if (freopen(path, "a", stdout) == NULL) {
575                                         perror("freopen logfile failed");
576                                         exit(1);
577                                 }
578                         }
579                         procid = i;
580                         for (i = 0; !loops || (i < loops); i++)
581                                 doproc();
582                         return 0;
583                 }
584         }
585         while (wait(&stat) > 0 && !should_stop) {
586                 continue;
587         }
588         action.sa_flags = SA_RESTART;
589         sigaction(SIGTERM, &action, 0);
590         kill(-getpid(), SIGTERM);
591         while (wait(&stat) > 0)
592                 continue;
593
594         if (errtag != 0) {
595                 err_inj.errtag = 0;
596                 err_inj.fd = fd;
597                 srval = xfsctl(buf, fd, XFS_IOC_ERROR_CLEARALL, &err_inj);
598                 if (srval != 0) {
599                         fprintf(stderr, "Bad ej clear on %s fd=%d (%d).\n",
600                                 buf, fd, errno);
601                         perror("xfsctl(XFS_IOC_ERROR_CLEARALL)");
602                         close(fd);
603                         exit(1);
604                 }
605                 close(fd);
606         }
607
608         unlink(buf);
609         return 0;
610 }
611
612 int
613 add_string(struct print_string *str, const char *add)
614 {
615         int len = strlen(add);
616
617         if (len <= 0)
618                 return 0;
619
620         if (len > (str->max - 1) - str->len) {
621                 str->len = str->max - 1;
622                 return 0;
623         }
624
625         memcpy(str->buffer + str->len, add, len);
626         str->len += len;
627         str->buffer[str->len] = '\0';
628
629         return len;
630 }
631
632 char *
633 translate_flags(int flags, const char *delim,
634                 const struct print_flags *flag_array)
635 {
636         int i, mask, first = 1;
637         const char *add;
638
639         if (!flag_str.buffer) {
640                 flag_str.buffer = malloc(4096);
641                 flag_str.max = 4096;
642                 flag_str.len = 0;
643         }
644         if (!flag_str.buffer)
645                 return NULL;
646         flag_str.len = 0;
647         flag_str.buffer[0] = '\0';
648
649         for (i = 0;  flag_array[i].name && flags; i++) {
650                 mask = flag_array[i].mask;
651                 if ((flags & mask) != mask)
652                         continue;
653
654                 add = flag_array[i].name;
655                 flags &= ~mask;
656                 if (!first && delim)
657                         add_string(&flag_str, delim);
658                 else
659                         first = 0;
660                 add_string(&flag_str, add);
661         }
662
663         /* Check whether there are any leftover flags. */
664         if (flags) {
665                 int ret;
666                 char number[11];
667
668                 if (!first && delim)
669                         add_string(&flag_str, delim);
670
671                 ret = snprintf(number, 11, "0x%x", flags) > 0;
672                 if (ret > 0 && ret <= 11)
673                         add_string(&flag_str, number);
674         }
675
676         return flag_str.buffer;
677 }
678
679 void
680 add_to_flist(int ft, int id, int parent)
681 {
682         fent_t  *fep;
683         flist_t *ftp;
684
685         ftp = &flist[ft];
686         if (ftp->nfiles == ftp->nslots) {
687                 ftp->nslots += FLIST_SLOT_INCR;
688                 ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t));
689         }
690         fep = &ftp->fents[ftp->nfiles++];
691         fep->id = id;
692         fep->parent = parent;
693 }
694
695 void
696 append_pathname(pathname_t *name, char *str)
697 {
698         int     len;
699
700         len = strlen(str);
701 #ifdef DEBUG
702         /* attempting to append to a dir a zero length path */
703         if (len && *str == '/' && name->len == 0) {
704                 fprintf(stderr, "fsstress: append_pathname failure\n");
705                 chdir(homedir);
706                 abort();
707                 /* NOTREACHED */
708         }
709 #endif
710         name->path = realloc(name->path, name->len + 1 + len);
711         strcpy(&name->path[name->len], str);
712         name->len += len;
713 }
714
715 int
716 attr_list_path(pathname_t *name,
717                char *buffer,
718                const int buffersize,
719                int flags,
720                attrlist_cursor_t *cursor)
721 {
722         char            buf[NAME_MAX + 1];
723         pathname_t      newname;
724         int             rval;
725
726         if (flags != ATTR_DONTFOLLOW) {
727                 errno = EINVAL;
728                 return -1;
729         }
730
731         rval = attr_list(name->path, buffer, buffersize, flags, cursor);
732         if (rval >= 0 || errno != ENAMETOOLONG)
733                 return rval;
734         separate_pathname(name, buf, &newname);
735         if (chdir(buf) == 0) {
736                 rval = attr_list_path(&newname, buffer, buffersize, flags, cursor);
737                 chdir("..");
738         }
739         free_pathname(&newname);
740         return rval;
741 }
742
743 int
744 attr_remove_path(pathname_t *name, const char *attrname, int flags)
745 {
746         char            buf[NAME_MAX + 1];
747         pathname_t      newname;
748         int             rval;
749
750         rval = attr_remove(name->path, attrname, flags);
751         if (rval >= 0 || errno != ENAMETOOLONG)
752                 return rval;
753         separate_pathname(name, buf, &newname);
754         if (chdir(buf) == 0) {
755                 rval = attr_remove_path(&newname, attrname, flags);
756                 chdir("..");
757         }
758         free_pathname(&newname);
759         return rval;
760 }
761
762 int
763 attr_set_path(pathname_t *name, const char *attrname, const char *attrvalue,
764               const int valuelength, int flags)
765 {
766         char            buf[NAME_MAX + 1];
767         pathname_t      newname;
768         int             rval;
769
770         rval = attr_set(name->path, attrname, attrvalue, valuelength, flags);
771         if (rval >= 0 || errno != ENAMETOOLONG)
772                 return rval;
773         separate_pathname(name, buf, &newname);
774         if (chdir(buf) == 0) {
775                 rval = attr_set_path(&newname, attrname, attrvalue, valuelength,
776                         flags);
777                 chdir("..");
778         }
779         free_pathname(&newname);
780         return rval;
781 }
782
783 void
784 check_cwd(void)
785 {
786 #ifdef DEBUG
787         struct stat64   statbuf;
788
789         if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino)
790                 return;
791         chdir(homedir);
792         fprintf(stderr, "fsstress: check_cwd failure\n");
793         abort();
794         /* NOTREACHED */
795 #endif
796 }
797
798 /*
799  * go thru flist and release all entries
800  *
801  * NOTE: this function shouldn't be called until the end of a process
802  */
803 void
804 cleanup_flist(void)
805 {
806         flist_t *flp;
807         int     i;
808
809         for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
810                 flp->nslots = 0;
811                 flp->nfiles = 0;
812                 free(flp->fents);
813                 flp->fents = NULL;
814         }
815 }
816
817 int
818 creat_path(pathname_t *name, mode_t mode)
819 {
820         char            buf[NAME_MAX + 1];
821         pathname_t      newname;
822         int             rval;
823
824         rval = creat(name->path, mode);
825         if (rval >= 0 || errno != ENAMETOOLONG)
826                 return rval;
827         separate_pathname(name, buf, &newname);
828         if (chdir(buf) == 0) {
829                 rval = creat_path(&newname, mode);
830                 chdir("..");
831         }
832         free_pathname(&newname);
833         return rval;
834 }
835
836 void
837 dcache_enter(int dirid, int slot)
838 {
839         dcache[dirid % NDCACHE] = slot;
840 }
841
842 void
843 dcache_init(void)
844 {
845         int     i;
846
847         for (i = 0; i < NDCACHE; i++)
848                 dcache[i] = -1;
849 }
850
851 fent_t *
852 dcache_lookup(int dirid)
853 {
854         fent_t  *fep;
855         int     i;
856
857         i = dcache[dirid % NDCACHE];
858         if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
859                 return fep;
860         return NULL;
861 }
862
863 void
864 dcache_purge(int dirid)
865 {
866         int     *dcp;
867
868         dcp = &dcache[dirid % NDCACHE];
869         if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
870                 *dcp = -1;
871 }
872
873 /*
874  * Delete the item from the list by
875  * moving last entry over the deleted one;
876  * unless deleted entry is the last one.
877  * Input: which file list array and which slot in array
878  */
879 void
880 del_from_flist(int ft, int slot)
881 {
882         flist_t *ftp;
883
884         ftp = &flist[ft];
885         if (ft == FT_DIR)
886                 dcache_purge(ftp->fents[slot].id);
887         if (slot != ftp->nfiles - 1) {
888                 if (ft == FT_DIR)
889                         dcache_purge(ftp->fents[ftp->nfiles - 1].id);
890                 ftp->fents[slot] = ftp->fents[--ftp->nfiles];
891         } else
892                 ftp->nfiles--;
893 }
894
895 fent_t *
896 dirid_to_fent(int dirid)
897 {
898         fent_t  *efep;
899         fent_t  *fep;
900         flist_t *flp;
901
902         if ((fep = dcache_lookup(dirid)))
903                 return fep;
904         flp = &flist[FT_DIR];
905         for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
906                 if (fep->id == dirid) {
907                         dcache_enter(dirid, fep - flp->fents);
908                         return fep;
909                 }
910         }
911         return NULL;
912 }
913
914 void
915 doproc(void)
916 {
917         struct stat64   statbuf;
918         char            buf[10];
919         char            cmd[64];
920         int             opno;
921         int             rval;
922         opdesc_t        *p;
923         int             dividend;
924
925         dividend = (operations + execute_freq) / (execute_freq + 1);
926         sprintf(buf, "p%x", procid);
927         (void)mkdir(buf, 0777);
928         if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) {
929                 perror(buf);
930                 _exit(1);
931         }
932         top_ino = statbuf.st_ino;
933         homedir = getcwd(NULL, -1);
934         seed += procid;
935         srandom(seed);
936         if (namerand)
937                 namerand = random();
938         for (opno = 0; opno < operations; opno++) {
939                 if (execute_cmd && opno && opno % dividend == 0) {
940                         if (verbose)
941                                 printf("%d: execute command %s\n", opno,
942                                         execute_cmd);
943                         rval = system(execute_cmd);
944                         if (rval)
945                                 fprintf(stderr, "execute command failed with "
946                                         "%d\n", rval);
947                 }
948                 p = &ops[freq_table[random() % freq_table_size]];
949                 p->func(opno, random());
950                 /*
951                  * test for forced shutdown by stat'ing the test
952                  * directory.  If this stat returns EIO, assume
953                  * the forced shutdown happened.
954                  */
955                 if (errtag != 0 && opno % 100 == 0)  {
956                         rval = stat64(".", &statbuf);
957                         if (rval == EIO)  {
958                                 fprintf(stderr, "Detected EIO\n");
959                                 goto errout;
960                         }
961                 }
962         }
963 errout:
964         chdir("..");
965         if (cleanup) {
966                 sprintf(cmd, "rm -rf %s", buf);
967                 system(cmd);
968                 cleanup_flist();
969         }
970 }
971
972 /*
973  * build up a pathname going thru the file entry and all
974  * its parent entries
975  * Return 0 on error, 1 on success;
976  */
977 int
978 fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
979 {
980         char    buf[NAME_MAX + 1];
981         int     i;
982         fent_t  *pfep;
983         int     e;
984
985         if (fep == NULL)
986                 return 0;
987
988         /* build up parent directory name */
989         if (fep->parent != -1) {
990                 pfep = dirid_to_fent(fep->parent);
991 #ifdef DEBUG
992                 if (pfep == NULL) {
993                         fprintf(stderr, "%d: fent-id = %d: can't find parent id: %d\n",
994                                 procid, fep->id, fep->parent);
995                 } 
996 #endif
997                 if (pfep == NULL)
998                         return 0;
999                 e = fent_to_name(name, &flist[FT_DIR], pfep);
1000                 if (!e)
1001                         return 0;
1002                 append_pathname(name, "/");
1003         }
1004
1005         i = sprintf(buf, "%c%x", flp->tag, fep->id);
1006         namerandpad(fep->id, buf, i);
1007         append_pathname(name, buf);
1008         return 1;
1009 }
1010
1011 void
1012 fix_parent(int oldid, int newid)
1013 {
1014         fent_t  *fep;
1015         flist_t *flp;
1016         int     i;
1017         int     j;
1018
1019         for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1020                 for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
1021                         if (fep->parent == oldid)
1022                                 fep->parent = newid;
1023                 }
1024         }
1025 }
1026
1027 void
1028 free_pathname(pathname_t *name)
1029 {
1030         if (name->path) {
1031                 free(name->path);
1032                 name->path = NULL;
1033                 name->len = 0;
1034         }
1035 }
1036
1037 /*
1038  * Generate a filename of type ft.
1039  * If we have a fep which should be a directory then use it
1040  * as the parent path for this new filename i.e. prepend with it.
1041  */
1042 int
1043 generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
1044 {
1045         char    buf[NAME_MAX + 1];
1046         flist_t *flp;
1047         int     id;
1048         int     j;
1049         int     len;
1050         int     e;
1051
1052         /* create name */
1053         flp = &flist[ft];
1054         len = sprintf(buf, "%c%x", flp->tag, id = nameseq++);
1055         namerandpad(id, buf, len);
1056
1057         /* prepend fep parent dir-name to it */
1058         if (fep) {
1059                 e = fent_to_name(name, &flist[FT_DIR], fep);
1060                 if (!e)
1061                         return 0;
1062                 append_pathname(name, "/");
1063         }
1064         append_pathname(name, buf);
1065
1066         *idp = id;
1067         *v = verbose;
1068         for (j = 0; !*v && j < ilistlen; j++) {
1069                 if (ilist[j] == id) {
1070                         *v = 1;
1071                         break;
1072                 }
1073         }
1074         return 1;
1075 }
1076
1077 /*
1078  * Get file 
1079  * Input: "which" to choose the file-types eg. non-directory
1080  * Input: "r" to choose which file
1081  * Output: file-list, file-entry, name for the chosen file.
1082  * Output: verbose if chosen file is on the ilist.
1083  */
1084 int
1085 get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
1086           int *v)
1087 {
1088         int     totalsum = 0; /* total number of matching files */
1089         int     partialsum = 0; /* partial sum of matching files */
1090         fent_t  *fep;
1091         flist_t *flp;
1092         int     i;
1093         int     j;
1094         int     x;
1095         int     e = 1; /* success */
1096
1097         /*
1098          * go thru flist and add up number of files for each
1099          * category that matches with <which>.
1100          */
1101         for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1102                 if (which & (1 << i))
1103                         totalsum += flp->nfiles;
1104         }
1105         if (totalsum == 0) {
1106                 if (flpp)
1107                         *flpp = NULL;
1108                 if (fepp)
1109                         *fepp = NULL;
1110                 *v = verbose;
1111                 return 0;
1112         }
1113
1114         /*
1115          * Now we have possible matches between 0..totalsum-1.
1116          * And we use r to help us choose which one we want,
1117          * which when bounded by totalsum becomes x.
1118          */ 
1119         x = (int)(r % totalsum);
1120         for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1121                 if (which & (1 << i)) {
1122                         if (x < partialsum + flp->nfiles) {
1123
1124                                 /* found the matching file entry */
1125                                 fep = &flp->fents[x - partialsum];
1126
1127                                 /* fill-in what we were asked for */
1128                                 if (name) {
1129                                         e = fent_to_name(name, flp, fep);
1130 #ifdef DEBUG
1131                                         if (!e) {
1132                                                 fprintf(stderr, "%d: failed to get path for entry:"
1133                                                                 " id=%d,parent=%d\n",   
1134                                                         procid, fep->id, fep->parent);
1135                                         }
1136 #endif
1137                                 }
1138                                 if (flpp)
1139                                         *flpp = flp;
1140                                 if (fepp)
1141                                         *fepp = fep;
1142
1143                                 /* turn on verbose if its an ilisted file */
1144                                 *v = verbose;
1145                                 for (j = 0; !*v && j < ilistlen; j++) {
1146                                         if (ilist[j] == fep->id) {
1147                                                 *v = 1;
1148                                                 break;
1149                                         }
1150                                 }
1151                                 return e;
1152                         }
1153                         partialsum += flp->nfiles;
1154                 }
1155         }
1156 #ifdef DEBUG
1157         fprintf(stderr, "fsstress: get_fname failure\n");
1158         abort();
1159 #endif
1160         return 0;
1161 }
1162
1163 void
1164 init_pathname(pathname_t *name)
1165 {
1166         name->len = 0;
1167         name->path = NULL;
1168 }
1169
1170 int
1171 lchown_path(pathname_t *name, uid_t owner, gid_t group)
1172 {
1173         char            buf[NAME_MAX + 1];
1174         pathname_t      newname;
1175         int             rval;
1176
1177         rval = lchown(name->path, owner, group);
1178         if (rval >= 0 || errno != ENAMETOOLONG)
1179                 return rval;
1180         separate_pathname(name, buf, &newname);
1181         if (chdir(buf) == 0) {
1182                 rval = lchown_path(&newname, owner, group);
1183                 chdir("..");
1184         }
1185         free_pathname(&newname);
1186         return rval;
1187 }
1188
1189 int
1190 link_path(pathname_t *name1, pathname_t *name2)
1191 {
1192         char            buf1[NAME_MAX + 1];
1193         char            buf2[NAME_MAX + 1];
1194         int             down1;
1195         pathname_t      newname1;
1196         pathname_t      newname2;
1197         int             rval;
1198
1199         rval = link(name1->path, name2->path);
1200         if (rval >= 0 || errno != ENAMETOOLONG)
1201                 return rval;
1202         separate_pathname(name1, buf1, &newname1);
1203         separate_pathname(name2, buf2, &newname2);
1204         if (strcmp(buf1, buf2) == 0) {
1205                 if (chdir(buf1) == 0) {
1206                         rval = link_path(&newname1, &newname2);
1207                         chdir("..");
1208                 }
1209         } else {
1210                 if (strcmp(buf1, "..") == 0)
1211                         down1 = 0;
1212                 else if (strcmp(buf2, "..") == 0)
1213                         down1 = 1;
1214                 else if (strlen(buf1) == 0)
1215                         down1 = 0;
1216                 else if (strlen(buf2) == 0)
1217                         down1 = 1;
1218                 else
1219                         down1 = MAX(newname1.len, 3 + name2->len) <=
1220                                 MAX(3 + name1->len, newname2.len);
1221                 if (down1) {
1222                         free_pathname(&newname2);
1223                         append_pathname(&newname2, "../");
1224                         append_pathname(&newname2, name2->path);
1225                         if (chdir(buf1) == 0) {
1226                                 rval = link_path(&newname1, &newname2);
1227                                 chdir("..");
1228                         }
1229                 } else {
1230                         free_pathname(&newname1);
1231                         append_pathname(&newname1, "../");
1232                         append_pathname(&newname1, name1->path);
1233                         if (chdir(buf2) == 0) {
1234                                 rval = link_path(&newname1, &newname2);
1235                                 chdir("..");
1236                         }
1237                 }
1238         }
1239         free_pathname(&newname1);
1240         free_pathname(&newname2);
1241         return rval;
1242 }
1243
1244 int
1245 lstat64_path(pathname_t *name, struct stat64 *sbuf)
1246 {
1247         char            buf[NAME_MAX + 1];
1248         pathname_t      newname;
1249         int             rval;
1250
1251         rval = lstat64(name->path, sbuf);
1252         if (rval >= 0 || errno != ENAMETOOLONG)
1253                 return rval;
1254         separate_pathname(name, buf, &newname);
1255         if (chdir(buf) == 0) {
1256                 rval = lstat64_path(&newname, sbuf);
1257                 chdir("..");
1258         }
1259         free_pathname(&newname);
1260         return rval;
1261 }
1262
1263 void
1264 make_freq_table(void)
1265 {
1266         int             f;
1267         int             i;
1268         opdesc_t        *p;
1269
1270         for (p = ops, f = 0; p < ops_end; p++)
1271                 f += p->freq;
1272         freq_table = malloc(f * sizeof(*freq_table));
1273         freq_table_size = f;
1274         for (p = ops, i = 0; p < ops_end; p++) {
1275                 for (f = 0; f < p->freq; f++, i++)
1276                         freq_table[i] = p->op;
1277         }
1278 }
1279
1280 int
1281 mkdir_path(pathname_t *name, mode_t mode)
1282 {
1283         char            buf[NAME_MAX + 1];
1284         pathname_t      newname;
1285         int             rval;
1286
1287         rval = mkdir(name->path, mode);
1288         if (rval >= 0 || errno != ENAMETOOLONG)
1289                 return rval;
1290         separate_pathname(name, buf, &newname);
1291         if (chdir(buf) == 0) {
1292                 rval = mkdir_path(&newname, mode);
1293                 chdir("..");
1294         }
1295         free_pathname(&newname);
1296         return rval;
1297 }
1298
1299 int
1300 mknod_path(pathname_t *name, mode_t mode, dev_t dev)
1301 {
1302         char            buf[NAME_MAX + 1];
1303         pathname_t      newname;
1304         int             rval;
1305
1306         rval = mknod(name->path, mode, dev);
1307         if (rval >= 0 || errno != ENAMETOOLONG)
1308                 return rval;
1309         separate_pathname(name, buf, &newname);
1310         if (chdir(buf) == 0) {
1311                 rval = mknod_path(&newname, mode, dev);
1312                 chdir("..");
1313         }
1314         free_pathname(&newname);
1315         return rval;
1316 }
1317
1318 void
1319 namerandpad(int id, char *buf, int i)
1320 {
1321         int             bucket;
1322         static int      buckets[] =
1323                                 { 2, 4, 8, 16, 32, 64, 128, NAME_MAX };
1324         int             padlen;
1325         int             padmod;
1326
1327         if (namerand == 0)
1328                 return;
1329         bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0]));
1330         padmod = buckets[bucket] + 1 - i;
1331         if (padmod <= 0)
1332                 return;
1333         padlen = (id ^ namerand) % padmod;
1334         if (padlen) {
1335                 memset(&buf[i], 'X', padlen);
1336                 buf[i + padlen] = '\0';
1337         }
1338 }
1339
1340 int
1341 open_path(pathname_t *name, int oflag)
1342 {
1343         char            buf[NAME_MAX + 1];
1344         pathname_t      newname;
1345         int             rval;
1346
1347         rval = open(name->path, oflag);
1348         if (rval >= 0 || errno != ENAMETOOLONG)
1349                 return rval;
1350         separate_pathname(name, buf, &newname);
1351         if (chdir(buf) == 0) {
1352                 rval = open_path(&newname, oflag);
1353                 chdir("..");
1354         }
1355         free_pathname(&newname);
1356         return rval;
1357 }
1358
1359 DIR *
1360 opendir_path(pathname_t *name)
1361 {
1362         char            buf[NAME_MAX + 1];
1363         pathname_t      newname;
1364         DIR             *rval;
1365
1366         rval = opendir(name->path);
1367         if (rval || errno != ENAMETOOLONG)
1368                 return rval;
1369         separate_pathname(name, buf, &newname);
1370         if (chdir(buf) == 0) {
1371                 rval = opendir_path(&newname);
1372                 chdir("..");
1373         }
1374         free_pathname(&newname);
1375         return rval;
1376 }
1377
1378 void
1379 process_freq(char *arg)
1380 {
1381         opdesc_t        *p;
1382         char            *s;
1383
1384         s = strchr(arg, '=');
1385         if (s == NULL) {
1386                 fprintf(stderr, "bad argument '%s'\n", arg);
1387                 exit(1);
1388         }
1389         *s++ = '\0';
1390         for (p = ops; p < ops_end; p++) {
1391                 if (strcmp(arg, p->name) == 0) {
1392                         p->freq = atoi(s);
1393                         return;
1394                 }
1395         }
1396         fprintf(stderr, "can't find op type %s for -f\n", arg);
1397         exit(1);
1398 }
1399
1400 int
1401 readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz)
1402 {
1403         char            buf[NAME_MAX + 1];
1404         pathname_t      newname;
1405         int             rval;
1406
1407         rval = readlink(name->path, lbuf, lbufsiz);
1408         if (rval >= 0 || errno != ENAMETOOLONG)
1409                 return rval;
1410         separate_pathname(name, buf, &newname);
1411         if (chdir(buf) == 0) {
1412                 rval = readlink_path(&newname, lbuf, lbufsiz);
1413                 chdir("..");
1414         }
1415         free_pathname(&newname);
1416         return rval;
1417 }
1418
1419 int
1420 rename_path(pathname_t *name1, pathname_t *name2)
1421 {
1422         char            buf1[NAME_MAX + 1];
1423         char            buf2[NAME_MAX + 1];
1424         int             down1;
1425         pathname_t      newname1;
1426         pathname_t      newname2;
1427         int             rval;
1428
1429         rval = rename(name1->path, name2->path);
1430         if (rval >= 0 || errno != ENAMETOOLONG)
1431                 return rval;
1432         separate_pathname(name1, buf1, &newname1);
1433         separate_pathname(name2, buf2, &newname2);
1434         if (strcmp(buf1, buf2) == 0) {
1435                 if (chdir(buf1) == 0) {
1436                         rval = rename_path(&newname1, &newname2);
1437                         chdir("..");
1438                 }
1439         } else {
1440                 if (strcmp(buf1, "..") == 0)
1441                         down1 = 0;
1442                 else if (strcmp(buf2, "..") == 0)
1443                         down1 = 1;
1444                 else if (strlen(buf1) == 0)
1445                         down1 = 0;
1446                 else if (strlen(buf2) == 0)
1447                         down1 = 1;
1448                 else
1449                         down1 = MAX(newname1.len, 3 + name2->len) <=
1450                                 MAX(3 + name1->len, newname2.len);
1451                 if (down1) {
1452                         free_pathname(&newname2);
1453                         append_pathname(&newname2, "../");
1454                         append_pathname(&newname2, name2->path);
1455                         if (chdir(buf1) == 0) {
1456                                 rval = rename_path(&newname1, &newname2);
1457                                 chdir("..");
1458                         }
1459                 } else {
1460                         free_pathname(&newname1);
1461                         append_pathname(&newname1, "../");
1462                         append_pathname(&newname1, name1->path);
1463                         if (chdir(buf2) == 0) {
1464                                 rval = rename_path(&newname1, &newname2);
1465                                 chdir("..");
1466                         }
1467                 }
1468         }
1469         free_pathname(&newname1);
1470         free_pathname(&newname2);
1471         return rval;
1472 }
1473
1474 int
1475 rmdir_path(pathname_t *name)
1476 {
1477         char            buf[NAME_MAX + 1];
1478         pathname_t      newname;
1479         int             rval;
1480
1481         rval = rmdir(name->path);
1482         if (rval >= 0 || errno != ENAMETOOLONG)
1483                 return rval;
1484         separate_pathname(name, buf, &newname);
1485         if (chdir(buf) == 0) {
1486                 rval = rmdir_path(&newname);
1487                 chdir("..");
1488         }
1489         free_pathname(&newname);
1490         return rval;
1491 }
1492
1493 void
1494 separate_pathname(pathname_t *name, char *buf, pathname_t *newname)
1495 {
1496         char    *slash;
1497
1498         init_pathname(newname);
1499         slash = strchr(name->path, '/');
1500         if (slash == NULL) {
1501                 buf[0] = '\0';
1502                 return;
1503         }
1504         *slash = '\0';
1505         strcpy(buf, name->path);
1506         *slash = '/';
1507         append_pathname(newname, slash + 1);
1508 }
1509
1510 #define WIDTH 80
1511
1512 void
1513 show_ops(int flag, char *lead_str)
1514 {
1515         opdesc_t        *p;
1516
1517         if (flag<0) {
1518                 /* print in list form */
1519                 int             x = WIDTH;
1520                 
1521                 for (p = ops; p < ops_end; p++) {
1522                         if (lead_str != NULL && x+strlen(p->name)>=WIDTH-5)
1523                                 x=printf("%s%s", (p==ops)?"":"\n", lead_str);
1524                         x+=printf("%s ", p->name);
1525                 }
1526                 printf("\n");
1527         } else if (flag == 0) {
1528                 /* Table view style */
1529                 int             f;
1530                 for (f = 0, p = ops; p < ops_end; p++)
1531                         f += p->freq;
1532
1533                 if (f == 0)
1534                         flag = 1;
1535
1536                 for (p = ops; p < ops_end; p++) {
1537                         if (flag != 0 || p->freq > 0) {
1538                                 if (lead_str != NULL)
1539                                         printf("%s", lead_str);
1540                                 printf("%20s %d/%d %s\n",
1541                                 p->name, p->freq, f,
1542                                 (p->iswrite == 0) ? " " : "write op");
1543                         }
1544                 }
1545         } else {
1546                 /* Command line style */
1547                 if (lead_str != NULL)
1548                         printf("%s", lead_str);
1549                 printf ("-z -s %ld -m %d -n %d -p %d \\\n", seed, idmodulo,
1550                         operations, nproc);
1551                 for (p = ops; p < ops_end; p++)
1552                         if (p->freq > 0)
1553                                 printf("-f %s=%d \\\n",p->name, p->freq);
1554         }
1555 }
1556
1557 int
1558 stat64_path(pathname_t *name, struct stat64 *sbuf)
1559 {
1560         char            buf[NAME_MAX + 1];
1561         pathname_t      newname;
1562         int             rval;
1563
1564         rval = stat64(name->path, sbuf);
1565         if (rval >= 0 || errno != ENAMETOOLONG)
1566                 return rval;
1567         separate_pathname(name, buf, &newname);
1568         if (chdir(buf) == 0) {
1569                 rval = stat64_path(&newname, sbuf);
1570                 chdir("..");
1571         }
1572         free_pathname(&newname);
1573         return rval;
1574 }
1575
1576 int
1577 symlink_path(const char *name1, pathname_t *name)
1578 {
1579         char            buf[NAME_MAX + 1];
1580         pathname_t      newname;
1581         int             rval;
1582         
1583         if (!strcmp(name1, name->path)) {
1584             printf("yikes! %s %s\n", name1, name->path);
1585             return 0;
1586         }
1587
1588         rval = symlink(name1, name->path);
1589         if (rval >= 0 || errno != ENAMETOOLONG)
1590                 return rval;
1591         separate_pathname(name, buf, &newname);
1592         if (chdir(buf) == 0) {
1593                 rval = symlink_path(name1, &newname);
1594                 chdir("..");
1595         }
1596         free_pathname(&newname);
1597         return rval;
1598 }
1599
1600 int
1601 truncate64_path(pathname_t *name, off64_t length)
1602 {
1603         char            buf[NAME_MAX + 1];
1604         pathname_t      newname;
1605         int             rval;
1606
1607         rval = truncate64(name->path, length);
1608         if (rval >= 0 || errno != ENAMETOOLONG)
1609                 return rval;
1610         separate_pathname(name, buf, &newname);
1611         if (chdir(buf) == 0) {
1612                 rval = truncate64_path(&newname, length);
1613                 chdir("..");
1614         }
1615         free_pathname(&newname);
1616         return rval;
1617 }
1618
1619 int
1620 unlink_path(pathname_t *name)
1621 {
1622         char            buf[NAME_MAX + 1];
1623         pathname_t      newname;
1624         int             rval;
1625
1626         rval = unlink(name->path);
1627         if (rval >= 0 || errno != ENAMETOOLONG)
1628                 return rval;
1629         separate_pathname(name, buf, &newname);
1630         if (chdir(buf) == 0) {
1631                 rval = unlink_path(&newname);
1632                 chdir("..");
1633         }
1634         free_pathname(&newname);
1635         return rval;
1636 }
1637
1638 void
1639 usage(void)
1640 {
1641         printf("Usage: %s -H   or\n", myprog);
1642         printf("       %s [-c][-d dir][-e errtg][-f op_name=freq][-l loops][-n nops]\n",
1643                 myprog);
1644         printf("          [-p nproc][-r len][-s seed][-v][-w][-x cmd][-z][-S][-X ncmd]\n");
1645         printf("where\n");
1646         printf("   -c               clean up the test directory after each run\n");
1647         printf("   -d dir           specifies the base directory for operations\n");
1648         printf("   -e errtg         specifies error injection stuff\n");
1649         printf("   -f op_name=freq  changes the frequency of option name to freq\n");
1650         printf("                    the valid operation names are:\n");
1651         show_ops(-1, "                        ");
1652         printf("   -i filenum       get verbose output for this nth file object\n");
1653         printf("   -l loops         specifies the no. of times the testrun should loop.\n");
1654         printf("                     *use 0 for infinite (default 1)\n");
1655         printf("   -m modulo        uid/gid modulo for chown/chgrp (default 32)\n");
1656         printf("   -n nops          specifies the no. of operations per process (default 1)\n");
1657         printf("   -o logfile       specifies logfile name\n");
1658         printf("   -p nproc         specifies the no. of processes (default 1)\n");
1659         printf("   -r               specifies random name padding\n");
1660         printf("   -s seed          specifies the seed for the random generator (default random)\n");
1661         printf("   -v               specifies verbose mode\n");
1662         printf("   -w               zeros frequencies of non-write operations\n");
1663         printf("   -x cmd           execute command in the middle of operations\n");
1664         printf("   -z               zeros frequencies of all operations\n");
1665         printf("   -S [c,t]         prints the list of operations (omitting zero frequency) in command line or table style\n");
1666         printf("   -V               specifies verifiable logging mode (omitting inode numbers)\n");
1667         printf("   -X ncmd          number of calls to the -x command (default 1)\n");
1668         printf("   -H               prints usage and exits\n");
1669 }
1670
1671 void
1672 write_freq(void)
1673 {
1674         opdesc_t        *p;
1675
1676         for (p = ops; p < ops_end; p++) {
1677                 if (!p->iswrite)
1678                         p->freq = 0;
1679         }
1680 }
1681
1682 void
1683 zero_freq(void)
1684 {
1685         opdesc_t        *p;
1686
1687         for (p = ops; p < ops_end; p++)
1688                 p->freq = 0;
1689 }
1690
1691 void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
1692 {
1693         if (verbose)
1694                 snprintf(str, sz, "[%ld %ld %d %d %lld %lld]",
1695                          verifiable_log ? -1: (long)s->st_ino,
1696                          (long)s->st_nlink,  s->st_uid, s->st_gid,
1697                          (long long) s->st_blocks, (long long) s->st_size);
1698 }
1699
1700 void
1701 allocsp_f(int opno, long r)
1702 {
1703         int             e;
1704         pathname_t      f;
1705         int             fd;
1706         struct xfs_flock64      fl;
1707         __int64_t       lr;
1708         off64_t         off;
1709         struct stat64   stb;
1710         int             v;
1711         char            st[1024];
1712
1713         init_pathname(&f);
1714         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1715                 if (v)
1716                         printf("%d/%d: allocsp - no filename\n", procid, opno);
1717                 free_pathname(&f);
1718                 return;
1719         }
1720         fd = open_path(&f, O_RDWR);
1721         e = fd < 0 ? errno : 0;
1722         check_cwd();
1723         if (fd < 0) {
1724                 if (v)
1725                         printf("%d/%d: allocsp - open %s failed %d\n",
1726                                 procid, opno, f.path, e);
1727                 free_pathname(&f);
1728                 return;
1729         }
1730         if (fstat64(fd, &stb) < 0) {
1731                 if (v)
1732                         printf("%d/%d: allocsp - fstat64 %s failed %d\n",
1733                                 procid, opno, f.path, errno);
1734                 free_pathname(&f);
1735                 close(fd);
1736                 return;
1737         }
1738         inode_info(st, sizeof(st), &stb, v);
1739         lr = ((__int64_t)random() << 32) + random();
1740         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1741         off %= maxfsize;
1742         fl.l_whence = SEEK_SET;
1743         fl.l_start = off;
1744         fl.l_len = 0;
1745         e = xfsctl(f.path, fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
1746         if (v) {
1747                 printf("%d/%d: xfsctl(XFS_IOC_ALLOCSP64) %s%s %lld 0 %d\n",
1748                        procid, opno, f.path, st, (long long)off, e);
1749         }
1750         free_pathname(&f);
1751         close(fd);
1752 }
1753
1754 void
1755 attr_remove_f(int opno, long r)
1756 {
1757         attrlist_ent_t          *aep;
1758         attrlist_t              *alist;
1759         char                    *aname;
1760         char                    buf[4096];
1761         attrlist_cursor_t       cursor;
1762         int                     e;
1763         int                     ent;
1764         pathname_t              f;
1765         int                     total;
1766         int                     v;
1767         int                     which;
1768
1769         init_pathname(&f);
1770         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1771                 append_pathname(&f, ".");
1772         total = 0;
1773         bzero(&cursor, sizeof(cursor));
1774         do {
1775                 bzero(buf, sizeof(buf));
1776                 e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, &cursor);
1777                 check_cwd();
1778                 if (e)
1779                         break;
1780                 alist = (attrlist_t *)buf;
1781                 total += alist->al_count;
1782         } while (alist->al_more);
1783         if (total == 0) {
1784                 if (v)
1785                         printf("%d/%d: attr_remove - no attrs for %s\n",
1786                                 procid, opno, f.path);
1787                 free_pathname(&f);
1788                 return;
1789         }
1790         which = (int)(random() % total);
1791         bzero(&cursor, sizeof(cursor));
1792         ent = 0;
1793         aname = NULL;
1794         do {
1795                 bzero(buf, sizeof(buf));
1796                 e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, &cursor);
1797                 check_cwd();
1798                 if (e)
1799                         break;
1800                 alist = (attrlist_t *)buf;
1801                 if (which < ent + alist->al_count) {
1802                         aep = (attrlist_ent_t *)
1803                                 &buf[alist->al_offset[which - ent]];
1804                         aname = aep->a_name;
1805                         break;
1806                 }
1807                 ent += alist->al_count;
1808         } while (alist->al_more);
1809         if (aname == NULL) {
1810                 if (v)
1811                         printf(
1812                         "%d/%d: attr_remove - name %d not found at %s\n",
1813                                 procid, opno, which, f.path);
1814                 free_pathname(&f);
1815                 return;
1816         }
1817         e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0;
1818         check_cwd();
1819         if (v)
1820                 printf("%d/%d: attr_remove %s %s %d\n",
1821                         procid, opno, f.path, aname, e);
1822         free_pathname(&f);
1823 }
1824
1825 void
1826 attr_set_f(int opno, long r)
1827 {
1828         char            aname[10];
1829         char            *aval;
1830         int             e;
1831         pathname_t      f;
1832         int             len;
1833         static int      lengths[] = { 10, 100, 1000, 10000 };
1834         int             li;
1835         int             v;
1836
1837         init_pathname(&f);
1838         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1839                 append_pathname(&f, ".");
1840         sprintf(aname, "a%x", nameseq++);
1841         li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0])));
1842         len = (int)(random() % lengths[li]);
1843         if (len == 0)
1844                 len = 1;
1845         aval = malloc(len);
1846         memset(aval, nameseq & 0xff, len);
1847         e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ?
1848                 errno : 0;
1849         check_cwd();
1850         free(aval);
1851         if (v)
1852                 printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path,
1853                         aname, e);
1854         free_pathname(&f);
1855 }
1856
1857 void
1858 bulkstat_f(int opno, long r)
1859 {
1860         int             count;
1861         int             fd;
1862         __u64           last;
1863         int             nent;
1864         xfs_bstat_t     *t;
1865         __int64_t       total;
1866         xfs_fsop_bulkreq_t bsr;
1867
1868         last = 0;
1869         nent = (r % 999) + 2;
1870         t = malloc(nent * sizeof(*t));
1871         fd = open(".", O_RDONLY);
1872         total = 0;
1873
1874         bsr.lastip=&last;
1875         bsr.icount=nent;
1876         bsr.ubuffer=t;
1877         bsr.ocount=&count;
1878             
1879         while (xfsctl(".", fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
1880                 total += count;
1881         free(t);
1882         if (verbose)
1883                 printf("%d/%d: bulkstat nent %d total %lld\n",
1884                         procid, opno, nent, (long long)total);
1885         close(fd);
1886 }
1887
1888 void
1889 bulkstat1_f(int opno, long r)
1890 {
1891         int             e;
1892         pathname_t      f;
1893         int             fd;
1894         int             good;
1895         __u64           ino;
1896         struct stat64   s;
1897         xfs_bstat_t     t;
1898         int             v;
1899         xfs_fsop_bulkreq_t bsr;
1900         
1901
1902         good = random() & 1;
1903         if (good) {
1904                /* use an inode we know exists */
1905                 init_pathname(&f);
1906                 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1907                         append_pathname(&f, ".");
1908                 ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino;
1909                 check_cwd();
1910                 free_pathname(&f);
1911         } else {
1912                 /* 
1913                  * pick a random inode 
1914                  *
1915                  * note this can generate kernel warning messages
1916                  * since bulkstat_one will read the disk block that
1917                  * would contain a given inode even if that disk
1918                  * block doesn't contain inodes.
1919                  *
1920                  * this is detected later, but not until after the
1921                  * warning is displayed.
1922                  *
1923                  * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0"
1924                  *
1925                  */
1926                 ino = (ino64_t)r;
1927                 v = verbose;
1928         }
1929         fd = open(".", O_RDONLY);
1930         
1931         bsr.lastip=&ino;
1932         bsr.icount=1;
1933         bsr.ubuffer=&t;
1934         bsr.ocount=NULL;
1935         e = xfsctl(".", fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
1936         if (v)
1937                 printf("%d/%d: bulkstat1 %s ino %lld %d\n", 
1938                        procid, opno, good?"real":"random",
1939                        verifiable_log ? -1LL : (long long)ino, e);
1940         close(fd);
1941 }
1942
1943 void
1944 chown_f(int opno, long r)
1945 {
1946         int             e;
1947         pathname_t      f;
1948         int             nbits;
1949         uid_t           u;
1950         gid_t           g;
1951         int             v;
1952
1953         init_pathname(&f);
1954         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1955                 append_pathname(&f, ".");
1956         u = (uid_t)random();
1957         g = (gid_t)random();
1958         nbits = (int)(random() % idmodulo);
1959         u &= (1 << nbits) - 1;
1960         g &= (1 << nbits) - 1;
1961         e = lchown_path(&f, u, g) < 0 ? errno : 0;
1962         check_cwd();
1963         if (v)
1964                 printf("%d/%d: chown %s %d/%d %d\n", procid, opno, f.path, (int)u, (int)g, e);
1965         free_pathname(&f);
1966 }
1967
1968 void
1969 setxattr_f(int opno, long r)
1970 {
1971 #ifdef XFS_XFLAG_EXTSIZE
1972         struct fsxattr  fsx;
1973         int             fd;
1974         int             e;
1975         pathname_t      f;
1976         int             nbits;
1977         uint            p;
1978         int             v;
1979
1980         init_pathname(&f);
1981         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1982                 append_pathname(&f, ".");
1983         fd = open_path(&f, O_RDWR);
1984         e = fd < 0 ? errno : 0;
1985         check_cwd();
1986
1987         /* project ID */
1988         p = (uint)random();
1989         e = MIN(idmodulo, XFS_PROJIDMODULO_MAX);
1990         nbits = (int)(random() % e);
1991         p &= (1 << nbits) - 1;
1992
1993         if ((e = xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &fsx)) == 0) {
1994                 fsx.fsx_projid = p;
1995                 e = xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &fsx);
1996         }
1997         if (v)
1998                 printf("%d/%d: setxattr %s %u %d\n", procid, opno, f.path, p, e);
1999         free_pathname(&f);
2000         close(fd);
2001 #endif
2002 }
2003
2004 void
2005 creat_f(int opno, long r)
2006 {
2007         struct fsxattr  a;
2008         int             e;
2009         int             e1;
2010         int             extsize;
2011         pathname_t      f;
2012         int             fd;
2013         fent_t          *fep;
2014         int             id;
2015         int             parid;
2016         int             type;
2017         int             v;
2018         int             v1;
2019
2020         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
2021                 parid = -1;
2022         else
2023                 parid = fep->id;
2024         init_pathname(&f);
2025         e1 = (random() % 100);
2026         type = rtpct ? ((e1 > rtpct) ? FT_REG : FT_RTF) : FT_REG;
2027 #ifdef NOTYET
2028         if (type == FT_RTF)     /* rt always gets an extsize */
2029                 extsize = (random() % 10) + 1;
2030         else if (e1 < 10)       /* one-in-ten get an extsize */
2031                 extsize = random() % 1024;
2032         else
2033 #endif
2034                 extsize = 0;
2035         e = generate_fname(fep, type, &f, &id, &v);
2036         v |= v1;
2037         if (!e) {
2038                 if (v) {
2039                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
2040                         printf("%d/%d: creat - no filename from %s\n",
2041                                 procid, opno, f.path);
2042                 }
2043                 free_pathname(&f);
2044                 return;
2045         }
2046         fd = creat_path(&f, 0666);
2047         e = fd < 0 ? errno : 0;
2048         e1 = 0;
2049         check_cwd();
2050         if (fd >= 0) {
2051                 if (extsize &&
2052                     xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
2053                         if (type == FT_RTF) {
2054                                 a.fsx_xflags |= XFS_XFLAG_REALTIME;
2055                                 a.fsx_extsize = extsize *
2056                                                 geom.rtextsize * geom.blocksize;
2057 #ifdef NOTYET
2058                         } else if (extsize) {
2059                                 a.fsx_xflags |= XFS_XFLAG_EXTSIZE;
2060                                 a.fsx_extsize = extsize * geom.blocksize;
2061 #endif
2062                         }
2063                         if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
2064                                 e1 = errno;
2065                 }
2066                 add_to_flist(type, id, parid);
2067                 close(fd);
2068         }
2069         if (v) {
2070                 printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
2071                         extsize ? a.fsx_extsize : 0, e, e1);
2072                 printf("%d/%d: creat add id=%d,parent=%d\n", procid, opno, id, parid);
2073         }
2074         free_pathname(&f);
2075 }
2076
2077 void
2078 dread_f(int opno, long r)
2079 {
2080         __int64_t       align;
2081         char            *buf;
2082         struct dioattr  diob;
2083         int             e;
2084         pathname_t      f;
2085         int             fd;
2086         size_t          len;
2087         __int64_t       lr;
2088         off64_t         off;
2089         struct stat64   stb;
2090         int             v;
2091         char            st[1024];
2092         char            *dio_env;
2093
2094         init_pathname(&f);
2095         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2096                 if (v)
2097                         printf("%d/%d: dread - no filename\n", procid, opno);
2098                 free_pathname(&f);
2099                 return;
2100         }
2101         fd = open_path(&f, O_RDONLY|O_DIRECT);
2102         e = fd < 0 ? errno : 0;
2103         check_cwd();
2104         if (fd < 0) {
2105                 if (v)
2106                         printf("%d/%d: dread - open %s failed %d\n",
2107                                 procid, opno, f.path, e);
2108                 free_pathname(&f);
2109                 return;
2110         }
2111         if (fstat64(fd, &stb) < 0) {
2112                 if (v)
2113                         printf("%d/%d: dread - fstat64 %s failed %d\n",
2114                                procid, opno, f.path, errno);
2115                 free_pathname(&f);
2116                 close(fd);
2117                 return;
2118         }
2119         inode_info(st, sizeof(st), &stb, v);
2120         if (stb.st_size == 0) {
2121                 if (v)
2122                         printf("%d/%d: dread - %s%s zero size\n", procid, opno,
2123                                f.path, st);
2124                 free_pathname(&f);
2125                 close(fd);
2126                 return;
2127         }
2128         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
2129                 if (v)
2130                         printf(
2131                         "%d/%d: dread - xfsctl(XFS_IOC_DIOINFO) %s%s failed %d\n",
2132                                 procid, opno, f.path, st, errno);
2133                 free_pathname(&f);
2134                 close(fd);
2135                 return;
2136         }
2137
2138         dio_env = getenv("XFS_DIO_MIN");
2139         if (dio_env)
2140                 diob.d_mem = diob.d_miniosz = atoi(dio_env);
2141
2142         align = (__int64_t)diob.d_miniosz;
2143         lr = ((__int64_t)random() << 32) + random();
2144         off = (off64_t)(lr % stb.st_size);
2145         off -= (off % align);
2146         lseek64(fd, off, SEEK_SET);
2147         len = (random() % FILELEN_MAX) + 1;
2148         len -= (len % align);
2149         if (len <= 0)
2150                 len = align;
2151         else if (len > diob.d_maxiosz) 
2152                 len = diob.d_maxiosz;
2153         buf = memalign(diob.d_mem, len);
2154         e = read(fd, buf, len) < 0 ? errno : 0;
2155         free(buf);
2156         if (v)
2157                 printf("%d/%d: dread %s%s [%lld,%d] %d\n",
2158                        procid, opno, f.path, st, (long long)off, (int)len, e);
2159         free_pathname(&f);
2160         close(fd);
2161 }
2162
2163 void
2164 dwrite_f(int opno, long r)
2165 {
2166         __int64_t       align;
2167         char            *buf;
2168         struct dioattr  diob;
2169         int             e;
2170         pathname_t      f;
2171         int             fd;
2172         size_t          len;
2173         __int64_t       lr;
2174         off64_t         off;
2175         struct stat64   stb;
2176         int             v;
2177         char            st[1024];
2178         char            *dio_env;
2179
2180         init_pathname(&f);
2181         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2182                 if (v)
2183                         printf("%d/%d: dwrite - no filename\n", procid, opno);
2184                 free_pathname(&f);
2185                 return;
2186         }
2187         fd = open_path(&f, O_WRONLY|O_DIRECT);
2188         e = fd < 0 ? errno : 0;
2189         check_cwd();
2190         if (fd < 0) {
2191                 if (v)
2192                         printf("%d/%d: dwrite - open %s failed %d\n",
2193                                 procid, opno, f.path, e);
2194                 free_pathname(&f);
2195                 return;
2196         }
2197         if (fstat64(fd, &stb) < 0) {
2198                 if (v)
2199                         printf("%d/%d: dwrite - fstat64 %s failed %d\n",
2200                                 procid, opno, f.path, errno);
2201                 free_pathname(&f);
2202                 close(fd);
2203                 return;
2204         }
2205         inode_info(st, sizeof(st), &stb, v);
2206         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
2207                 if (v)
2208                         printf("%d/%d: dwrite - xfsctl(XFS_IOC_DIOINFO)"
2209                                 " %s%s failed %d\n",
2210                                procid, opno, f.path, st, errno);
2211                 free_pathname(&f);
2212                 close(fd);
2213                 return;
2214         }
2215
2216         dio_env = getenv("XFS_DIO_MIN");
2217         if (dio_env)
2218                 diob.d_mem = diob.d_miniosz = atoi(dio_env);
2219
2220         align = (__int64_t)diob.d_miniosz;
2221         lr = ((__int64_t)random() << 32) + random();
2222         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2223         off -= (off % align);
2224         lseek64(fd, off, SEEK_SET);
2225         len = (random() % FILELEN_MAX) + 1;
2226         len -= (len % align);
2227         if (len <= 0)
2228                 len = align;
2229         else if (len > diob.d_maxiosz) 
2230                 len = diob.d_maxiosz;
2231         buf = memalign(diob.d_mem, len);
2232         off %= maxfsize;
2233         lseek64(fd, off, SEEK_SET);
2234         memset(buf, nameseq & 0xff, len);
2235         e = write(fd, buf, len) < 0 ? errno : 0;
2236         free(buf);
2237         if (v)
2238                 printf("%d/%d: dwrite %s%s [%lld,%d] %d\n",
2239                        procid, opno, f.path, st, (long long)off, (int)len, e);
2240         free_pathname(&f);
2241         close(fd);
2242 }
2243
2244
2245 #ifdef HAVE_LINUX_FALLOC_H
2246 struct print_flags falloc_flags [] = {
2247         { FALLOC_FL_KEEP_SIZE, "KEEP_SIZE"},
2248         { FALLOC_FL_PUNCH_HOLE, "PUNCH_HOLE"},
2249         { FALLOC_FL_NO_HIDE_STALE, "NO_HIDE_STALE"},
2250         { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"},
2251         { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"},
2252         { FALLOC_FL_INSERT_RANGE, "INSERT_RANGE"},
2253         { -1, NULL}
2254 };
2255
2256 #define translate_falloc_flags(mode)    \
2257         ({translate_flags(mode, "|", falloc_flags);})
2258 #endif
2259
2260 void
2261 do_fallocate(int opno, long r, int mode)
2262 {
2263 #ifdef HAVE_LINUX_FALLOC_H
2264         int             e;
2265         pathname_t      f;
2266         int             fd;
2267         __int64_t       lr;
2268         off64_t         off;
2269         off64_t         len;
2270         struct stat64   stb;
2271         int             v;
2272         char            st[1024];
2273
2274         init_pathname(&f);
2275         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2276                 if (v)
2277                         printf("%d/%d: do_fallocate - no filename\n", procid, opno);
2278                 free_pathname(&f);
2279                 return;
2280         }
2281         fd = open_path(&f, O_RDWR);
2282         if (fd < 0) {
2283                 if (v)
2284                         printf("%d/%d: do_fallocate - open %s failed %d\n",
2285                                 procid, opno, f.path, errno);
2286                 free_pathname(&f);
2287                 return;
2288         }
2289         check_cwd();
2290         if (fstat64(fd, &stb) < 0) {
2291                 if (v)
2292                         printf("%d/%d: do_fallocate - fstat64 %s failed %d\n",
2293                                 procid, opno, f.path, errno);
2294                 free_pathname(&f);
2295                 close(fd);
2296                 return;
2297         }
2298         inode_info(st, sizeof(st), &stb, v);
2299         lr = ((__int64_t)random() << 32) + random();
2300         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2301         off %= maxfsize;
2302         len = (off64_t)(random() % (1024 * 1024));
2303         /*
2304          * Collapse/insert range requires off and len to be block aligned,
2305          * make it more likely to be the case.
2306          */
2307         if ((mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)) &&
2308                 (opno % 2)) {
2309                 off = ((off + stb.st_blksize - 1) & ~(stb.st_blksize - 1));
2310                 len = ((len + stb.st_blksize - 1) & ~(stb.st_blksize - 1));
2311         }
2312         mode |= FALLOC_FL_KEEP_SIZE & random();
2313         e = fallocate(fd, mode, (loff_t)off, (loff_t)len) < 0 ? errno : 0;
2314         if (v)
2315                 printf("%d/%d: fallocate(%s) %s %st %lld %lld %d\n",
2316                        procid, opno, translate_falloc_flags(mode),
2317                        f.path, st, (long long)off, (long long)len, e);
2318         free_pathname(&f);
2319         close(fd);
2320 #endif
2321 }
2322
2323 void
2324 fallocate_f(int opno, long r)
2325 {
2326 #ifdef HAVE_LINUX_FALLOC_H
2327         do_fallocate(opno, r, 0);
2328 #endif
2329 }
2330
2331 void
2332 fdatasync_f(int opno, long r)
2333 {
2334         int             e;
2335         pathname_t      f;
2336         int             fd;
2337         int             v;
2338
2339         init_pathname(&f);
2340         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2341                 if (v)
2342                         printf("%d/%d: fdatasync - no filename\n",
2343                                 procid, opno);
2344                 free_pathname(&f);
2345                 return;
2346         }
2347         fd = open_path(&f, O_WRONLY);
2348         e = fd < 0 ? errno : 0;
2349         check_cwd();
2350         if (fd < 0) {
2351                 if (v)
2352                         printf("%d/%d: fdatasync - open %s failed %d\n",
2353                                 procid, opno, f.path, e);
2354                 free_pathname(&f);
2355                 return;
2356         }
2357         e = fdatasync(fd) < 0 ? errno : 0;
2358         if (v)
2359                 printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e);
2360         free_pathname(&f);
2361         close(fd);
2362 }
2363
2364 #ifdef HAVE_LINUX_FIEMAP_H
2365 struct print_flags fiemap_flags[] = {
2366         { FIEMAP_FLAG_SYNC, "SYNC"},
2367         { FIEMAP_FLAG_XATTR, "XATTR"},
2368         { -1, NULL}
2369 };
2370
2371 #define translate_fiemap_flags(mode)    \
2372         ({translate_flags(mode, "|", fiemap_flags);})
2373 #endif
2374
2375 void
2376 fiemap_f(int opno, long r)
2377 {
2378 #ifdef HAVE_LINUX_FIEMAP_H
2379         int             e;
2380         pathname_t      f;
2381         int             fd;
2382         __int64_t       lr;
2383         off64_t         off;
2384         struct stat64   stb;
2385         int             v;
2386         char            st[1024];
2387         int blocks_to_map;
2388         struct fiemap *fiemap;
2389
2390         init_pathname(&f);
2391         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2392                 if (v)
2393                         printf("%d/%d: fiemap - no filename\n", procid, opno);
2394                 free_pathname(&f);
2395                 return;
2396         }
2397         fd = open_path(&f, O_RDWR);
2398         e = fd < 0 ? errno : 0;
2399         check_cwd();
2400         if (fd < 0) {
2401                 if (v)
2402                         printf("%d/%d: fiemap - open %s failed %d\n",
2403                                 procid, opno, f.path, e);
2404                 free_pathname(&f);
2405                 return;
2406         }
2407         if (fstat64(fd, &stb) < 0) {
2408                 if (v)
2409                         printf("%d/%d: fiemap - fstat64 %s failed %d\n",
2410                                 procid, opno, f.path, errno);
2411                 free_pathname(&f);
2412                 close(fd);
2413                 return;
2414         }
2415         inode_info(st, sizeof(st), &stb, v);
2416         blocks_to_map = random() & 0xffff;
2417         fiemap = (struct fiemap *)malloc(sizeof(struct fiemap) +
2418                         (blocks_to_map * sizeof(struct fiemap_extent)));
2419         if (!fiemap) {
2420                 if (v)
2421                         printf("%d/%d: malloc failed \n", procid, opno);
2422                 free_pathname(&f);
2423                 close(fd);
2424                 return;
2425         }
2426         lr = ((__int64_t)random() << 32) + random();
2427         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2428         off %= maxfsize;
2429         fiemap->fm_flags = random() & (FIEMAP_FLAGS_COMPAT | 0x10000);
2430         fiemap->fm_extent_count = blocks_to_map;
2431         fiemap->fm_mapped_extents = random() & 0xffff;
2432         fiemap->fm_start = off;
2433         fiemap->fm_length = ((__int64_t)random() << 32) + random();
2434
2435         e = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
2436         if (v)
2437                 printf("%d/%d: ioctl(FIEMAP) %s%s %lld %lld (%s) %d\n",
2438                        procid, opno, f.path, st, (long long)fiemap->fm_start,
2439                        (long long) fiemap->fm_length,
2440                        translate_fiemap_flags(fiemap->fm_flags), e);
2441         free(fiemap);
2442         free_pathname(&f);
2443         close(fd);
2444 #endif
2445 }
2446
2447 void
2448 freesp_f(int opno, long r)
2449 {
2450         int             e;
2451         pathname_t      f;
2452         int             fd;
2453         struct xfs_flock64      fl;
2454         __int64_t       lr;
2455         off64_t         off;
2456         struct stat64   stb;
2457         int             v;
2458         char            st[1024];
2459
2460         init_pathname(&f);
2461         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2462                 if (v)
2463                         printf("%d/%d: freesp - no filename\n", procid, opno);
2464                 free_pathname(&f);
2465                 return;
2466         }
2467         fd = open_path(&f, O_RDWR);
2468         e = fd < 0 ? errno : 0;
2469         check_cwd();
2470         if (fd < 0) {
2471                 if (v)
2472                         printf("%d/%d: freesp - open %s failed %d\n",
2473                                 procid, opno, f.path, e);
2474                 free_pathname(&f);
2475                 return;
2476         }
2477         if (fstat64(fd, &stb) < 0) {
2478                 if (v)
2479                         printf("%d/%d: freesp - fstat64 %s failed %d\n",
2480                                 procid, opno, f.path, errno);
2481                 free_pathname(&f);
2482                 close(fd);
2483                 return;
2484         }
2485         inode_info(st, sizeof(st), &stb, v);
2486         lr = ((__int64_t)random() << 32) + random();
2487         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2488         off %= maxfsize;
2489         fl.l_whence = SEEK_SET;
2490         fl.l_start = off;
2491         fl.l_len = 0;
2492         e = xfsctl(f.path, fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
2493         if (v)
2494                 printf("%d/%d: xfsctl(XFS_IOC_FREESP64) %s%s %lld 0 %d\n",
2495                        procid, opno, f.path, st, (long long)off, e);
2496         free_pathname(&f);
2497         close(fd);
2498 }
2499
2500 void
2501 fsync_f(int opno, long r)
2502 {
2503         int             e;
2504         pathname_t      f;
2505         int             fd;
2506         int             v;
2507
2508         init_pathname(&f);
2509         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2510                 if (v)
2511                         printf("%d/%d: fsync - no filename\n", procid, opno);
2512                 free_pathname(&f);
2513                 return;
2514         }
2515         fd = open_path(&f, O_WRONLY);
2516         e = fd < 0 ? errno : 0;
2517         check_cwd();
2518         if (fd < 0) {
2519                 if (v)
2520                         printf("%d/%d: fsync - open %s failed %d\n",
2521                                 procid, opno, f.path, e);
2522                 free_pathname(&f);
2523                 return;
2524         }
2525         e = fsync(fd) < 0 ? errno : 0;
2526         if (v)
2527                 printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e);
2528         free_pathname(&f);
2529         close(fd);
2530 }
2531
2532 void
2533 getattr_f(int opno, long r)
2534 {
2535         int             fd;
2536         int             e;
2537         pathname_t      f;
2538         uint            fl;
2539         int             v;
2540
2541         init_pathname(&f);
2542         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2543                 append_pathname(&f, ".");
2544         fd = open_path(&f, O_RDWR);
2545         e = fd < 0 ? errno : 0;
2546         check_cwd();
2547
2548         e = ioctl(fd, FS_IOC_GETFLAGS, &fl);
2549         if (v)
2550                 printf("%d/%d: getattr %s %u %d\n", procid, opno, f.path, fl, e);
2551         free_pathname(&f);
2552         close(fd);
2553 }
2554
2555 void
2556 getdents_f(int opno, long r)
2557 {
2558         DIR             *dir;
2559         pathname_t      f;
2560         int             v;
2561
2562         init_pathname(&f);
2563         if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
2564                 append_pathname(&f, ".");
2565         dir = opendir_path(&f);
2566         check_cwd();
2567         if (dir == NULL) {
2568                 if (v)
2569                         printf("%d/%d: getdents - can't open %s\n",
2570                                 procid, opno, f.path);
2571                 free_pathname(&f);
2572                 return;
2573         }
2574         while (readdir64(dir) != NULL)
2575                 continue;
2576         if (v)
2577                 printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
2578         free_pathname(&f);
2579         closedir(dir);
2580 }
2581
2582 void
2583 link_f(int opno, long r)
2584 {
2585         int             e;
2586         pathname_t      f;
2587         fent_t          *fep;
2588         flist_t         *flp;
2589         int             id;
2590         pathname_t      l;
2591         int             parid;
2592         int             v;
2593         int             v1;
2594
2595         init_pathname(&f);
2596         if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
2597                 if (v1)
2598                         printf("%d/%d: link - no file\n", procid, opno);
2599                 free_pathname(&f);
2600                 return;
2601         }
2602         if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
2603                 parid = -1;
2604         else
2605                 parid = fep->id;
2606         v |= v1;
2607         init_pathname(&l);
2608         e = generate_fname(fep, flp - flist, &l, &id, &v1);
2609         v |= v1;
2610         if (!e) {
2611                 if (v) {
2612                         (void)fent_to_name(&l, &flist[FT_DIR], fep);
2613                         printf("%d/%d: link - no filename from %s\n",
2614                                 procid, opno, l.path);
2615                 }
2616                 free_pathname(&l);
2617                 free_pathname(&f);
2618                 return;
2619         }
2620         e = link_path(&f, &l) < 0 ? errno : 0;
2621         check_cwd();
2622         if (e == 0)
2623                 add_to_flist(flp - flist, id, parid);
2624         if (v) {
2625                 printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
2626                         e);
2627                 printf("%d/%d: link add id=%d,parent=%d\n", procid, opno, id, parid);
2628         }
2629         free_pathname(&l);
2630         free_pathname(&f);
2631 }
2632
2633 void
2634 mkdir_f(int opno, long r)
2635 {
2636         int             e;
2637         pathname_t      f;
2638         fent_t          *fep;
2639         int             id;
2640         int             parid;
2641         int             v;
2642         int             v1;
2643
2644         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2645                 parid = -1;
2646         else
2647                 parid = fep->id;
2648         init_pathname(&f);
2649         e = generate_fname(fep, FT_DIR, &f, &id, &v1);
2650         v |= v1;
2651         if (!e) {
2652                 if (v) {
2653                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
2654                         printf("%d/%d: mkdir - no filename from %s\n",
2655                                 procid, opno, f.path);
2656                 }
2657                 free_pathname(&f);
2658                 return;
2659         }
2660         e = mkdir_path(&f, 0777) < 0 ? errno : 0;
2661         check_cwd();
2662         if (e == 0)
2663                 add_to_flist(FT_DIR, id, parid);
2664         if (v) {
2665                 printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
2666                 printf("%d/%d: mkdir add id=%d,parent=%d\n", procid, opno, id, parid);
2667         }
2668         free_pathname(&f);
2669 }
2670
2671 void
2672 mknod_f(int opno, long r)
2673 {
2674         int             e;
2675         pathname_t      f;
2676         fent_t          *fep;
2677         int             id;
2678         int             parid;
2679         int             v;
2680         int             v1;
2681
2682         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2683                 parid = -1;
2684         else
2685                 parid = fep->id;
2686         init_pathname(&f);
2687         e = generate_fname(fep, FT_DEV, &f, &id, &v1);
2688         v |= v1;
2689         if (!e) {
2690                 if (v) {
2691                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
2692                         printf("%d/%d: mknod - no filename from %s\n",
2693                                 procid, opno, f.path);
2694                 }
2695                 free_pathname(&f);
2696                 return;
2697         }
2698         e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
2699         check_cwd();
2700         if (e == 0)
2701                 add_to_flist(FT_DEV, id, parid);
2702         if (v) {
2703                 printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
2704                 printf("%d/%d: mknod add id=%d,parent=%d\n", procid, opno, id, parid);
2705         }
2706         free_pathname(&f);
2707 }
2708
2709 #ifdef HAVE_SYS_MMAN_H
2710 struct print_flags mmap_flags[] = {
2711         { MAP_SHARED, "SHARED"},
2712         { MAP_PRIVATE, "PRIVATE"},
2713         { -1, NULL}
2714 };
2715
2716 #define translate_mmap_flags(flags)       \
2717         ({translate_flags(flags, "|", mmap_flags);})
2718 #endif
2719
2720 void
2721 do_mmap(int opno, long r, int prot)
2722 {
2723 #ifdef HAVE_SYS_MMAN_H
2724         char            *addr;
2725         int             e;
2726         pathname_t      f;
2727         int             fd;
2728         size_t          len;
2729         __int64_t       lr;
2730         off64_t         off;
2731         int             flags;
2732         struct stat64   stb;
2733         int             v;
2734         char            st[1024];
2735         sigjmp_buf      sigbus_jmpbuf;
2736
2737         init_pathname(&f);
2738         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2739                 if (v)
2740                         printf("%d/%d: do_mmap - no filename\n", procid, opno);
2741                 free_pathname(&f);
2742                 return;
2743         }
2744         fd = open_path(&f, O_RDWR);
2745         e = fd < 0 ? errno : 0;
2746         check_cwd();
2747         if (fd < 0) {
2748                 if (v)
2749                         printf("%d/%d: do_mmap - open %s failed %d\n",
2750                                procid, opno, f.path, e);
2751                 free_pathname(&f);
2752                 return;
2753         }
2754         if (fstat64(fd, &stb) < 0) {
2755                 if (v)
2756                         printf("%d/%d: do_mmap - fstat64 %s failed %d\n",
2757                                procid, opno, f.path, errno);
2758                 free_pathname(&f);
2759                 close(fd);
2760                 return;
2761         }
2762         inode_info(st, sizeof(st), &stb, v);
2763         if (stb.st_size == 0) {
2764                 if (v)
2765                         printf("%d/%d: do_mmap - %s%s zero size\n", procid, opno,
2766                                f.path, st);
2767                 free_pathname(&f);
2768                 close(fd);
2769                 return;
2770         }
2771
2772         lr = ((__int64_t)random() << 32) + random();
2773         off = (off64_t)(lr % stb.st_size);
2774         off &= (off64_t)(~(sysconf(_SC_PAGE_SIZE) - 1));
2775         len = (size_t)(random() % MIN(stb.st_size - off, FILELEN_MAX)) + 1;
2776
2777         flags = (random() % 2) ? MAP_SHARED : MAP_PRIVATE;
2778         addr = mmap(NULL, len, prot, flags, fd, off);
2779         e = (addr == MAP_FAILED) ? errno : 0;
2780         if (e) {
2781                 if (v)
2782                         printf("%d/%d: do_mmap - mmap failed %s%s [%lld,%d,%s] %d\n",
2783                                procid, opno, f.path, st, (long long)off,
2784                                (int)len, translate_mmap_flags(flags), e);
2785                 free_pathname(&f);
2786                 close(fd);
2787                 return;
2788         }
2789
2790         if (prot & PROT_WRITE) {
2791                 if ((e = sigsetjmp(sigbus_jmpbuf, 1)) == 0) {
2792                         sigbus_jmp = &sigbus_jmpbuf;
2793                         memset(addr, nameseq & 0xff, len);
2794                 }
2795         } else {
2796                 char *buf;
2797                 if ((buf = malloc(len)) != NULL) {
2798                         memcpy(buf, addr, len);
2799                         free(buf);
2800                 }
2801         }
2802         munmap(addr, len);
2803         /* set NULL to stop other functions from doing siglongjmp */
2804         sigbus_jmp = NULL;
2805
2806         if (v)
2807                 printf("%d/%d: %s %s%s [%lld,%d,%s] %s\n",
2808                        procid, opno, (prot & PROT_WRITE) ? "mwrite" : "mread",
2809                        f.path, st, (long long)off, (int)len,
2810                        translate_mmap_flags(flags),
2811                        (e == 0) ? "0" : "Bus error");
2812
2813         free_pathname(&f);
2814         close(fd);
2815 #endif
2816 }
2817
2818 void
2819 mread_f(int opno, long r)
2820 {
2821 #ifdef HAVE_SYS_MMAN_H
2822         do_mmap(opno, r, PROT_READ);
2823 #endif
2824 }
2825
2826 void
2827 mwrite_f(int opno, long r)
2828 {
2829 #ifdef HAVE_SYS_MMAN_H
2830         do_mmap(opno, r, PROT_WRITE);
2831 #endif
2832 }
2833
2834 void
2835 punch_f(int opno, long r)
2836 {
2837 #ifdef HAVE_LINUX_FALLOC_H
2838         do_fallocate(opno, r, FALLOC_FL_PUNCH_HOLE);
2839 #endif
2840 }
2841
2842 void
2843 zero_f(int opno, long r)
2844 {
2845 #ifdef HAVE_LINUX_FALLOC_H
2846         do_fallocate(opno, r, FALLOC_FL_ZERO_RANGE);
2847 #endif
2848 }
2849
2850 void
2851 collapse_f(int opno, long r)
2852 {
2853 #ifdef HAVE_LINUX_FALLOC_H
2854         do_fallocate(opno, r, FALLOC_FL_COLLAPSE_RANGE);
2855 #endif
2856 }
2857
2858 void
2859 insert_f(int opno, long r)
2860 {
2861 #ifdef HAVE_LINUX_FALLOC_H
2862         do_fallocate(opno, r, FALLOC_FL_INSERT_RANGE);
2863 #endif
2864 }
2865
2866 void
2867 read_f(int opno, long r)
2868 {
2869         char            *buf;
2870         int             e;
2871         pathname_t      f;
2872         int             fd;
2873         size_t          len;
2874         __int64_t       lr;
2875         off64_t         off;
2876         struct stat64   stb;
2877         int             v;
2878         char            st[1024];
2879
2880         init_pathname(&f);
2881         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2882                 if (v)
2883                         printf("%d/%d: read - no filename\n", procid, opno);
2884                 free_pathname(&f);
2885                 return;
2886         }
2887         fd = open_path(&f, O_RDONLY);
2888         e = fd < 0 ? errno : 0;
2889         check_cwd();
2890         if (fd < 0) {
2891                 if (v)
2892                         printf("%d/%d: read - open %s failed %d\n",
2893                                 procid, opno, f.path, e);
2894                 free_pathname(&f);
2895                 return;
2896         }
2897         if (fstat64(fd, &stb) < 0) {
2898                 if (v)
2899                         printf("%d/%d: read - fstat64 %s failed %d\n",
2900                                 procid, opno, f.path, errno);
2901                 free_pathname(&f);
2902                 close(fd);
2903                 return;
2904         }
2905         inode_info(st, sizeof(st), &stb, v);
2906         if (stb.st_size == 0) {
2907                 if (v)
2908                         printf("%d/%d: read - %s%s zero size\n", procid, opno,
2909                                f.path, st);
2910                 free_pathname(&f);
2911                 close(fd);
2912                 return;
2913         }
2914         lr = ((__int64_t)random() << 32) + random();
2915         off = (off64_t)(lr % stb.st_size);
2916         lseek64(fd, off, SEEK_SET);
2917         len = (random() % FILELEN_MAX) + 1;
2918         buf = malloc(len);
2919         e = read(fd, buf, len) < 0 ? errno : 0;
2920         free(buf);
2921         if (v)
2922                 printf("%d/%d: read %s%s [%lld,%d] %d\n",
2923                        procid, opno, f.path, st, (long long)off, (int)len, e);
2924         free_pathname(&f);
2925         close(fd);
2926 }
2927
2928 void
2929 readlink_f(int opno, long r)
2930 {
2931         char            buf[PATH_MAX];
2932         int             e;
2933         pathname_t      f;
2934         int             v;
2935
2936         init_pathname(&f);
2937         if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
2938                 if (v)
2939                         printf("%d/%d: readlink - no filename\n", procid, opno);
2940                 free_pathname(&f);
2941                 return;
2942         }
2943         e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
2944         check_cwd();
2945         if (v)
2946                 printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e);
2947         free_pathname(&f);
2948 }
2949
2950 void
2951 rename_f(int opno, long r)
2952 {
2953         fent_t          *dfep;
2954         int             e;
2955         pathname_t      f;
2956         fent_t          *fep;
2957         flist_t         *flp;
2958         int             id;
2959         pathname_t      newf;
2960         int             oldid;
2961         int             parid;
2962         int             v;
2963         int             v1;
2964
2965         /* get an existing path for the source of the rename */
2966         init_pathname(&f);
2967         if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
2968                 if (v1)
2969                         printf("%d/%d: rename - no filename\n", procid, opno);
2970                 free_pathname(&f);
2971                 return;
2972         }
2973
2974         /* get an existing directory for the destination parent directory name */
2975         if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
2976                 parid = -1;
2977         else
2978                 parid = dfep->id;
2979         v |= v1;
2980
2981         /* generate a new path using an existing parent directory in name */
2982         init_pathname(&newf);
2983         e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
2984         v |= v1;
2985         if (!e) {
2986                 if (v) {
2987                         (void)fent_to_name(&f, &flist[FT_DIR], dfep);
2988                         printf("%d/%d: rename - no filename from %s\n",
2989                                 procid, opno, f.path);
2990                 }
2991                 free_pathname(&newf);
2992                 free_pathname(&f);
2993                 return;
2994         }
2995         e = rename_path(&f, &newf) < 0 ? errno : 0;
2996         check_cwd();
2997         if (e == 0) {
2998                 if (flp - flist == FT_DIR) {
2999                         oldid = fep->id;
3000                         fix_parent(oldid, id);
3001                 }
3002                 del_from_flist(flp - flist, fep - flp->fents);
3003                 add_to_flist(flp - flist, id, parid);
3004         }
3005         if (v) {
3006                 printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
3007                         newf.path, e);
3008                 if (e == 0) {
3009                         printf("%d/%d: rename del entry: id=%d,parent=%d\n",
3010                                 procid, opno, fep->id, fep->parent);
3011                         printf("%d/%d: rename add entry: id=%d,parent=%d\n",
3012                                 procid, opno, id, parid);
3013                 }
3014         }
3015         free_pathname(&newf);
3016         free_pathname(&f);
3017 }
3018
3019 void
3020 resvsp_f(int opno, long r)
3021 {
3022         int             e;
3023         pathname_t      f;
3024         int             fd;
3025         struct xfs_flock64      fl;
3026         __int64_t       lr;
3027         off64_t         off;
3028         struct stat64   stb;
3029         int             v;
3030         char            st[1024];
3031
3032         init_pathname(&f);
3033         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3034                 if (v)
3035                         printf("%d/%d: resvsp - no filename\n", procid, opno);
3036                 free_pathname(&f);
3037                 return;
3038         }
3039         fd = open_path(&f, O_RDWR);
3040         e = fd < 0 ? errno : 0;
3041         check_cwd();
3042         if (fd < 0) {
3043                 if (v)
3044                         printf("%d/%d: resvsp - open %s failed %d\n",
3045                                 procid, opno, f.path, e);
3046                 free_pathname(&f);
3047                 return;
3048         }
3049         if (fstat64(fd, &stb) < 0) {
3050                 if (v)
3051                         printf("%d/%d: resvsp - fstat64 %s failed %d\n",
3052                                 procid, opno, f.path, errno);
3053                 free_pathname(&f);
3054                 close(fd);
3055                 return;
3056         }
3057         inode_info(st, sizeof(st), &stb, v);
3058         lr = ((__int64_t)random() << 32) + random();
3059         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3060         off %= maxfsize;
3061         fl.l_whence = SEEK_SET;
3062         fl.l_start = off;
3063         fl.l_len = (off64_t)(random() % (1024 * 1024));
3064         e = xfsctl(f.path, fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
3065         if (v)
3066                 printf("%d/%d: xfsctl(XFS_IOC_RESVSP64) %s%s %lld %lld %d\n",
3067                        procid, opno, f.path, st,
3068                         (long long)off, (long long)fl.l_len, e);
3069         free_pathname(&f);
3070         close(fd);
3071 }
3072
3073 void
3074 rmdir_f(int opno, long r)
3075 {
3076         int             e;
3077         pathname_t      f;
3078         fent_t          *fep;
3079         int             v;
3080
3081         init_pathname(&f);
3082         if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
3083                 if (v)
3084                         printf("%d/%d: rmdir - no directory\n", procid, opno);
3085                 free_pathname(&f);
3086                 return;
3087         }
3088         e = rmdir_path(&f) < 0 ? errno : 0;
3089         check_cwd();
3090         if (e == 0)
3091                 del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
3092         if (v) {
3093                 printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e);
3094                 if (e == 0)
3095                         printf("%d/%d: rmdir del entry: id=%d,parent=%d\n",
3096                                 procid, opno, fep->id, fep->parent);
3097         }
3098         free_pathname(&f);
3099 }
3100
3101 void
3102 setattr_f(int opno, long r)
3103 {
3104         int             fd;
3105         int             e;
3106         pathname_t      f;
3107         uint            fl;
3108         int             v;
3109
3110         init_pathname(&f);
3111         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
3112                 append_pathname(&f, ".");
3113         fd = open_path(&f, O_RDWR);
3114         e = fd < 0 ? errno : 0;
3115         check_cwd();
3116
3117         fl = attr_mask & (uint)random();
3118         e = ioctl(fd, FS_IOC_SETFLAGS, &fl);
3119         if (v)
3120                 printf("%d/%d: setattr %s %x %d\n", procid, opno, f.path, fl, e);
3121         free_pathname(&f);
3122         close(fd);
3123 }
3124
3125 void
3126 stat_f(int opno, long r)
3127 {
3128         int             e;
3129         pathname_t      f;
3130         struct stat64   stb;
3131         int             v;
3132
3133         init_pathname(&f);
3134         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
3135                 if (v)
3136                         printf("%d/%d: stat - no entries\n", procid, opno);
3137                 free_pathname(&f);
3138                 return;
3139         }
3140         e = lstat64_path(&f, &stb) < 0 ? errno : 0;
3141         check_cwd();
3142         if (v)
3143                 printf("%d/%d: stat %s %d\n", procid, opno, f.path, e);
3144         free_pathname(&f);
3145 }
3146
3147 void
3148 symlink_f(int opno, long r)
3149 {
3150         int             e;
3151         pathname_t      f;
3152         fent_t          *fep;
3153         int             i;
3154         int             id;
3155         int             len;
3156         int             parid;
3157         int             v;
3158         int             v1;
3159         char            *val;
3160
3161         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
3162                 parid = -1;
3163         else
3164                 parid = fep->id;
3165         init_pathname(&f);
3166         e = generate_fname(fep, FT_SYM, &f, &id, &v1);
3167         v |= v1;
3168         if (!e) {
3169                 if (v) {
3170                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
3171                         printf("%d/%d: symlink - no filename from %s\n",
3172                                 procid, opno, f.path);
3173                 }
3174                 free_pathname(&f);
3175                 return;
3176         }
3177         len = (int)(random() % PATH_MAX);
3178         val = malloc(len + 1);
3179         if (len)
3180                 memset(val, 'x', len);
3181         val[len] = '\0';
3182         for (i = 10; i < len - 1; i += 10)
3183                 val[i] = '/';
3184         e = symlink_path(val, &f) < 0 ? errno : 0;
3185         check_cwd();
3186         if (e == 0)
3187                 add_to_flist(FT_SYM, id, parid);
3188         free(val);
3189         if (v) {
3190                 printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
3191                 printf("%d/%d: symlink add id=%d,parent=%d\n", procid, opno, id, parid);
3192         }
3193         free_pathname(&f);
3194 }
3195
3196 /* ARGSUSED */
3197 void
3198 sync_f(int opno, long r)
3199 {
3200         sync();
3201         if (verbose)
3202                 printf("%d/%d: sync\n", procid, opno);
3203 }
3204
3205 void
3206 truncate_f(int opno, long r)
3207 {
3208         int             e;
3209         pathname_t      f;
3210         __int64_t       lr;
3211         off64_t         off;
3212         struct stat64   stb;
3213         int             v;
3214         char            st[1024];
3215
3216         init_pathname(&f);
3217         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3218                 if (v)
3219                         printf("%d/%d: truncate - no filename\n", procid, opno);
3220                 free_pathname(&f);
3221                 return;
3222         }
3223         e = stat64_path(&f, &stb) < 0 ? errno : 0;
3224         check_cwd();
3225         if (e > 0) {
3226                 if (v)
3227                         printf("%d/%d: truncate - stat64 %s failed %d\n",
3228                                 procid, opno, f.path, e);
3229                 free_pathname(&f);
3230                 return;
3231         }
3232         inode_info(st, sizeof(st), &stb, v);
3233         lr = ((__int64_t)random() << 32) + random();
3234         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3235         off %= maxfsize;
3236         e = truncate64_path(&f, off) < 0 ? errno : 0;
3237         check_cwd();
3238         if (v)
3239                 printf("%d/%d: truncate %s%s %lld %d\n", procid, opno, f.path,
3240                        st, (long long)off, e);
3241         free_pathname(&f);
3242 }
3243
3244 void
3245 unlink_f(int opno, long r)
3246 {
3247         int             e;
3248         pathname_t      f;
3249         fent_t          *fep;
3250         flist_t         *flp;
3251         int             v;
3252
3253         init_pathname(&f);
3254         if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
3255                 if (v)
3256                         printf("%d/%d: unlink - no file\n", procid, opno);
3257                 free_pathname(&f);
3258                 return;
3259         }
3260         e = unlink_path(&f) < 0 ? errno : 0;
3261         check_cwd();
3262         if (e == 0)
3263                 del_from_flist(flp - flist, fep - flp->fents);
3264         if (v) {
3265                 printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e);
3266                 if (e == 0)
3267                         printf("%d/%d: unlink del entry: id=%d,parent=%d\n",
3268                                 procid, opno, fep->id, fep->parent);
3269         }
3270         free_pathname(&f);
3271 }
3272
3273 void
3274 unresvsp_f(int opno, long r)
3275 {
3276         int             e;
3277         pathname_t      f;
3278         int             fd;
3279         struct xfs_flock64      fl;
3280         __int64_t       lr;
3281         off64_t         off;
3282         struct stat64   stb;
3283         int             v;
3284         char            st[1024];
3285
3286         init_pathname(&f);
3287         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3288                 if (v)
3289                         printf("%d/%d: unresvsp - no filename\n", procid, opno);
3290                 free_pathname(&f);
3291                 return;
3292         }
3293         fd = open_path(&f, O_RDWR);
3294         e = fd < 0 ? errno : 0;
3295         check_cwd();
3296         if (fd < 0) {
3297                 if (v)
3298                         printf("%d/%d: unresvsp - open %s failed %d\n",
3299                                 procid, opno, f.path, e);
3300                 free_pathname(&f);
3301                 return;
3302         }
3303         if (fstat64(fd, &stb) < 0) {
3304                 if (v)
3305                         printf("%d/%d: unresvsp - fstat64 %s failed %d\n",
3306                                 procid, opno, f.path, errno);
3307                 free_pathname(&f);
3308                 close(fd);
3309                 return;
3310         }
3311         inode_info(st, sizeof(st), &stb, v);
3312         lr = ((__int64_t)random() << 32) + random();
3313         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3314         off %= maxfsize;
3315         fl.l_whence = SEEK_SET;
3316         fl.l_start = off;
3317         fl.l_len = (off64_t)(random() % (1 << 20));
3318         e = xfsctl(f.path, fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
3319         if (v)
3320                 printf("%d/%d: xfsctl(XFS_IOC_UNRESVSP64) %s%s %lld %lld %d\n",
3321                        procid, opno, f.path, st,
3322                         (long long)off, (long long)fl.l_len, e);
3323         free_pathname(&f);
3324         close(fd);
3325 }
3326
3327 void
3328 write_f(int opno, long r)
3329 {
3330         char            *buf;
3331         int             e;
3332         pathname_t      f;
3333         int             fd;
3334         size_t          len;
3335         __int64_t       lr;
3336         off64_t         off;
3337         struct stat64   stb;
3338         int             v;
3339         char            st[1024];
3340
3341         init_pathname(&f);
3342         if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
3343                 if (v)
3344                         printf("%d/%d: write - no filename\n", procid, opno);
3345                 free_pathname(&f);
3346                 return;
3347         }
3348         fd = open_path(&f, O_WRONLY);
3349         e = fd < 0 ? errno : 0;
3350         check_cwd();
3351         if (fd < 0) {
3352                 if (v)
3353                         printf("%d/%d: write - open %s failed %d\n",
3354                                 procid, opno, f.path, e);
3355                 free_pathname(&f);
3356                 return;
3357         }
3358         if (fstat64(fd, &stb) < 0) {
3359                 if (v)
3360                         printf("%d/%d: write - fstat64 %s failed %d\n",
3361                                 procid, opno, f.path, errno);
3362                 free_pathname(&f);
3363                 close(fd);
3364                 return;
3365         }
3366         inode_info(st, sizeof(st), &stb, v);
3367         lr = ((__int64_t)random() << 32) + random();
3368         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3369         off %= maxfsize;
3370         lseek64(fd, off, SEEK_SET);
3371         len = (random() % FILELEN_MAX) + 1;
3372         buf = malloc(len);
3373         memset(buf, nameseq & 0xff, len);
3374         e = write(fd, buf, len) < 0 ? errno : 0;
3375         free(buf);
3376         if (v)
3377                 printf("%d/%d: write %s%s [%lld,%d] %d\n",
3378                        procid, opno, f.path, st, (long long)off, (int)len, e);
3379         free_pathname(&f);
3380         close(fd);
3381 }