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