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