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