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