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