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