Fix fsstress builds when setting the project identifier (fsx interface now).
[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 #if !defined(__sgi__)
1632         struct fsxattr  fsx;
1633 #endif
1634         int             fd;
1635         int             e;
1636         pathname_t      f;
1637         int             nbits;
1638         uint            p;
1639         int             v;
1640
1641         init_pathname(&f);
1642         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1643                 append_pathname(&f, ".");
1644         fd = open_path(&f, O_RDWR);
1645         e = fd < 0 ? errno : 0;
1646         check_cwd();
1647
1648         p = (uid_t)random();
1649         e = MIN(idmodulo, XFS_PROJIDMODULO_MAX);
1650         nbits = (int)(random() % e);
1651         p &= (1 << nbits) - 1;
1652 #if defined(__sgi__)
1653         e = fchproj(fd, p);
1654 #else
1655         if ((e = xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &fsx)) == 0) {
1656                 fsx.fsx_projid = p;
1657                 e = xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &fsx);
1658         }
1659 #endif
1660         if (v)
1661                 printf("%d/%d: chproj %s %u %d\n", procid, opno, f.path, p, e);
1662         free_pathname(&f);
1663         close(fd);
1664 }
1665
1666 void
1667 creat_f(int opno, long r)
1668 {
1669         struct fsxattr  a;
1670         int             e;
1671         int             e1;
1672         int             extsize;
1673         pathname_t      f;
1674         int             fd;
1675         fent_t          *fep;
1676         int             id;
1677         int             parid;
1678         int             type;
1679         int             v;
1680         int             v1;
1681
1682         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
1683                 parid = -1;
1684         else
1685                 parid = fep->id;
1686         init_pathname(&f);
1687         type = rtpct ? ((random() % 100) > rtpct ? FT_REG : FT_RTF) : FT_REG;
1688         if (type == FT_RTF)
1689                 extsize = (random() % 10) + 1;
1690         else
1691                 extsize = 0;
1692         e = generate_fname(fep, type, &f, &id, &v);
1693         v |= v1;
1694         if (!e) {
1695                 if (v) {
1696                         fent_to_name(&f, &flist[FT_DIR], fep);
1697                         printf("%d/%d: creat - no filename from %s\n",
1698                                 procid, opno, f.path);
1699                 }
1700                 free_pathname(&f);
1701                 return;
1702         }
1703         fd = creat_path(&f, 0666);
1704         e = fd < 0 ? errno : 0;
1705         e1 = 0;
1706         check_cwd();
1707         if (fd >= 0) {
1708                 if (extsize &&
1709                     xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
1710                         a.fsx_xflags |= XFS_XFLAG_REALTIME;
1711                         a.fsx_extsize =
1712                                 geom.rtextsize * geom.blocksize * extsize;
1713                         if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
1714                                 e1 = errno;
1715                 }
1716                 add_to_flist(type, id, parid);
1717                 close(fd);
1718         }
1719         if (v)
1720                 printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
1721                         extsize ? a.fsx_extsize : 0, e, e1);
1722         free_pathname(&f);
1723 }
1724
1725 void
1726 dread_f(int opno, long r)
1727 {
1728         __int64_t       align;
1729         char            *buf;
1730         struct dioattr  diob;
1731         int             e;
1732         pathname_t      f;
1733         int             fd;
1734         size_t          len;
1735         __int64_t       lr;
1736         off64_t         off;
1737         struct stat64   stb;
1738         int             v;
1739
1740         init_pathname(&f);
1741         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1742                 if (v)
1743                         printf("%d/%d: dread - no filename\n", procid, opno);
1744                 free_pathname(&f);
1745                 return;
1746         }
1747         fd = open_path(&f, O_RDONLY|O_DIRECT);
1748         e = fd < 0 ? errno : 0;
1749         check_cwd();
1750         if (fd < 0) {
1751                 if (v)
1752                         printf("%d/%d: dread - open %s failed %d\n",
1753                                 procid, opno, f.path, e);
1754                 free_pathname(&f);
1755                 return;
1756         }
1757         if (fstat64(fd, &stb) < 0) {
1758                 if (v)
1759                         printf("%d/%d: dread - fstat64 %s failed %d\n",
1760                                 procid, opno, f.path, errno);
1761                 free_pathname(&f);
1762                 close(fd);
1763                 return;
1764         }
1765         if (stb.st_size == 0) {
1766                 if (v)
1767                         printf("%d/%d: dread - %s zero size\n", procid, opno,
1768                                 f.path);
1769                 free_pathname(&f);
1770                 close(fd);
1771                 return;
1772         }
1773         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
1774                 if (v)
1775                         printf(
1776                         "%d/%d: dread - xfsctl(XFS_IOC_DIOINFO) %s failed %d\n",
1777                                 procid, opno, f.path, errno);
1778                 free_pathname(&f);
1779                 close(fd);
1780                 return;
1781         }
1782         align = (__int64_t)diob.d_miniosz;
1783         lr = ((__int64_t)random() << 32) + random();
1784         off = (off64_t)(lr % stb.st_size);
1785         off -= (off % align);
1786         lseek64(fd, off, SEEK_SET);
1787         len = (random() % FILELEN_MAX) + 1;
1788         len -= (len % align);
1789         if (len <= 0)
1790                 len = align;
1791         else if (len > diob.d_maxiosz) 
1792                 len = diob.d_maxiosz;
1793         buf = memalign(diob.d_mem, len);
1794         e = read(fd, buf, len) < 0 ? errno : 0;
1795         free(buf);
1796         if (v)
1797                 printf("%d/%d: dread %s [%lld,%d] %d\n",
1798                         procid, opno, f.path, (long long)off, (int)len, e);
1799         free_pathname(&f);
1800         close(fd);
1801 }
1802
1803 void
1804 dwrite_f(int opno, long r)
1805 {
1806         __int64_t       align;
1807         char            *buf;
1808         struct dioattr  diob;
1809         int             e;
1810         pathname_t      f;
1811         int             fd;
1812         size_t          len;
1813         __int64_t       lr;
1814         off64_t         off;
1815         struct stat64   stb;
1816         int             v;
1817
1818         init_pathname(&f);
1819         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1820                 if (v)
1821                         printf("%d/%d: dwrite - no filename\n", procid, opno);
1822                 free_pathname(&f);
1823                 return;
1824         }
1825         fd = open_path(&f, O_WRONLY|O_DIRECT);
1826         e = fd < 0 ? errno : 0;
1827         check_cwd();
1828         if (fd < 0) {
1829                 if (v)
1830                         printf("%d/%d: dwrite - open %s failed %d\n",
1831                                 procid, opno, f.path, e);
1832                 free_pathname(&f);
1833                 return;
1834         }
1835         if (fstat64(fd, &stb) < 0) {
1836                 if (v)
1837                         printf("%d/%d: dwrite - fstat64 %s failed %d\n",
1838                                 procid, opno, f.path, errno);
1839                 free_pathname(&f);
1840                 close(fd);
1841                 return;
1842         }
1843         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
1844                 if (v)
1845                         printf("%d/%d: dwrite - xfsctl(XFS_IOC_DIOINFO)"
1846                                 " %s failed %d\n",
1847                                 procid, opno, f.path, errno);
1848                 free_pathname(&f);
1849                 close(fd);
1850                 return;
1851         }
1852         align = (__int64_t)diob.d_miniosz;
1853         lr = ((__int64_t)random() << 32) + random();
1854         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1855         off -= (off % align);
1856         lseek64(fd, off, SEEK_SET);
1857         len = (random() % FILELEN_MAX) + 1;
1858         len -= (len % align);
1859         if (len <= 0)
1860                 len = align;
1861         else if (len > diob.d_maxiosz) 
1862                 len = diob.d_maxiosz;
1863         buf = memalign(diob.d_mem, len);
1864         off %= maxfsize;
1865         lseek64(fd, off, SEEK_SET);
1866         memset(buf, nameseq & 0xff, len);
1867         e = write(fd, buf, len) < 0 ? errno : 0;
1868         free(buf);
1869         if (v)
1870                 printf("%d/%d: dwrite %s [%lld,%d] %d\n",
1871                         procid, opno, f.path, (long long)off, (int)len, e);
1872         free_pathname(&f);
1873         close(fd);
1874 }
1875
1876 void
1877 fdatasync_f(int opno, long r)
1878 {
1879         int             e;
1880         pathname_t      f;
1881         int             fd;
1882         int             v;
1883
1884         init_pathname(&f);
1885         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1886                 if (v)
1887                         printf("%d/%d: fdatasync - no filename\n",
1888                                 procid, opno);
1889                 free_pathname(&f);
1890                 return;
1891         }
1892         fd = open_path(&f, O_WRONLY);
1893         e = fd < 0 ? errno : 0;
1894         check_cwd();
1895         if (fd < 0) {
1896                 if (v)
1897                         printf("%d/%d: fdatasync - open %s failed %d\n",
1898                                 procid, opno, f.path, e);
1899                 free_pathname(&f);
1900                 return;
1901         }
1902         e = fdatasync(fd) < 0 ? errno : 0;
1903         if (v)
1904                 printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e);
1905         free_pathname(&f);
1906         close(fd);
1907 }
1908
1909 void
1910 freesp_f(int opno, long r)
1911 {
1912         int             e;
1913         pathname_t      f;
1914         int             fd;
1915         struct xfs_flock64      fl;
1916         __int64_t       lr;
1917         off64_t         off;
1918         struct stat64   stb;
1919         int             v;
1920
1921         init_pathname(&f);
1922         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1923                 if (v)
1924                         printf("%d/%d: freesp - no filename\n", procid, opno);
1925                 free_pathname(&f);
1926                 return;
1927         }
1928         fd = open_path(&f, O_RDWR);
1929         e = fd < 0 ? errno : 0;
1930         check_cwd();
1931         if (fd < 0) {
1932                 if (v)
1933                         printf("%d/%d: freesp - open %s failed %d\n",
1934                                 procid, opno, f.path, e);
1935                 free_pathname(&f);
1936                 return;
1937         }
1938         if (fstat64(fd, &stb) < 0) {
1939                 if (v)
1940                         printf("%d/%d: freesp - fstat64 %s failed %d\n",
1941                                 procid, opno, f.path, errno);
1942                 free_pathname(&f);
1943                 close(fd);
1944                 return;
1945         }
1946         lr = ((__int64_t)random() << 32) + random();
1947         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1948         off %= maxfsize;
1949         fl.l_whence = SEEK_SET;
1950         fl.l_start = off;
1951         fl.l_len = 0;
1952         e = xfsctl(f.path, fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
1953         if (v)
1954                 printf("%d/%d: xfsctl(XFS_IOC_FREESP64) %s %lld 0 %d\n",
1955                         procid, opno, f.path, (long long)off, e);
1956         free_pathname(&f);
1957         close(fd);
1958 }
1959
1960 void
1961 fsync_f(int opno, long r)
1962 {
1963         int             e;
1964         pathname_t      f;
1965         int             fd;
1966         int             v;
1967
1968         init_pathname(&f);
1969         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1970                 if (v)
1971                         printf("%d/%d: fsync - no filename\n", procid, opno);
1972                 free_pathname(&f);
1973                 return;
1974         }
1975         fd = open_path(&f, O_WRONLY);
1976         e = fd < 0 ? errno : 0;
1977         check_cwd();
1978         if (fd < 0) {
1979                 if (v)
1980                         printf("%d/%d: fsync - open %s failed %d\n",
1981                                 procid, opno, f.path, e);
1982                 free_pathname(&f);
1983                 return;
1984         }
1985         e = fsync(fd) < 0 ? errno : 0;
1986         if (v)
1987                 printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e);
1988         free_pathname(&f);
1989         close(fd);
1990 }
1991
1992 void
1993 getdents_f(int opno, long r)
1994 {
1995         DIR             *dir;
1996         pathname_t      f;
1997         int             v;
1998
1999         init_pathname(&f);
2000         if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
2001                 append_pathname(&f, ".");
2002         dir = opendir_path(&f);
2003         check_cwd();
2004         if (dir == NULL) {
2005                 if (v)
2006                         printf("%d/%d: getdents - can't open %s\n",
2007                                 procid, opno, f.path);
2008                 free_pathname(&f);
2009                 return;
2010         }
2011         while (readdir64(dir) != NULL)
2012                 continue;
2013         if (v)
2014                 printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
2015         free_pathname(&f);
2016         closedir(dir);
2017 }
2018
2019 void
2020 link_f(int opno, long r)
2021 {
2022         int             e;
2023         pathname_t      f;
2024         fent_t          *fep;
2025         flist_t         *flp;
2026         int             id;
2027         pathname_t      l;
2028         int             parid;
2029         int             v;
2030         int             v1;
2031
2032         init_pathname(&f);
2033         if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
2034                 if (v1)
2035                         printf("%d/%d: link - no file\n", procid, opno);
2036                 free_pathname(&f);
2037                 return;
2038         }
2039         if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
2040                 parid = -1;
2041         else
2042                 parid = fep->id;
2043         v |= v1;
2044         init_pathname(&l);
2045         e = generate_fname(fep, flp - flist, &l, &id, &v1);
2046         v |= v1;
2047         if (!e) {
2048                 if (v) {
2049                         fent_to_name(&l, &flist[FT_DIR], fep);
2050                         printf("%d/%d: link - no filename from %s\n",
2051                                 procid, opno, l.path);
2052                 }
2053                 free_pathname(&l);
2054                 free_pathname(&f);
2055                 return;
2056         }
2057         e = link_path(&f, &l) < 0 ? errno : 0;
2058         check_cwd();
2059         if (e == 0)
2060                 add_to_flist(flp - flist, id, parid);
2061         if (v)
2062                 printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
2063                         e);
2064         free_pathname(&l);
2065         free_pathname(&f);
2066 }
2067
2068 void
2069 mkdir_f(int opno, long r)
2070 {
2071         int             e;
2072         pathname_t      f;
2073         fent_t          *fep;
2074         int             id;
2075         int             parid;
2076         int             v;
2077         int             v1;
2078
2079         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2080                 parid = -1;
2081         else
2082                 parid = fep->id;
2083         init_pathname(&f);
2084         e = generate_fname(fep, FT_DIR, &f, &id, &v1);
2085         v |= v1;
2086         if (!e) {
2087                 if (v) {
2088                         fent_to_name(&f, &flist[FT_DIR], fep);
2089                         printf("%d/%d: mkdir - no filename from %s\n",
2090                                 procid, opno, f.path);
2091                 }
2092                 free_pathname(&f);
2093                 return;
2094         }
2095         e = mkdir_path(&f, 0777) < 0 ? errno : 0;
2096         check_cwd();
2097         if (e == 0)
2098                 add_to_flist(FT_DIR, id, parid);
2099         if (v)
2100                 printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
2101         free_pathname(&f);
2102 }
2103
2104 void
2105 mknod_f(int opno, long r)
2106 {
2107         int             e;
2108         pathname_t      f;
2109         fent_t          *fep;
2110         int             id;
2111         int             parid;
2112         int             v;
2113         int             v1;
2114
2115         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2116                 parid = -1;
2117         else
2118                 parid = fep->id;
2119         init_pathname(&f);
2120         e = generate_fname(fep, FT_DEV, &f, &id, &v1);
2121         v |= v1;
2122         if (!e) {
2123                 if (v) {
2124                         fent_to_name(&f, &flist[FT_DIR], fep);
2125                         printf("%d/%d: mknod - no filename from %s\n",
2126                                 procid, opno, f.path);
2127                 }
2128                 free_pathname(&f);
2129                 return;
2130         }
2131         e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
2132         check_cwd();
2133         if (e == 0)
2134                 add_to_flist(FT_DEV, id, parid);
2135         if (v)
2136                 printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
2137         free_pathname(&f);
2138 }
2139
2140 void
2141 read_f(int opno, long r)
2142 {
2143         char            *buf;
2144         int             e;
2145         pathname_t      f;
2146         int             fd;
2147         size_t          len;
2148         __int64_t       lr;
2149         off64_t         off;
2150         struct stat64   stb;
2151         int             v;
2152
2153         init_pathname(&f);
2154         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2155                 if (v)
2156                         printf("%d/%d: read - no filename\n", procid, opno);
2157                 free_pathname(&f);
2158                 return;
2159         }
2160         fd = open_path(&f, O_RDONLY);
2161         e = fd < 0 ? errno : 0;
2162         check_cwd();
2163         if (fd < 0) {
2164                 if (v)
2165                         printf("%d/%d: read - open %s failed %d\n",
2166                                 procid, opno, f.path, e);
2167                 free_pathname(&f);
2168                 return;
2169         }
2170         if (fstat64(fd, &stb) < 0) {
2171                 if (v)
2172                         printf("%d/%d: read - fstat64 %s failed %d\n",
2173                                 procid, opno, f.path, errno);
2174                 free_pathname(&f);
2175                 close(fd);
2176                 return;
2177         }
2178         if (stb.st_size == 0) {
2179                 if (v)
2180                         printf("%d/%d: read - %s zero size\n", procid, opno,
2181                                 f.path);
2182                 free_pathname(&f);
2183                 close(fd);
2184                 return;
2185         }
2186         lr = ((__int64_t)random() << 32) + random();
2187         off = (off64_t)(lr % stb.st_size);
2188         lseek64(fd, off, SEEK_SET);
2189         len = (random() % FILELEN_MAX) + 1;
2190         buf = malloc(len);
2191         e = read(fd, buf, len) < 0 ? errno : 0;
2192         free(buf);
2193         if (v)
2194                 printf("%d/%d: read %s [%lld,%d] %d\n",
2195                         procid, opno, f.path, (long long)off, (int)len, e);
2196         free_pathname(&f);
2197         close(fd);
2198 }
2199
2200 void
2201 readlink_f(int opno, long r)
2202 {
2203         char            buf[PATH_MAX];
2204         int             e;
2205         pathname_t      f;
2206         int             v;
2207
2208         init_pathname(&f);
2209         if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
2210                 if (v)
2211                         printf("%d/%d: readlink - no filename\n", procid, opno);
2212                 free_pathname(&f);
2213                 return;
2214         }
2215         e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
2216         check_cwd();
2217         if (v)
2218                 printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e);
2219         free_pathname(&f);
2220 }
2221
2222 void
2223 rename_f(int opno, long r)
2224 {
2225         fent_t          *dfep;
2226         int             e;
2227         pathname_t      f;
2228         fent_t          *fep;
2229         flist_t         *flp;
2230         int             id;
2231         pathname_t      newf;
2232         int             oldid;
2233         int             parid;
2234         int             v;
2235         int             v1;
2236
2237         init_pathname(&f);
2238         if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
2239                 if (v1)
2240                         printf("%d/%d: rename - no filename\n", procid, opno);
2241                 free_pathname(&f);
2242                 return;
2243         }
2244         if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
2245                 parid = -1;
2246         else
2247                 parid = dfep->id;
2248         v |= v1;
2249         init_pathname(&newf);
2250         e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
2251         v |= v1;
2252         if (!e) {
2253                 if (v) {
2254                         fent_to_name(&f, &flist[FT_DIR], dfep);
2255                         printf("%d/%d: rename - no filename from %s\n",
2256                                 procid, opno, f.path);
2257                 }
2258                 free_pathname(&newf);
2259                 free_pathname(&f);
2260                 return;
2261         }
2262         e = rename_path(&f, &newf) < 0 ? errno : 0;
2263         check_cwd();
2264         if (e == 0) {
2265                 if (flp - flist == FT_DIR) {
2266                         oldid = fep->id;
2267                         fix_parent(oldid, id);
2268                 }
2269                 del_from_flist(flp - flist, fep - flp->fents);
2270                 add_to_flist(flp - flist, id, parid);
2271         }
2272         if (v)
2273                 printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
2274                         newf.path, e);
2275         free_pathname(&newf);
2276         free_pathname(&f);
2277 }
2278
2279 void
2280 resvsp_f(int opno, long r)
2281 {
2282         int             e;
2283         pathname_t      f;
2284         int             fd;
2285         struct xfs_flock64      fl;
2286         __int64_t       lr;
2287         off64_t         off;
2288         struct stat64   stb;
2289         int             v;
2290
2291         init_pathname(&f);
2292         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2293                 if (v)
2294                         printf("%d/%d: resvsp - no filename\n", procid, opno);
2295                 free_pathname(&f);
2296                 return;
2297         }
2298         fd = open_path(&f, O_RDWR);
2299         e = fd < 0 ? errno : 0;
2300         check_cwd();
2301         if (fd < 0) {
2302                 if (v)
2303                         printf("%d/%d: resvsp - open %s failed %d\n",
2304                                 procid, opno, f.path, e);
2305                 free_pathname(&f);
2306                 return;
2307         }
2308         if (fstat64(fd, &stb) < 0) {
2309                 if (v)
2310                         printf("%d/%d: resvsp - fstat64 %s failed %d\n",
2311                                 procid, opno, f.path, errno);
2312                 free_pathname(&f);
2313                 close(fd);
2314                 return;
2315         }
2316         lr = ((__int64_t)random() << 32) + random();
2317         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2318         off %= maxfsize;
2319         fl.l_whence = SEEK_SET;
2320         fl.l_start = off;
2321         fl.l_len = (off64_t)(random() % (1024 * 1024));
2322         e = xfsctl(f.path, fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
2323         if (v)
2324                 printf("%d/%d: xfsctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n",
2325                         procid, opno, f.path,
2326                         (long long)off, (long long)fl.l_len, e);
2327         free_pathname(&f);
2328         close(fd);
2329 }
2330
2331 void
2332 rmdir_f(int opno, long r)
2333 {
2334         int             e;
2335         pathname_t      f;
2336         fent_t          *fep;
2337         int             v;
2338
2339         init_pathname(&f);
2340         if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
2341                 if (v)
2342                         printf("%d/%d: rmdir - no directory\n", procid, opno);
2343                 free_pathname(&f);
2344                 return;
2345         }
2346         e = rmdir_path(&f) < 0 ? errno : 0;
2347         check_cwd();
2348         if (e == 0)
2349                 del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
2350         if (v)
2351                 printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e);
2352         free_pathname(&f);
2353 }
2354
2355 void
2356 stat_f(int opno, long r)
2357 {
2358         int             e;
2359         pathname_t      f;
2360         struct stat64   stb;
2361         int             v;
2362
2363         init_pathname(&f);
2364         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
2365                 if (v)
2366                         printf("%d/%d: stat - no entries\n", procid, opno);
2367                 free_pathname(&f);
2368                 return;
2369         }
2370         e = lstat64_path(&f, &stb) < 0 ? errno : 0;
2371         check_cwd();
2372         if (v)
2373                 printf("%d/%d: stat %s %d\n", procid, opno, f.path, e);
2374         free_pathname(&f);
2375 }
2376
2377 void
2378 symlink_f(int opno, long r)
2379 {
2380         int             e;
2381         pathname_t      f;
2382         fent_t          *fep;
2383         int             i;
2384         int             id;
2385         int             len;
2386         int             parid;
2387         int             v;
2388         int             v1;
2389         char            *val;
2390
2391         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
2392                 parid = -1;
2393         else
2394                 parid = fep->id;
2395         init_pathname(&f);
2396         e = generate_fname(fep, FT_SYM, &f, &id, &v1);
2397         v |= v1;
2398         if (!e) {
2399                 if (v) {
2400                         fent_to_name(&f, &flist[FT_DIR], fep);
2401                         printf("%d/%d: symlink - no filename from %s\n",
2402                                 procid, opno, f.path);
2403                 }
2404                 free_pathname(&f);
2405                 return;
2406         }
2407         len = (int)(random() % PATH_MAX);
2408         val = malloc(len + 1);
2409         if (len)
2410                 memset(val, 'x', len);
2411         val[len] = '\0';
2412         for (i = 10; i < len - 1; i += 10)
2413                 val[i] = '/';
2414         e = symlink_path(val, &f) < 0 ? errno : 0;
2415         check_cwd();
2416         if (e == 0)
2417                 add_to_flist(FT_SYM, id, parid);
2418         free(val);
2419         if (v)
2420                 printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
2421         free_pathname(&f);
2422 }
2423
2424 /* ARGSUSED */
2425 void
2426 sync_f(int opno, long r)
2427 {
2428         sync();
2429         if (verbose)
2430                 printf("%d/%d: sync\n", procid, opno);
2431 }
2432
2433 void
2434 truncate_f(int opno, long r)
2435 {
2436         int             e;
2437         pathname_t      f;
2438         __int64_t       lr;
2439         off64_t         off;
2440         struct stat64   stb;
2441         int             v;
2442
2443         init_pathname(&f);
2444         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2445                 if (v)
2446                         printf("%d/%d: truncate - no filename\n", procid, opno);
2447                 free_pathname(&f);
2448                 return;
2449         }
2450         e = stat64_path(&f, &stb) < 0 ? errno : 0;
2451         check_cwd();
2452         if (e > 0) {
2453                 if (v)
2454                         printf("%d/%d: truncate - stat64 %s failed %d\n",
2455                                 procid, opno, f.path, e);
2456                 free_pathname(&f);
2457                 return;
2458         }
2459         lr = ((__int64_t)random() << 32) + random();
2460         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2461         off %= maxfsize;
2462         e = truncate64_path(&f, off) < 0 ? errno : 0;
2463         check_cwd();
2464         if (v)
2465                 printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path,
2466                         (long long)off, e);
2467         free_pathname(&f);
2468 }
2469
2470 void
2471 unlink_f(int opno, long r)
2472 {
2473         int             e;
2474         pathname_t      f;
2475         fent_t          *fep;
2476         flist_t         *flp;
2477         int             v;
2478
2479         init_pathname(&f);
2480         if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
2481                 if (v)
2482                         printf("%d/%d: unlink - no file\n", procid, opno);
2483                 free_pathname(&f);
2484                 return;
2485         }
2486         e = unlink_path(&f) < 0 ? errno : 0;
2487         check_cwd();
2488         if (e == 0)
2489                 del_from_flist(flp - flist, fep - flp->fents);
2490         if (v)
2491                 printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e);
2492         free_pathname(&f);
2493 }
2494
2495 void
2496 unresvsp_f(int opno, long r)
2497 {
2498         int             e;
2499         pathname_t      f;
2500         int             fd;
2501         struct xfs_flock64      fl;
2502         __int64_t       lr;
2503         off64_t         off;
2504         struct stat64   stb;
2505         int             v;
2506
2507         init_pathname(&f);
2508         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2509                 if (v)
2510                         printf("%d/%d: unresvsp - no filename\n", procid, opno);
2511                 free_pathname(&f);
2512                 return;
2513         }
2514         fd = open_path(&f, O_RDWR);
2515         e = fd < 0 ? errno : 0;
2516         check_cwd();
2517         if (fd < 0) {
2518                 if (v)
2519                         printf("%d/%d: unresvsp - open %s failed %d\n",
2520                                 procid, opno, f.path, e);
2521                 free_pathname(&f);
2522                 return;
2523         }
2524         if (fstat64(fd, &stb) < 0) {
2525                 if (v)
2526                         printf("%d/%d: unresvsp - fstat64 %s failed %d\n",
2527                                 procid, opno, f.path, errno);
2528                 free_pathname(&f);
2529                 close(fd);
2530                 return;
2531         }
2532         lr = ((__int64_t)random() << 32) + random();
2533         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2534         off %= maxfsize;
2535         fl.l_whence = SEEK_SET;
2536         fl.l_start = off;
2537         fl.l_len = (off64_t)(random() % (1 << 20));
2538         e = xfsctl(f.path, fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
2539         if (v)
2540                 printf("%d/%d: xfsctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n",
2541                         procid, opno, f.path,
2542                         (long long)off, (long long)fl.l_len, e);
2543         free_pathname(&f);
2544         close(fd);
2545 }
2546
2547 void
2548 write_f(int opno, long r)
2549 {
2550         char            *buf;
2551         int             e;
2552         pathname_t      f;
2553         int             fd;
2554         size_t          len;
2555         __int64_t       lr;
2556         off64_t         off;
2557         struct stat64   stb;
2558         int             v;
2559
2560         init_pathname(&f);
2561         if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
2562                 if (v)
2563                         printf("%d/%d: write - no filename\n", procid, opno);
2564                 free_pathname(&f);
2565                 return;
2566         }
2567         fd = open_path(&f, O_WRONLY);
2568         e = fd < 0 ? errno : 0;
2569         check_cwd();
2570         if (fd < 0) {
2571                 if (v)
2572                         printf("%d/%d: write - open %s failed %d\n",
2573                                 procid, opno, f.path, e);
2574                 free_pathname(&f);
2575                 return;
2576         }
2577         if (fstat64(fd, &stb) < 0) {
2578                 if (v)
2579                         printf("%d/%d: write - fstat64 %s failed %d\n",
2580                                 procid, opno, f.path, errno);
2581                 free_pathname(&f);
2582                 close(fd);
2583                 return;
2584         }
2585         lr = ((__int64_t)random() << 32) + random();
2586         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2587         off %= maxfsize;
2588         lseek64(fd, off, SEEK_SET);
2589         len = (random() % FILELEN_MAX) + 1;
2590         buf = malloc(len);
2591         memset(buf, nameseq & 0xff, len);
2592         e = write(fd, buf, len) < 0 ? errno : 0;
2593         free(buf);
2594         if (v)
2595                 printf("%d/%d: write %s [%lld,%d] %d\n",
2596                         procid, opno, f.path, (long long)off, (int)len, e);
2597         free_pathname(&f);
2598         close(fd);
2599 }