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