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