27f7307c2a667142dafd6b08244679798293650c
[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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
913         char            buf2[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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, MAXNAMELEN - 1 };
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
1143         char            buf2[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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[MAXNAMELEN];
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
1395 allocsp_f(int opno, long r)
1396 {
1397         int             e;
1398         pathname_t      f;
1399         int             fd;
1400         struct xfs_flock64      fl;
1401         __int64_t       lr;
1402         off64_t         off;
1403         struct stat64   stb;
1404         int             v;
1405
1406         init_pathname(&f);
1407         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1408                 if (v)
1409                         printf("%d/%d: allocsp - no filename\n", procid, opno);
1410                 free_pathname(&f);
1411                 return;
1412         }
1413         fd = open_path(&f, O_RDWR);
1414         e = fd < 0 ? errno : 0;
1415         check_cwd();
1416         if (fd < 0) {
1417                 if (v)
1418                         printf("%d/%d: allocsp - open %s failed %d\n",
1419                                 procid, opno, f.path, e);
1420                 free_pathname(&f);
1421                 return;
1422         }
1423         if (fstat64(fd, &stb) < 0) {
1424                 if (v)
1425                         printf("%d/%d: allocsp - fstat64 %s failed %d\n",
1426                                 procid, opno, f.path, errno);
1427                 free_pathname(&f);
1428                 close(fd);
1429                 return;
1430         }
1431         lr = ((__int64_t)random() << 32) + random();
1432         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1433         off %= maxfsize;
1434         fl.l_whence = SEEK_SET;
1435         fl.l_start = off;
1436         fl.l_len = 0;
1437         e = xfsctl(f.path, fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
1438         if (v)
1439                 printf("%d/%d: xfsctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n",
1440                         procid, opno, f.path, (long long)off, e);
1441         free_pathname(&f);
1442         close(fd);
1443 }
1444
1445 void
1446 attr_remove_f(int opno, long r)
1447 {
1448         attrlist_ent_t          *aep;
1449         attrlist_t              *alist;
1450         char                    *aname;
1451         char                    buf[4096];
1452         attrlist_cursor_t       cursor;
1453         int                     e;
1454         int                     ent;
1455         pathname_t              f;
1456         int                     total;
1457         int                     v;
1458         int                     which;
1459
1460         init_pathname(&f);
1461         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1462                 append_pathname(&f, ".");
1463         total = 0;
1464         bzero(&cursor, sizeof(cursor));
1465         do {
1466                 bzero(buf, sizeof(buf));
1467                 e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, &cursor);
1468                 check_cwd();
1469                 if (e)
1470                         break;
1471                 alist = (attrlist_t *)buf;
1472                 total += alist->al_count;
1473         } while (alist->al_more);
1474         if (total == 0) {
1475                 if (v)
1476                         printf("%d/%d: attr_remove - no attrs for %s\n",
1477                                 procid, opno, f.path);
1478                 free_pathname(&f);
1479                 return;
1480         }
1481         which = (int)(random() % total);
1482         bzero(&cursor, sizeof(cursor));
1483         ent = 0;
1484         aname = NULL;
1485         do {
1486                 bzero(buf, sizeof(buf));
1487                 e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, &cursor);
1488                 check_cwd();
1489                 if (e)
1490                         break;
1491                 alist = (attrlist_t *)buf;
1492                 if (which < ent + alist->al_count) {
1493                         aep = (attrlist_ent_t *)
1494                                 &buf[alist->al_offset[which - ent]];
1495                         aname = aep->a_name;
1496                         break;
1497                 }
1498                 ent += alist->al_count;
1499         } while (alist->al_more);
1500         if (aname == NULL) {
1501                 if (v)
1502                         printf(
1503                         "%d/%d: attr_remove - name %d not found at %s\n",
1504                                 procid, opno, which, f.path);
1505                 free_pathname(&f);
1506                 return;
1507         }
1508         e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0;
1509         check_cwd();
1510         if (v)
1511                 printf("%d/%d: attr_remove %s %s %d\n",
1512                         procid, opno, f.path, aname, e);
1513         free_pathname(&f);
1514 }
1515
1516 void
1517 attr_set_f(int opno, long r)
1518 {
1519         char            aname[10];
1520         char            *aval;
1521         int             e;
1522         pathname_t      f;
1523         int             len;
1524         static int      lengths[] = { 10, 100, 1000, 10000 };
1525         int             li;
1526         int             v;
1527
1528         init_pathname(&f);
1529         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1530                 append_pathname(&f, ".");
1531         sprintf(aname, "a%x", nameseq++);
1532         li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0])));
1533         len = (int)(random() % lengths[li]);
1534         if (len == 0)
1535                 len = 1;
1536         aval = malloc(len);
1537         memset(aval, nameseq & 0xff, len);
1538         e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ?
1539                 errno : 0;
1540         check_cwd();
1541         free(aval);
1542         if (v)
1543                 printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path,
1544                         aname, e);
1545         free_pathname(&f);
1546 }
1547
1548 void
1549 bulkstat_f(int opno, long r)
1550 {
1551         int             count;
1552         int             fd;
1553         __uint64_t      last;
1554         int             nent;
1555         xfs_bstat_t     *t;
1556         __int64_t       total;
1557         xfs_fsop_bulkreq_t bsr;
1558
1559         last = 0;
1560         nent = (r % 999) + 2;
1561         t = malloc(nent * sizeof(*t));
1562         fd = open(".", O_RDONLY);
1563         total = 0;
1564
1565         bsr.lastip=&last;
1566         bsr.icount=nent;
1567         bsr.ubuffer=t;
1568         bsr.ocount=&count;
1569             
1570         while (xfsctl(".", fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
1571                 total += count;
1572         free(t);
1573         if (verbose)
1574                 printf("%d/%d: bulkstat nent %d total %lld\n",
1575                         procid, opno, nent, (long long)total);
1576         close(fd);
1577 }
1578
1579 void
1580 bulkstat1_f(int opno, long r)
1581 {
1582         int             e;
1583         pathname_t      f;
1584         int             fd;
1585         int             good;
1586         __uint64_t      ino;
1587         struct stat64   s;
1588         xfs_bstat_t     t;
1589         int             v;
1590         xfs_fsop_bulkreq_t bsr;
1591         
1592
1593         good = random() & 1;
1594         if (good) {
1595                /* use an inode we know exists */
1596                 init_pathname(&f);
1597                 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1598                         append_pathname(&f, ".");
1599                 ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino;
1600                 check_cwd();
1601                 free_pathname(&f);
1602         } else {
1603                 /* 
1604                  * pick a random inode 
1605                  *
1606                  * note this can generate kernel warning messages
1607                  * since bulkstat_one will read the disk block that
1608                  * would contain a given inode even if that disk
1609                  * block doesn't contain inodes.
1610                  *
1611                  * this is detected later, but not until after the
1612                  * warning is displayed.
1613                  *
1614                  * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0"
1615                  *
1616                  */
1617                 ino = (ino64_t)r;
1618                 v = verbose;
1619         }
1620         fd = open(".", O_RDONLY);
1621         
1622         bsr.lastip=&ino;
1623         bsr.icount=1;
1624         bsr.ubuffer=&t;
1625         bsr.ocount=NULL;
1626         
1627         e = xfsctl(".", fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
1628         if (v)
1629                 printf("%d/%d: bulkstat1 %s ino %lld %d\n", 
1630                     procid, opno, good?"real":"random", (long long)ino, e);
1631         close(fd);
1632 }
1633
1634 void
1635 chown_f(int opno, long r)
1636 {
1637         int             e;
1638         pathname_t      f;
1639         int             nbits;
1640         uid_t           u;
1641         gid_t           g;
1642         int             v;
1643
1644         init_pathname(&f);
1645         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1646                 append_pathname(&f, ".");
1647         u = (uid_t)random();
1648         g = (gid_t)random();
1649         nbits = (int)(random() % idmodulo);
1650         u &= (1 << nbits) - 1;
1651         g &= (1 << nbits) - 1;
1652         e = lchown_path(&f, u, g) < 0 ? errno : 0;
1653         check_cwd();
1654         if (v)
1655                 printf("%d/%d: chown %s %d/%d %d\n", procid, opno, f.path, (int)u, (int)g, e);
1656         free_pathname(&f);
1657 }
1658
1659 void
1660 setxattr_f(int opno, long r)
1661 {
1662         struct fsxattr  fsx;
1663         int             fd;
1664         int             e;
1665         pathname_t      f;
1666         int             nbits;
1667         uint            p;
1668         int             v;
1669
1670         init_pathname(&f);
1671         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1672                 append_pathname(&f, ".");
1673         fd = open_path(&f, O_RDWR);
1674         e = fd < 0 ? errno : 0;
1675         check_cwd();
1676
1677         /* project ID */
1678         p = (uint)random();
1679         e = MIN(idmodulo, XFS_PROJIDMODULO_MAX);
1680         nbits = (int)(random() % e);
1681         p &= (1 << nbits) - 1;
1682
1683         if ((e = xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &fsx)) == 0) {
1684                 fsx.fsx_projid = p;
1685                 e = xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &fsx);
1686         }
1687         if (v)
1688                 printf("%d/%d: setxattr %s %u %d\n", procid, opno, f.path, p, e);
1689         free_pathname(&f);
1690         close(fd);
1691 }
1692
1693 void
1694 creat_f(int opno, long r)
1695 {
1696         struct fsxattr  a;
1697         int             e;
1698         int             e1;
1699         int             extsize;
1700         pathname_t      f;
1701         int             fd;
1702         fent_t          *fep;
1703         int             id;
1704         int             parid;
1705         int             type;
1706         int             v;
1707         int             v1;
1708
1709         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
1710                 parid = -1;
1711         else
1712                 parid = fep->id;
1713         init_pathname(&f);
1714         e1 = (random() % 100);
1715         type = rtpct ? ((e1 > rtpct) ? FT_REG : FT_RTF) : FT_REG;
1716 #ifdef NOTYET
1717         if (type == FT_RTF)     /* rt always gets an extsize */
1718                 extsize = (random() % 10) + 1;
1719         else if (e1 < 10)       /* one-in-ten get an extsize */
1720                 extsize = random() % 1024;
1721         else
1722 #endif
1723                 extsize = 0;
1724         e = generate_fname(fep, type, &f, &id, &v);
1725         v |= v1;
1726         if (!e) {
1727                 if (v) {
1728                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
1729                         printf("%d/%d: creat - no filename from %s\n",
1730                                 procid, opno, f.path);
1731                 }
1732                 free_pathname(&f);
1733                 return;
1734         }
1735         fd = creat_path(&f, 0666);
1736         e = fd < 0 ? errno : 0;
1737         e1 = 0;
1738         check_cwd();
1739         if (fd >= 0) {
1740                 if (extsize &&
1741                     xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
1742                         if (type == FT_RTF) {
1743                                 a.fsx_xflags |= XFS_XFLAG_REALTIME;
1744                                 a.fsx_extsize = extsize *
1745                                                 geom.rtextsize * geom.blocksize;
1746                         } else if (extsize) {
1747                                 a.fsx_xflags |= XFS_XFLAG_EXTSIZE;
1748                                 a.fsx_extsize = extsize * geom.blocksize;
1749                         }
1750                         if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
1751                                 e1 = errno;
1752                 }
1753                 add_to_flist(type, id, parid);
1754                 close(fd);
1755         }
1756         if (v) {
1757                 printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
1758                         extsize ? a.fsx_extsize : 0, e, e1);
1759                 printf("%d/%d: creat add id=%d,parent=%d\n", procid, opno, id, parid);
1760         }
1761         free_pathname(&f);
1762 }
1763
1764 void
1765 dread_f(int opno, long r)
1766 {
1767         __int64_t       align;
1768         char            *buf;
1769         struct dioattr  diob;
1770         int             e;
1771         pathname_t      f;
1772         int             fd;
1773         size_t          len;
1774         __int64_t       lr;
1775         off64_t         off;
1776         struct stat64   stb;
1777         int             v;
1778
1779         init_pathname(&f);
1780         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1781                 if (v)
1782                         printf("%d/%d: dread - no filename\n", procid, opno);
1783                 free_pathname(&f);
1784                 return;
1785         }
1786         fd = open_path(&f, O_RDONLY|O_DIRECT);
1787         e = fd < 0 ? errno : 0;
1788         check_cwd();
1789         if (fd < 0) {
1790                 if (v)
1791                         printf("%d/%d: dread - open %s failed %d\n",
1792                                 procid, opno, f.path, e);
1793                 free_pathname(&f);
1794                 return;
1795         }
1796         if (fstat64(fd, &stb) < 0) {
1797                 if (v)
1798                         printf("%d/%d: dread - fstat64 %s failed %d\n",
1799                                 procid, opno, f.path, errno);
1800                 free_pathname(&f);
1801                 close(fd);
1802                 return;
1803         }
1804         if (stb.st_size == 0) {
1805                 if (v)
1806                         printf("%d/%d: dread - %s zero size\n", procid, opno,
1807                                 f.path);
1808                 free_pathname(&f);
1809                 close(fd);
1810                 return;
1811         }
1812         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
1813                 if (v)
1814                         printf(
1815                         "%d/%d: dread - xfsctl(XFS_IOC_DIOINFO) %s failed %d\n",
1816                                 procid, opno, f.path, errno);
1817                 free_pathname(&f);
1818                 close(fd);
1819                 return;
1820         }
1821         align = (__int64_t)diob.d_miniosz;
1822         lr = ((__int64_t)random() << 32) + random();
1823         off = (off64_t)(lr % stb.st_size);
1824         off -= (off % align);
1825         lseek64(fd, off, SEEK_SET);
1826         len = (random() % FILELEN_MAX) + 1;
1827         len -= (len % align);
1828         if (len <= 0)
1829                 len = align;
1830         else if (len > diob.d_maxiosz) 
1831                 len = diob.d_maxiosz;
1832         buf = memalign(diob.d_mem, len);
1833         e = read(fd, buf, len) < 0 ? errno : 0;
1834         free(buf);
1835         if (v)
1836                 printf("%d/%d: dread %s [%lld,%d] %d\n",
1837                         procid, opno, f.path, (long long)off, (int)len, e);
1838         free_pathname(&f);
1839         close(fd);
1840 }
1841
1842 void
1843 dwrite_f(int opno, long r)
1844 {
1845         __int64_t       align;
1846         char            *buf;
1847         struct dioattr  diob;
1848         int             e;
1849         pathname_t      f;
1850         int             fd;
1851         size_t          len;
1852         __int64_t       lr;
1853         off64_t         off;
1854         struct stat64   stb;
1855         int             v;
1856
1857         init_pathname(&f);
1858         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1859                 if (v)
1860                         printf("%d/%d: dwrite - no filename\n", procid, opno);
1861                 free_pathname(&f);
1862                 return;
1863         }
1864         fd = open_path(&f, O_WRONLY|O_DIRECT);
1865         e = fd < 0 ? errno : 0;
1866         check_cwd();
1867         if (fd < 0) {
1868                 if (v)
1869                         printf("%d/%d: dwrite - open %s failed %d\n",
1870                                 procid, opno, f.path, e);
1871                 free_pathname(&f);
1872                 return;
1873         }
1874         if (fstat64(fd, &stb) < 0) {
1875                 if (v)
1876                         printf("%d/%d: dwrite - fstat64 %s failed %d\n",
1877                                 procid, opno, f.path, errno);
1878                 free_pathname(&f);
1879                 close(fd);
1880                 return;
1881         }
1882         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
1883                 if (v)
1884                         printf("%d/%d: dwrite - xfsctl(XFS_IOC_DIOINFO)"
1885                                 " %s failed %d\n",
1886                                 procid, opno, f.path, errno);
1887                 free_pathname(&f);
1888                 close(fd);
1889                 return;
1890         }
1891         align = (__int64_t)diob.d_miniosz;
1892         lr = ((__int64_t)random() << 32) + random();
1893         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1894         off -= (off % align);
1895         lseek64(fd, off, SEEK_SET);
1896         len = (random() % FILELEN_MAX) + 1;
1897         len -= (len % align);
1898         if (len <= 0)
1899                 len = align;
1900         else if (len > diob.d_maxiosz) 
1901                 len = diob.d_maxiosz;
1902         buf = memalign(diob.d_mem, len);
1903         off %= maxfsize;
1904         lseek64(fd, off, SEEK_SET);
1905         memset(buf, nameseq & 0xff, len);
1906         e = write(fd, buf, len) < 0 ? errno : 0;
1907         free(buf);
1908         if (v)
1909                 printf("%d/%d: dwrite %s [%lld,%d] %d\n",
1910                         procid, opno, f.path, (long long)off, (int)len, e);
1911         free_pathname(&f);
1912         close(fd);
1913 }
1914
1915 void
1916 fdatasync_f(int opno, long r)
1917 {
1918         int             e;
1919         pathname_t      f;
1920         int             fd;
1921         int             v;
1922
1923         init_pathname(&f);
1924         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1925                 if (v)
1926                         printf("%d/%d: fdatasync - no filename\n",
1927                                 procid, opno);
1928                 free_pathname(&f);
1929                 return;
1930         }
1931         fd = open_path(&f, O_WRONLY);
1932         e = fd < 0 ? errno : 0;
1933         check_cwd();
1934         if (fd < 0) {
1935                 if (v)
1936                         printf("%d/%d: fdatasync - open %s failed %d\n",
1937                                 procid, opno, f.path, e);
1938                 free_pathname(&f);
1939                 return;
1940         }
1941         e = fdatasync(fd) < 0 ? errno : 0;
1942         if (v)
1943                 printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e);
1944         free_pathname(&f);
1945         close(fd);
1946 }
1947
1948 void
1949 freesp_f(int opno, long r)
1950 {
1951         int             e;
1952         pathname_t      f;
1953         int             fd;
1954         struct xfs_flock64      fl;
1955         __int64_t       lr;
1956         off64_t         off;
1957         struct stat64   stb;
1958         int             v;
1959
1960         init_pathname(&f);
1961         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1962                 if (v)
1963                         printf("%d/%d: freesp - no filename\n", procid, opno);
1964                 free_pathname(&f);
1965                 return;
1966         }
1967         fd = open_path(&f, O_RDWR);
1968         e = fd < 0 ? errno : 0;
1969         check_cwd();
1970         if (fd < 0) {
1971                 if (v)
1972                         printf("%d/%d: freesp - open %s failed %d\n",
1973                                 procid, opno, f.path, e);
1974                 free_pathname(&f);
1975                 return;
1976         }
1977         if (fstat64(fd, &stb) < 0) {
1978                 if (v)
1979                         printf("%d/%d: freesp - fstat64 %s failed %d\n",
1980                                 procid, opno, f.path, errno);
1981                 free_pathname(&f);
1982                 close(fd);
1983                 return;
1984         }
1985         lr = ((__int64_t)random() << 32) + random();
1986         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1987         off %= maxfsize;
1988         fl.l_whence = SEEK_SET;
1989         fl.l_start = off;
1990         fl.l_len = 0;
1991         e = xfsctl(f.path, fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
1992         if (v)
1993                 printf("%d/%d: xfsctl(XFS_IOC_FREESP64) %s %lld 0 %d\n",
1994                         procid, opno, f.path, (long long)off, e);
1995         free_pathname(&f);
1996         close(fd);
1997 }
1998
1999 void
2000 fsync_f(int opno, long r)
2001 {
2002         int             e;
2003         pathname_t      f;
2004         int             fd;
2005         int             v;
2006
2007         init_pathname(&f);
2008         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2009                 if (v)
2010                         printf("%d/%d: fsync - no filename\n", procid, opno);
2011                 free_pathname(&f);
2012                 return;
2013         }
2014         fd = open_path(&f, O_WRONLY);
2015         e = fd < 0 ? errno : 0;
2016         check_cwd();
2017         if (fd < 0) {
2018                 if (v)
2019                         printf("%d/%d: fsync - open %s failed %d\n",
2020                                 procid, opno, f.path, e);
2021                 free_pathname(&f);
2022                 return;
2023         }
2024         e = fsync(fd) < 0 ? errno : 0;
2025         if (v)
2026                 printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e);
2027         free_pathname(&f);
2028         close(fd);
2029 }
2030
2031 void
2032 getdents_f(int opno, long r)
2033 {
2034         DIR             *dir;
2035         pathname_t      f;
2036         int             v;
2037
2038         init_pathname(&f);
2039         if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
2040                 append_pathname(&f, ".");
2041         dir = opendir_path(&f);
2042         check_cwd();
2043         if (dir == NULL) {
2044                 if (v)
2045                         printf("%d/%d: getdents - can't open %s\n",
2046                                 procid, opno, f.path);
2047                 free_pathname(&f);
2048                 return;
2049         }
2050         while (readdir64(dir) != NULL)
2051                 continue;
2052         if (v)
2053                 printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
2054         free_pathname(&f);
2055         closedir(dir);
2056 }
2057
2058 void
2059 link_f(int opno, long r)
2060 {
2061         int             e;
2062         pathname_t      f;
2063         fent_t          *fep;
2064         flist_t         *flp;
2065         int             id;
2066         pathname_t      l;
2067         int             parid;
2068         int             v;
2069         int             v1;
2070
2071         init_pathname(&f);
2072         if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
2073                 if (v1)
2074                         printf("%d/%d: link - no file\n", procid, opno);
2075                 free_pathname(&f);
2076                 return;
2077         }
2078         if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
2079                 parid = -1;
2080         else
2081                 parid = fep->id;
2082         v |= v1;
2083         init_pathname(&l);
2084         e = generate_fname(fep, flp - flist, &l, &id, &v1);
2085         v |= v1;
2086         if (!e) {
2087                 if (v) {
2088                         (void)fent_to_name(&l, &flist[FT_DIR], fep);
2089                         printf("%d/%d: link - no filename from %s\n",
2090                                 procid, opno, l.path);
2091                 }
2092                 free_pathname(&l);
2093                 free_pathname(&f);
2094                 return;
2095         }
2096         e = link_path(&f, &l) < 0 ? errno : 0;
2097         check_cwd();
2098         if (e == 0)
2099                 add_to_flist(flp - flist, id, parid);
2100         if (v) {
2101                 printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
2102                         e);
2103                 printf("%d/%d: link add id=%d,parent=%d\n", procid, opno, id, parid);
2104         }
2105         free_pathname(&l);
2106         free_pathname(&f);
2107 }
2108
2109 void
2110 mkdir_f(int opno, long r)
2111 {
2112         int             e;
2113         pathname_t      f;
2114         fent_t          *fep;
2115         int             id;
2116         int             parid;
2117         int             v;
2118         int             v1;
2119
2120         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2121                 parid = -1;
2122         else
2123                 parid = fep->id;
2124         init_pathname(&f);
2125         e = generate_fname(fep, FT_DIR, &f, &id, &v1);
2126         v |= v1;
2127         if (!e) {
2128                 if (v) {
2129                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
2130                         printf("%d/%d: mkdir - no filename from %s\n",
2131                                 procid, opno, f.path);
2132                 }
2133                 free_pathname(&f);
2134                 return;
2135         }
2136         e = mkdir_path(&f, 0777) < 0 ? errno : 0;
2137         check_cwd();
2138         if (e == 0)
2139                 add_to_flist(FT_DIR, id, parid);
2140         if (v) {
2141                 printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
2142                 printf("%d/%d: mkdir add id=%d,parent=%d\n", procid, opno, id, parid);
2143         }
2144         free_pathname(&f);
2145 }
2146
2147 void
2148 mknod_f(int opno, long r)
2149 {
2150         int             e;
2151         pathname_t      f;
2152         fent_t          *fep;
2153         int             id;
2154         int             parid;
2155         int             v;
2156         int             v1;
2157
2158         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2159                 parid = -1;
2160         else
2161                 parid = fep->id;
2162         init_pathname(&f);
2163         e = generate_fname(fep, FT_DEV, &f, &id, &v1);
2164         v |= v1;
2165         if (!e) {
2166                 if (v) {
2167                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
2168                         printf("%d/%d: mknod - no filename from %s\n",
2169                                 procid, opno, f.path);
2170                 }
2171                 free_pathname(&f);
2172                 return;
2173         }
2174         e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
2175         check_cwd();
2176         if (e == 0)
2177                 add_to_flist(FT_DEV, id, parid);
2178         if (v) {
2179                 printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
2180                 printf("%d/%d: mknod add id=%d,parent=%d\n", procid, opno, id, parid);
2181         }
2182         free_pathname(&f);
2183 }
2184
2185 void
2186 read_f(int opno, long r)
2187 {
2188         char            *buf;
2189         int             e;
2190         pathname_t      f;
2191         int             fd;
2192         size_t          len;
2193         __int64_t       lr;
2194         off64_t         off;
2195         struct stat64   stb;
2196         int             v;
2197
2198         init_pathname(&f);
2199         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2200                 if (v)
2201                         printf("%d/%d: read - no filename\n", procid, opno);
2202                 free_pathname(&f);
2203                 return;
2204         }
2205         fd = open_path(&f, O_RDONLY);
2206         e = fd < 0 ? errno : 0;
2207         check_cwd();
2208         if (fd < 0) {
2209                 if (v)
2210                         printf("%d/%d: read - open %s failed %d\n",
2211                                 procid, opno, f.path, e);
2212                 free_pathname(&f);
2213                 return;
2214         }
2215         if (fstat64(fd, &stb) < 0) {
2216                 if (v)
2217                         printf("%d/%d: read - fstat64 %s failed %d\n",
2218                                 procid, opno, f.path, errno);
2219                 free_pathname(&f);
2220                 close(fd);
2221                 return;
2222         }
2223         if (stb.st_size == 0) {
2224                 if (v)
2225                         printf("%d/%d: read - %s zero size\n", procid, opno,
2226                                 f.path);
2227                 free_pathname(&f);
2228                 close(fd);
2229                 return;
2230         }
2231         lr = ((__int64_t)random() << 32) + random();
2232         off = (off64_t)(lr % stb.st_size);
2233         lseek64(fd, off, SEEK_SET);
2234         len = (random() % FILELEN_MAX) + 1;
2235         buf = malloc(len);
2236         e = read(fd, buf, len) < 0 ? errno : 0;
2237         free(buf);
2238         if (v)
2239                 printf("%d/%d: read %s [%lld,%d] %d\n",
2240                         procid, opno, f.path, (long long)off, (int)len, e);
2241         free_pathname(&f);
2242         close(fd);
2243 }
2244
2245 void
2246 readlink_f(int opno, long r)
2247 {
2248         char            buf[PATH_MAX];
2249         int             e;
2250         pathname_t      f;
2251         int             v;
2252
2253         init_pathname(&f);
2254         if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
2255                 if (v)
2256                         printf("%d/%d: readlink - no filename\n", procid, opno);
2257                 free_pathname(&f);
2258                 return;
2259         }
2260         e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
2261         check_cwd();
2262         if (v)
2263                 printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e);
2264         free_pathname(&f);
2265 }
2266
2267 void
2268 rename_f(int opno, long r)
2269 {
2270         fent_t          *dfep;
2271         int             e;
2272         pathname_t      f;
2273         fent_t          *fep;
2274         flist_t         *flp;
2275         int             id;
2276         pathname_t      newf;
2277         int             oldid;
2278         int             parid;
2279         int             v;
2280         int             v1;
2281
2282         /* get an existing path for the source of the rename */
2283         init_pathname(&f);
2284         if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
2285                 if (v1)
2286                         printf("%d/%d: rename - no filename\n", procid, opno);
2287                 free_pathname(&f);
2288                 return;
2289         }
2290
2291         /* get an existing directory for the destination parent directory name */
2292         if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
2293                 parid = -1;
2294         else
2295                 parid = dfep->id;
2296         v |= v1;
2297
2298         /* generate a new path using an existing parent directory in name */
2299         init_pathname(&newf);
2300         e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
2301         v |= v1;
2302         if (!e) {
2303                 if (v) {
2304                         (void)fent_to_name(&f, &flist[FT_DIR], dfep);
2305                         printf("%d/%d: rename - no filename from %s\n",
2306                                 procid, opno, f.path);
2307                 }
2308                 free_pathname(&newf);
2309                 free_pathname(&f);
2310                 return;
2311         }
2312         e = rename_path(&f, &newf) < 0 ? errno : 0;
2313         check_cwd();
2314         if (e == 0) {
2315                 if (flp - flist == FT_DIR) {
2316                         oldid = fep->id;
2317                         fix_parent(oldid, id);
2318                 }
2319                 del_from_flist(flp - flist, fep - flp->fents);
2320                 add_to_flist(flp - flist, id, parid);
2321         }
2322         if (v) {
2323                 printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
2324                         newf.path, e);
2325                 if (e == 0) {
2326                         printf("%d/%d: rename del entry: id=%d,parent=%d\n",
2327                                 procid, opno, fep->id, fep->parent);
2328                         printf("%d/%d: rename add entry: id=%d,parent=%d\n",
2329                                 procid, opno, id, parid);
2330                 }
2331         }
2332         free_pathname(&newf);
2333         free_pathname(&f);
2334 }
2335
2336 void
2337 resvsp_f(int opno, long r)
2338 {
2339         int             e;
2340         pathname_t      f;
2341         int             fd;
2342         struct xfs_flock64      fl;
2343         __int64_t       lr;
2344         off64_t         off;
2345         struct stat64   stb;
2346         int             v;
2347
2348         init_pathname(&f);
2349         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2350                 if (v)
2351                         printf("%d/%d: resvsp - no filename\n", procid, opno);
2352                 free_pathname(&f);
2353                 return;
2354         }
2355         fd = open_path(&f, O_RDWR);
2356         e = fd < 0 ? errno : 0;
2357         check_cwd();
2358         if (fd < 0) {
2359                 if (v)
2360                         printf("%d/%d: resvsp - open %s failed %d\n",
2361                                 procid, opno, f.path, e);
2362                 free_pathname(&f);
2363                 return;
2364         }
2365         if (fstat64(fd, &stb) < 0) {
2366                 if (v)
2367                         printf("%d/%d: resvsp - fstat64 %s failed %d\n",
2368                                 procid, opno, f.path, errno);
2369                 free_pathname(&f);
2370                 close(fd);
2371                 return;
2372         }
2373         lr = ((__int64_t)random() << 32) + random();
2374         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2375         off %= maxfsize;
2376         fl.l_whence = SEEK_SET;
2377         fl.l_start = off;
2378         fl.l_len = (off64_t)(random() % (1024 * 1024));
2379         e = xfsctl(f.path, fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
2380         if (v)
2381                 printf("%d/%d: xfsctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n",
2382                         procid, opno, f.path,
2383                         (long long)off, (long long)fl.l_len, e);
2384         free_pathname(&f);
2385         close(fd);
2386 }
2387
2388 void
2389 rmdir_f(int opno, long r)
2390 {
2391         int             e;
2392         pathname_t      f;
2393         fent_t          *fep;
2394         int             v;
2395
2396         init_pathname(&f);
2397         if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
2398                 if (v)
2399                         printf("%d/%d: rmdir - no directory\n", procid, opno);
2400                 free_pathname(&f);
2401                 return;
2402         }
2403         e = rmdir_path(&f) < 0 ? errno : 0;
2404         check_cwd();
2405         if (e == 0)
2406                 del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
2407         if (v) {
2408                 printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e);
2409                 if (e == 0)
2410                         printf("%d/%d: rmdir del entry: id=%d,parent=%d\n",
2411                                 procid, opno, fep->id, fep->parent);
2412         }
2413         free_pathname(&f);
2414 }
2415
2416 void
2417 stat_f(int opno, long r)
2418 {
2419         int             e;
2420         pathname_t      f;
2421         struct stat64   stb;
2422         int             v;
2423
2424         init_pathname(&f);
2425         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
2426                 if (v)
2427                         printf("%d/%d: stat - no entries\n", procid, opno);
2428                 free_pathname(&f);
2429                 return;
2430         }
2431         e = lstat64_path(&f, &stb) < 0 ? errno : 0;
2432         check_cwd();
2433         if (v)
2434                 printf("%d/%d: stat %s %d\n", procid, opno, f.path, e);
2435         free_pathname(&f);
2436 }
2437
2438 void
2439 symlink_f(int opno, long r)
2440 {
2441         int             e;
2442         pathname_t      f;
2443         fent_t          *fep;
2444         int             i;
2445         int             id;
2446         int             len;
2447         int             parid;
2448         int             v;
2449         int             v1;
2450         char            *val;
2451
2452         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2453                 parid = -1;
2454         else
2455                 parid = fep->id;
2456         init_pathname(&f);
2457         e = generate_fname(fep, FT_SYM, &f, &id, &v1);
2458         v |= v1;
2459         if (!e) {
2460                 if (v) {
2461                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
2462                         printf("%d/%d: symlink - no filename from %s\n",
2463                                 procid, opno, f.path);
2464                 }
2465                 free_pathname(&f);
2466                 return;
2467         }
2468         len = (int)(random() % PATH_MAX);
2469         val = malloc(len + 1);
2470         if (len)
2471                 memset(val, 'x', len);
2472         val[len] = '\0';
2473         for (i = 10; i < len - 1; i += 10)
2474                 val[i] = '/';
2475         e = symlink_path(val, &f) < 0 ? errno : 0;
2476         check_cwd();
2477         if (e == 0)
2478                 add_to_flist(FT_SYM, id, parid);
2479         free(val);
2480         if (v) {
2481                 printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
2482                 printf("%d/%d: symlink add id=%d,parent=%d\n", procid, opno, id, parid);
2483         }
2484         free_pathname(&f);
2485 }
2486
2487 /* ARGSUSED */
2488 void
2489 sync_f(int opno, long r)
2490 {
2491         sync();
2492         if (verbose)
2493                 printf("%d/%d: sync\n", procid, opno);
2494 }
2495
2496 void
2497 truncate_f(int opno, long r)
2498 {
2499         int             e;
2500         pathname_t      f;
2501         __int64_t       lr;
2502         off64_t         off;
2503         struct stat64   stb;
2504         int             v;
2505
2506         init_pathname(&f);
2507         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2508                 if (v)
2509                         printf("%d/%d: truncate - no filename\n", procid, opno);
2510                 free_pathname(&f);
2511                 return;
2512         }
2513         e = stat64_path(&f, &stb) < 0 ? errno : 0;
2514         check_cwd();
2515         if (e > 0) {
2516                 if (v)
2517                         printf("%d/%d: truncate - stat64 %s failed %d\n",
2518                                 procid, opno, f.path, e);
2519                 free_pathname(&f);
2520                 return;
2521         }
2522         lr = ((__int64_t)random() << 32) + random();
2523         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2524         off %= maxfsize;
2525         e = truncate64_path(&f, off) < 0 ? errno : 0;
2526         check_cwd();
2527         if (v)
2528                 printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path,
2529                         (long long)off, e);
2530         free_pathname(&f);
2531 }
2532
2533 void
2534 unlink_f(int opno, long r)
2535 {
2536         int             e;
2537         pathname_t      f;
2538         fent_t          *fep;
2539         flist_t         *flp;
2540         int             v;
2541
2542         init_pathname(&f);
2543         if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
2544                 if (v)
2545                         printf("%d/%d: unlink - no file\n", procid, opno);
2546                 free_pathname(&f);
2547                 return;
2548         }
2549         e = unlink_path(&f) < 0 ? errno : 0;
2550         check_cwd();
2551         if (e == 0)
2552                 del_from_flist(flp - flist, fep - flp->fents);
2553         if (v) {
2554                 printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e);
2555                 if (e == 0)
2556                         printf("%d/%d: unlink del entry: id=%d,parent=%d\n",
2557                                 procid, opno, fep->id, fep->parent);
2558         }
2559         free_pathname(&f);
2560 }
2561
2562 void
2563 unresvsp_f(int opno, long r)
2564 {
2565         int             e;
2566         pathname_t      f;
2567         int             fd;
2568         struct xfs_flock64      fl;
2569         __int64_t       lr;
2570         off64_t         off;
2571         struct stat64   stb;
2572         int             v;
2573
2574         init_pathname(&f);
2575         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2576                 if (v)
2577                         printf("%d/%d: unresvsp - no filename\n", procid, opno);
2578                 free_pathname(&f);
2579                 return;
2580         }
2581         fd = open_path(&f, O_RDWR);
2582         e = fd < 0 ? errno : 0;
2583         check_cwd();
2584         if (fd < 0) {
2585                 if (v)
2586                         printf("%d/%d: unresvsp - open %s failed %d\n",
2587                                 procid, opno, f.path, e);
2588                 free_pathname(&f);
2589                 return;
2590         }
2591         if (fstat64(fd, &stb) < 0) {
2592                 if (v)
2593                         printf("%d/%d: unresvsp - fstat64 %s failed %d\n",
2594                                 procid, opno, f.path, errno);
2595                 free_pathname(&f);
2596                 close(fd);
2597                 return;
2598         }
2599         lr = ((__int64_t)random() << 32) + random();
2600         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2601         off %= maxfsize;
2602         fl.l_whence = SEEK_SET;
2603         fl.l_start = off;
2604         fl.l_len = (off64_t)(random() % (1 << 20));
2605         e = xfsctl(f.path, fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
2606         if (v)
2607                 printf("%d/%d: xfsctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n",
2608                         procid, opno, f.path,
2609                         (long long)off, (long long)fl.l_len, e);
2610         free_pathname(&f);
2611         close(fd);
2612 }
2613
2614 void
2615 write_f(int opno, long r)
2616 {
2617         char            *buf;
2618         int             e;
2619         pathname_t      f;
2620         int             fd;
2621         size_t          len;
2622         __int64_t       lr;
2623         off64_t         off;
2624         struct stat64   stb;
2625         int             v;
2626
2627         init_pathname(&f);
2628         if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
2629                 if (v)
2630                         printf("%d/%d: write - no filename\n", procid, opno);
2631                 free_pathname(&f);
2632                 return;
2633         }
2634         fd = open_path(&f, O_WRONLY);
2635         e = fd < 0 ? errno : 0;
2636         check_cwd();
2637         if (fd < 0) {
2638                 if (v)
2639                         printf("%d/%d: write - open %s failed %d\n",
2640                                 procid, opno, f.path, e);
2641                 free_pathname(&f);
2642                 return;
2643         }
2644         if (fstat64(fd, &stb) < 0) {
2645                 if (v)
2646                         printf("%d/%d: write - fstat64 %s failed %d\n",
2647                                 procid, opno, f.path, errno);
2648                 free_pathname(&f);
2649                 close(fd);
2650                 return;
2651         }
2652         lr = ((__int64_t)random() << 32) + random();
2653         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2654         off %= maxfsize;
2655         lseek64(fd, off, SEEK_SET);
2656         len = (random() % FILELEN_MAX) + 1;
2657         buf = malloc(len);
2658         memset(buf, nameseq & 0xff, len);
2659         e = write(fd, buf, len) < 0 ? errno : 0;
2660         free(buf);
2661         if (v)
2662                 printf("%d/%d: write %s [%lld,%d] %d\n",
2663                         procid, opno, f.path, (long long)off, (int)len, e);
2664         free_pathname(&f);
2665         close(fd);
2666 }