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