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