fsx: check ENOSYS in test_copy_range() & test_fallocate()
[xfstests-dev.git] / ltp / fsstress.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2000-2002 Silicon Graphics, Inc.
4  * All Rights Reserved.
5  */
6
7 #include <linux/fs.h>
8 #include <setjmp.h>
9 #include <sys/uio.h>
10 #include <stddef.h>
11 #include "global.h"
12
13 #ifdef HAVE_ATTR_ATTRIBUTES_H
14 #include <attr/attributes.h>
15 #endif
16 #ifdef HAVE_LINUX_FIEMAP_H
17 #include <linux/fiemap.h>
18 #endif
19 #ifndef HAVE_ATTR_LIST
20 #define attr_list(path, buf, size, flags, cursor) (errno = -ENOSYS, -1)
21 #endif
22 #ifdef HAVE_SYS_PRCTL_H
23 #include <sys/prctl.h>
24 #endif
25 #ifdef AIO
26 #include <libaio.h>
27 io_context_t    io_ctx;
28 #endif
29 #include <sys/syscall.h>
30
31 #ifndef FS_IOC_GETFLAGS
32 #define FS_IOC_GETFLAGS                 _IOR('f', 1, long)
33 #endif
34 #ifndef FS_IOC_SETFLAGS
35 #define FS_IOC_SETFLAGS                 _IOW('f', 2, long)
36 #endif
37
38 #include <math.h>
39 #define XFS_ERRTAG_MAX          17
40 #define XFS_IDMODULO_MAX        31      /* user/group IDs (1 << x)  */
41 #define XFS_PROJIDMODULO_MAX    16      /* project IDs (1 << x)     */
42 #ifndef IOV_MAX
43 #define IOV_MAX 1024
44 #endif
45
46 #define FILELEN_MAX             (32*4096)
47
48 typedef enum {
49         OP_AFSYNC,
50         OP_ALLOCSP,
51         OP_AREAD,
52         OP_ATTR_REMOVE,
53         OP_ATTR_SET,
54         OP_AWRITE,
55         OP_BULKSTAT,
56         OP_BULKSTAT1,
57         OP_CHOWN,
58         OP_CLONERANGE,
59         OP_COPYRANGE,
60         OP_CREAT,
61         OP_DEDUPERANGE,
62         OP_DREAD,
63         OP_DWRITE,
64         OP_FALLOCATE,
65         OP_FDATASYNC,
66         OP_FIEMAP,
67         OP_FREESP,
68         OP_FSYNC,
69         OP_GETATTR,
70         OP_GETDENTS,
71         OP_LINK,
72         OP_MKDIR,
73         OP_MKNOD,
74         OP_MREAD,
75         OP_MWRITE,
76         OP_PUNCH,
77         OP_ZERO,
78         OP_COLLAPSE,
79         OP_INSERT,
80         OP_READ,
81         OP_READLINK,
82         OP_READV,
83         OP_RENAME,
84         OP_RESVSP,
85         OP_RMDIR,
86         OP_SETATTR,
87         OP_SETXATTR,
88         OP_STAT,
89         OP_SYMLINK,
90         OP_SYNC,
91         OP_TRUNCATE,
92         OP_UNLINK,
93         OP_UNRESVSP,
94         OP_WRITE,
95         OP_WRITEV,
96         OP_LAST
97 } opty_t;
98
99 typedef void (*opfnc_t)(int, long);
100
101 typedef struct opdesc {
102         opty_t  op;
103         char    *name;
104         opfnc_t func;
105         int     freq;
106         int     iswrite;
107 } opdesc_t;
108
109 typedef struct fent {
110         int     id;
111         int     parent;
112 } fent_t;
113
114 typedef struct flist {
115         int     nfiles;
116         int     nslots;
117         int     tag;
118         fent_t  *fents;
119 } flist_t;
120
121 typedef struct pathname {
122         int     len;
123         char    *path;
124 } pathname_t;
125
126 struct print_flags {
127         unsigned long mask;
128         const char *name;
129 };
130
131 struct print_string {
132         char *buffer;
133         int len;
134         int max;
135 };
136
137 #define FT_DIR  0
138 #define FT_DIRm (1 << FT_DIR)
139 #define FT_REG  1
140 #define FT_REGm (1 << FT_REG)
141 #define FT_SYM  2
142 #define FT_SYMm (1 << FT_SYM)
143 #define FT_DEV  3
144 #define FT_DEVm (1 << FT_DEV)
145 #define FT_RTF  4
146 #define FT_RTFm (1 << FT_RTF)
147 #define FT_nft  5
148 #define FT_ANYm ((1 << FT_nft) - 1)
149 #define FT_REGFILE      (FT_REGm | FT_RTFm)
150 #define FT_NOTDIR       (FT_ANYm & ~FT_DIRm)
151
152 #define FLIST_SLOT_INCR 16
153 #define NDCACHE 64
154
155 #define MAXFSIZE        ((1ULL << 63) - 1ULL)
156 #define MAXFSIZE32      ((1ULL << 40) - 1ULL)
157
158 void    afsync_f(int, long);
159 void    allocsp_f(int, long);
160 void    aread_f(int, long);
161 void    attr_remove_f(int, long);
162 void    attr_set_f(int, long);
163 void    awrite_f(int, long);
164 void    bulkstat_f(int, long);
165 void    bulkstat1_f(int, long);
166 void    chown_f(int, long);
167 void    clonerange_f(int, long);
168 void    copyrange_f(int, long);
169 void    creat_f(int, long);
170 void    deduperange_f(int, long);
171 void    dread_f(int, long);
172 void    dwrite_f(int, long);
173 void    fallocate_f(int, long);
174 void    fdatasync_f(int, long);
175 void    fiemap_f(int, long);
176 void    freesp_f(int, long);
177 void    fsync_f(int, long);
178 void    getattr_f(int, long);
179 void    getdents_f(int, long);
180 void    link_f(int, long);
181 void    mkdir_f(int, long);
182 void    mknod_f(int, long);
183 void    mread_f(int, long);
184 void    mwrite_f(int, long);
185 void    punch_f(int, long);
186 void    zero_f(int, long);
187 void    collapse_f(int, long);
188 void    insert_f(int, long);
189 void    read_f(int, long);
190 void    readlink_f(int, long);
191 void    readv_f(int, long);
192 void    rename_f(int, long);
193 void    resvsp_f(int, long);
194 void    rmdir_f(int, long);
195 void    setattr_f(int, long);
196 void    setxattr_f(int, long);
197 void    stat_f(int, long);
198 void    symlink_f(int, long);
199 void    sync_f(int, long);
200 void    truncate_f(int, long);
201 void    unlink_f(int, long);
202 void    unresvsp_f(int, long);
203 void    write_f(int, long);
204 void    writev_f(int, long);
205
206 opdesc_t        ops[] = {
207      /* { OP_ENUM, "name", function, freq, iswrite }, */
208         { OP_AFSYNC, "afsync", afsync_f, 0, 1 },
209         { OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 },
210         { OP_AREAD, "aread", aread_f, 1, 0 },
211         { OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 },
212         { OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 },
213         { OP_AWRITE, "awrite", awrite_f, 1, 1 },
214         { OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0 },
215         { OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0 },
216         { OP_CHOWN, "chown", chown_f, 3, 1 },
217         { OP_CLONERANGE, "clonerange", clonerange_f, 4, 1 },
218         { OP_COPYRANGE, "copyrange", copyrange_f, 4, 1 },
219         { OP_CREAT, "creat", creat_f, 4, 1 },
220         { OP_DEDUPERANGE, "deduperange", deduperange_f, 4, 1},
221         { OP_DREAD, "dread", dread_f, 4, 0 },
222         { OP_DWRITE, "dwrite", dwrite_f, 4, 1 },
223         { OP_FALLOCATE, "fallocate", fallocate_f, 1, 1 },
224         { OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 },
225         { OP_FIEMAP, "fiemap", fiemap_f, 1, 1 },
226         { OP_FREESP, "freesp", freesp_f, 1, 1 },
227         { OP_FSYNC, "fsync", fsync_f, 1, 1 },
228         { OP_GETATTR, "getattr", getattr_f, 1, 0 },
229         { OP_GETDENTS, "getdents", getdents_f, 1, 0 },
230         { OP_LINK, "link", link_f, 1, 1 },
231         { OP_MKDIR, "mkdir", mkdir_f, 2, 1 },
232         { OP_MKNOD, "mknod", mknod_f, 2, 1 },
233         { OP_MREAD, "mread", mread_f, 2, 0 },
234         { OP_MWRITE, "mwrite", mwrite_f, 2, 1 },
235         { OP_PUNCH, "punch", punch_f, 1, 1 },
236         { OP_ZERO, "zero", zero_f, 1, 1 },
237         { OP_COLLAPSE, "collapse", collapse_f, 1, 1 },
238         { OP_INSERT, "insert", insert_f, 1, 1 },
239         { OP_READ, "read", read_f, 1, 0 },
240         { OP_READLINK, "readlink", readlink_f, 1, 0 },
241         { OP_READV, "readv", readv_f, 1, 0 },
242         { OP_RENAME, "rename", rename_f, 2, 1 },
243         { OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
244         { OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
245         { OP_SETATTR, "setattr", setattr_f, 0, 1 },
246         { OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
247         { OP_STAT, "stat", stat_f, 1, 0 },
248         { OP_SYMLINK, "symlink", symlink_f, 2, 1 },
249         { OP_SYNC, "sync", sync_f, 1, 1 },
250         { OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
251         { OP_UNLINK, "unlink", unlink_f, 1, 1 },
252         { OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1 },
253         { OP_WRITE, "write", write_f, 4, 1 },
254         { OP_WRITEV, "writev", writev_f, 4, 1 },
255 }, *ops_end;
256
257 flist_t flist[FT_nft] = {
258         { 0, 0, 'd', NULL },
259         { 0, 0, 'f', NULL },
260         { 0, 0, 'l', NULL },
261         { 0, 0, 'c', NULL },
262         { 0, 0, 'r', NULL },
263 };
264
265 int             dcache[NDCACHE];
266 int             errrange;
267 int             errtag;
268 opty_t          *freq_table;
269 int             freq_table_size;
270 xfs_fsop_geom_t geom;
271 char            *homedir;
272 int             *ilist;
273 int             ilistlen;
274 off64_t         maxfsize;
275 char            *myprog;
276 int             namerand;
277 int             nameseq;
278 int             nops;
279 int             nproc = 1;
280 int             operations = 1;
281 unsigned int    idmodulo = XFS_IDMODULO_MAX;
282 unsigned int    attr_mask = ~0;
283 int             procid;
284 int             rtpct;
285 unsigned long   seed = 0;
286 ino_t           top_ino;
287 int             cleanup = 0;
288 int             verbose = 0;
289 int             verifiable_log = 0;
290 sig_atomic_t    should_stop = 0;
291 sigjmp_buf      *sigbus_jmp = NULL;
292 char            *execute_cmd = NULL;
293 int             execute_freq = 1;
294 struct print_string     flag_str = {0};
295
296 void    add_to_flist(int, int, int);
297 void    append_pathname(pathname_t *, char *);
298 int     attr_list_path(pathname_t *, char *, const int, int, attrlist_cursor_t *);
299 int     attr_remove_path(pathname_t *, const char *, int);
300 int     attr_set_path(pathname_t *, const char *, const char *, const int, int);
301 void    check_cwd(void);
302 void    cleanup_flist(void);
303 int     creat_path(pathname_t *, mode_t);
304 void    dcache_enter(int, int);
305 void    dcache_init(void);
306 fent_t  *dcache_lookup(int);
307 void    dcache_purge(int);
308 void    del_from_flist(int, int);
309 int     dirid_to_name(char *, int);
310 void    doproc(void);
311 int     fent_to_name(pathname_t *, flist_t *, fent_t *);
312 void    fix_parent(int, int);
313 void    free_pathname(pathname_t *);
314 int     generate_fname(fent_t *, int, pathname_t *, int *, int *);
315 int     get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
316 void    init_pathname(pathname_t *);
317 int     lchown_path(pathname_t *, uid_t, gid_t);
318 int     link_path(pathname_t *, pathname_t *);
319 int     lstat64_path(pathname_t *, struct stat64 *);
320 void    make_freq_table(void);
321 int     mkdir_path(pathname_t *, mode_t);
322 int     mknod_path(pathname_t *, mode_t, dev_t);
323 void    namerandpad(int, char *, int);
324 int     open_path(pathname_t *, int);
325 DIR     *opendir_path(pathname_t *);
326 void    process_freq(char *);
327 int     readlink_path(pathname_t *, char *, size_t);
328 int     rename_path(pathname_t *, pathname_t *);
329 int     rmdir_path(pathname_t *);
330 void    separate_pathname(pathname_t *, char *, pathname_t *);
331 void    show_ops(int, char *);
332 int     stat64_path(pathname_t *, struct stat64 *);
333 int     symlink_path(const char *, pathname_t *);
334 int     truncate64_path(pathname_t *, off64_t);
335 int     unlink_path(pathname_t *);
336 void    usage(void);
337 void    write_freq(void);
338 void    zero_freq(void);
339
340 void sg_handler(int signum)
341 {
342         switch (signum) {
343         case SIGTERM:
344                 should_stop = 1;
345                 break;
346         case SIGBUS:
347                 /*
348                  * Only handle SIGBUS when mmap write to a hole and no
349                  * block can be allocated due to ENOSPC, abort otherwise.
350                  */
351                 if (sigbus_jmp) {
352                         siglongjmp(*sigbus_jmp, -1);
353                 } else {
354                         printf("Unknown SIGBUS is caught, Abort!\n");
355                         abort();
356                 }
357                 /* should not reach here */
358                 break;
359         default:
360                 break;
361         }
362 }
363
364 int main(int argc, char **argv)
365 {
366         char            buf[10];
367         int             c;
368         char            *dirname = NULL;
369         char            *logname = NULL;
370         char            rpath[PATH_MAX];
371         int             fd;
372         int             i;
373         int             j;
374         char            *p;
375         int             stat;
376         struct timeval  t;
377         ptrdiff_t       srval;
378         int             nousage = 0;
379         xfs_error_injection_t           err_inj;
380         struct sigaction action;
381         int             loops = 1;
382         const char      *allopts = "cd:e:f:i:l:m:M:n:o:p:rs:S:vVwx:X:zH";
383
384         errrange = errtag = 0;
385         umask(0);
386         nops = sizeof(ops) / sizeof(ops[0]);
387         ops_end = &ops[nops];
388         myprog = argv[0];
389         while ((c = getopt(argc, argv, allopts)) != -1) {
390                 switch (c) {
391                 case 'c':
392                         cleanup = 1;
393                         break;
394                 case 'd':
395                         dirname = optarg;
396                         break;
397                 case 'e':
398                         sscanf(optarg, "%d", &errtag);
399                         if (errtag < 0) {
400                                 errtag = -errtag;
401                                 errrange = 1;
402                         } else if (errtag == 0)
403                                 errtag = -1;
404                         if (errtag >= XFS_ERRTAG_MAX) {
405                                 fprintf(stderr,
406                                         "error tag %d too large (max %d)\n",
407                                         errtag, XFS_ERRTAG_MAX - 1);
408                                 exit(1);
409                         }
410                         break;
411                 case 'f':
412                         process_freq(optarg);
413                         break;
414                 case 'i':
415                         ilist = realloc(ilist, ++ilistlen * sizeof(*ilist));
416                         ilist[ilistlen - 1] = strtol(optarg, &p, 16);
417                         break;
418                 case 'm':
419                         idmodulo = strtoul(optarg, NULL, 0);
420                         if (idmodulo > XFS_IDMODULO_MAX) {
421                                 fprintf(stderr,
422                                         "chown modulo %d too big (max %d)\n",
423                                         idmodulo, XFS_IDMODULO_MAX);
424                                 exit(1);
425                         }
426                         break;
427                 case 'l':
428                         loops = atoi(optarg);
429                         break;
430                 case 'n':
431                         operations = atoi(optarg);
432                         break;
433                 case 'o':
434                         logname = optarg;
435                         break;
436
437                 case 'p':
438                         nproc = atoi(optarg);
439                         break;
440                 case 'r':
441                         namerand = 1;
442                         break;
443                 case 's':
444                         seed = strtoul(optarg, NULL, 0);
445                         break;
446                 case 'v':
447                         verbose = 1;
448                         break;
449                 case 'w':
450                         write_freq();
451                         break;
452                 case 'x':
453                         execute_cmd = optarg;
454                         break;
455                 case 'z':
456                         zero_freq();
457                         break;
458                 case 'M':
459                         attr_mask = strtoul(optarg, NULL, 0);
460                         break;
461                 case 'S':
462                         i = 0;
463                         if (optarg[0] == 'c')
464                                 i = 1;
465                         show_ops(i, NULL);
466                         printf("\n");
467                         nousage=1;
468                         break;
469                 case 'V':
470                         verifiable_log = 1;
471                         break;
472
473                 case 'X':
474                         execute_freq = strtoul(optarg, NULL, 0);
475                         break;
476                 case '?':
477                         fprintf(stderr, "%s - invalid parameters\n",
478                                 myprog);
479                         /* fall through */
480                 case 'H':
481                         usage();
482                         exit(1);
483                 }
484         }
485
486         if (!dirname) {
487             /* no directory specified */
488             if (!nousage) usage();
489             exit(1);
490         }
491
492         (void)mkdir(dirname, 0777);
493         if (logname && logname[0] != '/') {
494                 if (!getcwd(rpath, sizeof(rpath))){
495                         perror("getcwd failed");
496                         exit(1);
497                 }
498         } else {
499                 rpath[0] = '\0';
500         }
501         if (chdir(dirname) < 0) {
502                 perror(dirname);
503                 exit(1);
504         }
505         if (logname) {
506                 char path[PATH_MAX + NAME_MAX + 1];
507                 snprintf(path, sizeof(path), "%s/%s", rpath, logname);
508                 if (freopen(path, "a", stdout) == NULL) {
509                         perror("freopen logfile failed");
510                         exit(1);
511                 }
512         }
513         sprintf(buf, "fss%x", (unsigned int)getpid());
514         fd = creat(buf, 0666);
515         if (lseek64(fd, (off64_t)(MAXFSIZE32 + 1ULL), SEEK_SET) < 0)
516                 maxfsize = (off64_t)MAXFSIZE32;
517         else
518                 maxfsize = (off64_t)MAXFSIZE;
519         make_freq_table();
520         dcache_init();
521         setlinebuf(stdout);
522         if (!seed) {
523                 gettimeofday(&t, (void *)NULL);
524                 seed = (int)t.tv_sec ^ (int)t.tv_usec;
525                 printf("seed = %ld\n", seed);
526         }
527         i = xfsctl(buf, fd, XFS_IOC_FSGEOMETRY, &geom);
528         if (i >= 0 && geom.rtblocks)
529                 rtpct = MIN(MAX(geom.rtblocks * 100 /
530                                 (geom.rtblocks + geom.datablocks), 1), 99);
531         else
532                 rtpct = 0;
533         if (errtag != 0) {
534                 if (errrange == 0) {
535                         if (errtag <= 0) {
536                                 srandom(seed);
537                                 j = random() % 100;
538
539                                 for (i = 0; i < j; i++)
540                                         (void) random();
541
542                                 errtag = (random() % (XFS_ERRTAG_MAX-1)) + 1;
543                         }
544                 } else {
545                         srandom(seed);
546                         j = random() % 100;
547
548                         for (i = 0; i < j; i++)
549                                 (void) random();
550
551                         errtag += (random() % (XFS_ERRTAG_MAX - errtag));
552                 }
553                 printf("Injecting failure on tag #%d\n", errtag);
554                 err_inj.errtag = errtag;
555                 err_inj.fd = fd;
556                 srval = xfsctl(buf, fd, XFS_IOC_ERROR_INJECTION, &err_inj);
557                 if (srval < -1) {
558                         perror("fsstress - XFS_SYSSGI error injection call");
559                         close(fd);
560                         unlink(buf);
561                         exit(1);
562                 }
563         } else
564                 close(fd);
565
566         setpgid(0, 0);
567         action.sa_handler = sg_handler;
568         sigemptyset(&action.sa_mask);
569         action.sa_flags = 0;
570         if (sigaction(SIGTERM, &action, 0)) {
571                 perror("sigaction failed");
572                 exit(1);
573         }
574
575         for (i = 0; i < nproc; i++) {
576                 if (fork() == 0) {
577                         sigemptyset(&action.sa_mask);
578                         action.sa_handler = SIG_DFL;
579                         if (sigaction(SIGTERM, &action, 0))
580                                 return 1;
581                         action.sa_handler = sg_handler;
582                         if (sigaction(SIGBUS, &action, 0))
583                                 return 1;
584 #ifdef HAVE_SYS_PRCTL_H
585                         prctl(PR_SET_PDEATHSIG, SIGKILL);
586                         if (getppid() == 1) /* parent died already? */
587                                 return 0;
588 #endif
589                         if (logname) {
590                                 char path[PATH_MAX + NAME_MAX + 2 + 11];
591                                 snprintf(path, sizeof(path), "%s/%s.%d",
592                                          rpath, logname, i);
593                                 if (freopen(path, "a", stdout) == NULL) {
594                                         perror("freopen logfile failed");
595                                         exit(1);
596                                 }
597                         }
598                         procid = i;
599 #ifdef AIO
600                         if (io_setup(128, &io_ctx) != 0) {
601                                 fprintf(stderr, "io_setup failed");
602                                 exit(1);
603                         }
604 #endif
605                         for (i = 0; !loops || (i < loops); i++)
606                                 doproc();
607 #ifdef AIO
608                         if(io_destroy(io_ctx) != 0) {
609                                 fprintf(stderr, "io_destroy failed");
610                                 return 1;
611                         }
612 #endif
613
614                         cleanup_flist();
615                         free(freq_table);
616                         return 0;
617                 }
618         }
619         while (wait(&stat) > 0 && !should_stop) {
620                 continue;
621         }
622         action.sa_flags = SA_RESTART;
623         sigaction(SIGTERM, &action, 0);
624         kill(-getpid(), SIGTERM);
625         while (wait(&stat) > 0)
626                 continue;
627
628         if (errtag != 0) {
629                 err_inj.errtag = 0;
630                 err_inj.fd = fd;
631                 srval = xfsctl(buf, fd, XFS_IOC_ERROR_CLEARALL, &err_inj);
632                 if (srval != 0) {
633                         fprintf(stderr, "Bad ej clear on %s fd=%d (%d).\n",
634                                 buf, fd, errno);
635                         perror("xfsctl(XFS_IOC_ERROR_CLEARALL)");
636                         close(fd);
637                         exit(1);
638                 }
639                 close(fd);
640         }
641
642         free(freq_table);
643         unlink(buf);
644         return 0;
645 }
646
647 int
648 add_string(struct print_string *str, const char *add)
649 {
650         int len = strlen(add);
651
652         if (len <= 0)
653                 return 0;
654
655         if (len > (str->max - 1) - str->len) {
656                 str->len = str->max - 1;
657                 return 0;
658         }
659
660         memcpy(str->buffer + str->len, add, len);
661         str->len += len;
662         str->buffer[str->len] = '\0';
663
664         return len;
665 }
666
667 char *
668 translate_flags(int flags, const char *delim,
669                 const struct print_flags *flag_array)
670 {
671         int i, mask, first = 1;
672         const char *add;
673
674         if (!flag_str.buffer) {
675                 flag_str.buffer = malloc(4096);
676                 flag_str.max = 4096;
677                 flag_str.len = 0;
678         }
679         if (!flag_str.buffer)
680                 return NULL;
681         flag_str.len = 0;
682         flag_str.buffer[0] = '\0';
683
684         for (i = 0;  flag_array[i].name && flags; i++) {
685                 mask = flag_array[i].mask;
686                 if ((flags & mask) != mask)
687                         continue;
688
689                 add = flag_array[i].name;
690                 flags &= ~mask;
691                 if (!first && delim)
692                         add_string(&flag_str, delim);
693                 else
694                         first = 0;
695                 add_string(&flag_str, add);
696         }
697
698         /* Check whether there are any leftover flags. */
699         if (flags) {
700                 int ret;
701                 char number[11];
702
703                 if (!first && delim)
704                         add_string(&flag_str, delim);
705
706                 ret = snprintf(number, 11, "0x%x", flags) > 0;
707                 if (ret > 0 && ret <= 11)
708                         add_string(&flag_str, number);
709         }
710
711         return flag_str.buffer;
712 }
713
714 void
715 add_to_flist(int ft, int id, int parent)
716 {
717         fent_t  *fep;
718         flist_t *ftp;
719
720         ftp = &flist[ft];
721         if (ftp->nfiles == ftp->nslots) {
722                 ftp->nslots += FLIST_SLOT_INCR;
723                 ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t));
724         }
725         fep = &ftp->fents[ftp->nfiles++];
726         fep->id = id;
727         fep->parent = parent;
728 }
729
730 void
731 append_pathname(pathname_t *name, char *str)
732 {
733         int     len;
734
735         len = strlen(str);
736 #ifdef DEBUG
737         /* attempting to append to a dir a zero length path */
738         if (len && *str == '/' && name->len == 0) {
739                 fprintf(stderr, "fsstress: append_pathname failure\n");
740                 assert(chdir(homedir) == 0);
741                 abort();
742                 /* NOTREACHED */
743         }
744 #endif
745         name->path = realloc(name->path, name->len + 1 + len);
746         strcpy(&name->path[name->len], str);
747         name->len += len;
748 }
749
750 int
751 attr_list_path(pathname_t *name,
752                char *buffer,
753                const int buffersize,
754                int flags,
755                attrlist_cursor_t *cursor)
756 {
757         char            buf[NAME_MAX + 1];
758         pathname_t      newname;
759         int             rval;
760
761         if (flags != ATTR_DONTFOLLOW) {
762                 errno = EINVAL;
763                 return -1;
764         }
765
766         rval = attr_list(name->path, buffer, buffersize, flags, cursor);
767         if (rval >= 0 || errno != ENAMETOOLONG)
768                 return rval;
769         separate_pathname(name, buf, &newname);
770         if (chdir(buf) == 0) {
771                 rval = attr_list_path(&newname, buffer, buffersize, flags, cursor);
772                 assert(chdir("..") == 0);
773         }
774         free_pathname(&newname);
775         return rval;
776 }
777
778 int
779 attr_remove_path(pathname_t *name, const char *attrname, int flags)
780 {
781         char            buf[NAME_MAX + 1];
782         pathname_t      newname;
783         int             rval;
784
785         rval = attr_remove(name->path, attrname, flags);
786         if (rval >= 0 || errno != ENAMETOOLONG)
787                 return rval;
788         separate_pathname(name, buf, &newname);
789         if (chdir(buf) == 0) {
790                 rval = attr_remove_path(&newname, attrname, flags);
791                 assert(chdir("..") == 0);
792         }
793         free_pathname(&newname);
794         return rval;
795 }
796
797 int
798 attr_set_path(pathname_t *name, const char *attrname, const char *attrvalue,
799               const int valuelength, int flags)
800 {
801         char            buf[NAME_MAX + 1];
802         pathname_t      newname;
803         int             rval;
804
805         rval = attr_set(name->path, attrname, attrvalue, valuelength, flags);
806         if (rval >= 0 || errno != ENAMETOOLONG)
807                 return rval;
808         separate_pathname(name, buf, &newname);
809         if (chdir(buf) == 0) {
810                 rval = attr_set_path(&newname, attrname, attrvalue, valuelength,
811                         flags);
812                 assert(chdir("..") == 0);
813         }
814         free_pathname(&newname);
815         return rval;
816 }
817
818 void
819 check_cwd(void)
820 {
821 #ifdef DEBUG
822         struct stat64   statbuf;
823
824         if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino)
825                 return;
826         assert(chdir(homedir) == 0);
827         fprintf(stderr, "fsstress: check_cwd failure\n");
828         abort();
829         /* NOTREACHED */
830 #endif
831 }
832
833 /*
834  * go thru flist and release all entries
835  *
836  * NOTE: this function shouldn't be called until the end of a process
837  */
838 void
839 cleanup_flist(void)
840 {
841         flist_t *flp;
842         int     i;
843
844         for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
845                 flp->nslots = 0;
846                 flp->nfiles = 0;
847                 free(flp->fents);
848                 flp->fents = NULL;
849         }
850 }
851
852 int
853 creat_path(pathname_t *name, mode_t mode)
854 {
855         char            buf[NAME_MAX + 1];
856         pathname_t      newname;
857         int             rval;
858
859         rval = creat(name->path, mode);
860         if (rval >= 0 || errno != ENAMETOOLONG)
861                 return rval;
862         separate_pathname(name, buf, &newname);
863         if (chdir(buf) == 0) {
864                 rval = creat_path(&newname, mode);
865                 assert(chdir("..") == 0);
866         }
867         free_pathname(&newname);
868         return rval;
869 }
870
871 void
872 dcache_enter(int dirid, int slot)
873 {
874         dcache[dirid % NDCACHE] = slot;
875 }
876
877 void
878 dcache_init(void)
879 {
880         int     i;
881
882         for (i = 0; i < NDCACHE; i++)
883                 dcache[i] = -1;
884 }
885
886 fent_t *
887 dcache_lookup(int dirid)
888 {
889         fent_t  *fep;
890         int     i;
891
892         i = dcache[dirid % NDCACHE];
893         if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
894                 return fep;
895         return NULL;
896 }
897
898 void
899 dcache_purge(int dirid)
900 {
901         int     *dcp;
902
903         dcp = &dcache[dirid % NDCACHE];
904         if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
905                 *dcp = -1;
906 }
907
908 /*
909  * Delete the item from the list by
910  * moving last entry over the deleted one;
911  * unless deleted entry is the last one.
912  * Input: which file list array and which slot in array
913  */
914 void
915 del_from_flist(int ft, int slot)
916 {
917         flist_t *ftp;
918
919         ftp = &flist[ft];
920         if (ft == FT_DIR)
921                 dcache_purge(ftp->fents[slot].id);
922         if (slot != ftp->nfiles - 1) {
923                 if (ft == FT_DIR)
924                         dcache_purge(ftp->fents[ftp->nfiles - 1].id);
925                 ftp->fents[slot] = ftp->fents[--ftp->nfiles];
926         } else
927                 ftp->nfiles--;
928 }
929
930 fent_t *
931 dirid_to_fent(int dirid)
932 {
933         fent_t  *efep;
934         fent_t  *fep;
935         flist_t *flp;
936
937         if ((fep = dcache_lookup(dirid)))
938                 return fep;
939         flp = &flist[FT_DIR];
940         for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
941                 if (fep->id == dirid) {
942                         dcache_enter(dirid, fep - flp->fents);
943                         return fep;
944                 }
945         }
946         return NULL;
947 }
948
949 void
950 doproc(void)
951 {
952         struct stat64   statbuf;
953         char            buf[10];
954         char            cmd[64];
955         int             opno;
956         int             rval;
957         opdesc_t        *p;
958         int             dividend;
959
960         dividend = (operations + execute_freq) / (execute_freq + 1);
961         sprintf(buf, "p%x", procid);
962         (void)mkdir(buf, 0777);
963         if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) {
964                 perror(buf);
965                 _exit(1);
966         }
967         top_ino = statbuf.st_ino;
968         homedir = getcwd(NULL, 0);
969         if (!homedir) {
970                 perror("getcwd failed");
971                 _exit(1);
972         }
973         seed += procid;
974         srandom(seed);
975         if (namerand)
976                 namerand = random();
977         for (opno = 0; opno < operations; opno++) {
978                 if (execute_cmd && opno && opno % dividend == 0) {
979                         if (verbose)
980                                 printf("%d: execute command %s\n", opno,
981                                         execute_cmd);
982                         rval = system(execute_cmd);
983                         if (rval)
984                                 fprintf(stderr, "execute command failed with "
985                                         "%d\n", rval);
986                 }
987                 p = &ops[freq_table[random() % freq_table_size]];
988                 p->func(opno, random());
989                 /*
990                  * test for forced shutdown by stat'ing the test
991                  * directory.  If this stat returns EIO, assume
992                  * the forced shutdown happened.
993                  */
994                 if (errtag != 0 && opno % 100 == 0)  {
995                         rval = stat64(".", &statbuf);
996                         if (rval == EIO)  {
997                                 fprintf(stderr, "Detected EIO\n");
998                                 goto errout;
999                         }
1000                 }
1001         }
1002 errout:
1003         assert(chdir("..") == 0);
1004         free(homedir);
1005         if (cleanup) {
1006                 int ret;
1007
1008                 sprintf(cmd, "rm -rf %s", buf);
1009                 ret = system(cmd);
1010                 if (ret != 0)
1011                         perror("cleaning up");
1012                 cleanup_flist();
1013         }
1014 }
1015
1016 /*
1017  * build up a pathname going thru the file entry and all
1018  * its parent entries
1019  * Return 0 on error, 1 on success;
1020  */
1021 int
1022 fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
1023 {
1024         char    buf[NAME_MAX + 1];
1025         int     i;
1026         fent_t  *pfep;
1027         int     e;
1028
1029         if (fep == NULL)
1030                 return 0;
1031
1032         /* build up parent directory name */
1033         if (fep->parent != -1) {
1034                 pfep = dirid_to_fent(fep->parent);
1035 #ifdef DEBUG
1036                 if (pfep == NULL) {
1037                         fprintf(stderr, "%d: fent-id = %d: can't find parent id: %d\n",
1038                                 procid, fep->id, fep->parent);
1039                 } 
1040 #endif
1041                 if (pfep == NULL)
1042                         return 0;
1043                 e = fent_to_name(name, &flist[FT_DIR], pfep);
1044                 if (!e)
1045                         return 0;
1046                 append_pathname(name, "/");
1047         }
1048
1049         i = sprintf(buf, "%c%x", flp->tag, fep->id);
1050         namerandpad(fep->id, buf, i);
1051         append_pathname(name, buf);
1052         return 1;
1053 }
1054
1055 void
1056 fix_parent(int oldid, int newid)
1057 {
1058         fent_t  *fep;
1059         flist_t *flp;
1060         int     i;
1061         int     j;
1062
1063         for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1064                 for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
1065                         if (fep->parent == oldid)
1066                                 fep->parent = newid;
1067                 }
1068         }
1069 }
1070
1071 void
1072 free_pathname(pathname_t *name)
1073 {
1074         if (name->path) {
1075                 free(name->path);
1076                 name->path = NULL;
1077                 name->len = 0;
1078         }
1079 }
1080
1081 /*
1082  * Generate a filename of type ft.
1083  * If we have a fep which should be a directory then use it
1084  * as the parent path for this new filename i.e. prepend with it.
1085  */
1086 int
1087 generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
1088 {
1089         char    buf[NAME_MAX + 1];
1090         flist_t *flp;
1091         int     id;
1092         int     j;
1093         int     len;
1094         int     e;
1095
1096         /* create name */
1097         flp = &flist[ft];
1098         len = sprintf(buf, "%c%x", flp->tag, id = nameseq++);
1099         namerandpad(id, buf, len);
1100
1101         /* prepend fep parent dir-name to it */
1102         if (fep) {
1103                 e = fent_to_name(name, &flist[FT_DIR], fep);
1104                 if (!e)
1105                         return 0;
1106                 append_pathname(name, "/");
1107         }
1108         append_pathname(name, buf);
1109
1110         *idp = id;
1111         *v = verbose;
1112         for (j = 0; !*v && j < ilistlen; j++) {
1113                 if (ilist[j] == id) {
1114                         *v = 1;
1115                         break;
1116                 }
1117         }
1118         return 1;
1119 }
1120
1121 /*
1122  * Get file 
1123  * Input: "which" to choose the file-types eg. non-directory
1124  * Input: "r" to choose which file
1125  * Output: file-list, file-entry, name for the chosen file.
1126  * Output: verbose if chosen file is on the ilist.
1127  */
1128 int
1129 get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
1130           int *v)
1131 {
1132         int     totalsum = 0; /* total number of matching files */
1133         int     partialsum = 0; /* partial sum of matching files */
1134         fent_t  *fep;
1135         flist_t *flp;
1136         int     i;
1137         int     j;
1138         int     x;
1139         int     e = 1; /* success */
1140
1141         /*
1142          * go thru flist and add up number of files for each
1143          * category that matches with <which>.
1144          */
1145         for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1146                 if (which & (1 << i))
1147                         totalsum += flp->nfiles;
1148         }
1149         if (totalsum == 0) {
1150                 if (flpp)
1151                         *flpp = NULL;
1152                 if (fepp)
1153                         *fepp = NULL;
1154                 *v = verbose;
1155                 return 0;
1156         }
1157
1158         /*
1159          * Now we have possible matches between 0..totalsum-1.
1160          * And we use r to help us choose which one we want,
1161          * which when bounded by totalsum becomes x.
1162          */ 
1163         x = (int)(r % totalsum);
1164         for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1165                 if (which & (1 << i)) {
1166                         if (x < partialsum + flp->nfiles) {
1167
1168                                 /* found the matching file entry */
1169                                 fep = &flp->fents[x - partialsum];
1170
1171                                 /* fill-in what we were asked for */
1172                                 if (name) {
1173                                         e = fent_to_name(name, flp, fep);
1174 #ifdef DEBUG
1175                                         if (!e) {
1176                                                 fprintf(stderr, "%d: failed to get path for entry:"
1177                                                                 " id=%d,parent=%d\n",   
1178                                                         procid, fep->id, fep->parent);
1179                                         }
1180 #endif
1181                                 }
1182                                 if (flpp)
1183                                         *flpp = flp;
1184                                 if (fepp)
1185                                         *fepp = fep;
1186
1187                                 /* turn on verbose if its an ilisted file */
1188                                 *v = verbose;
1189                                 for (j = 0; !*v && j < ilistlen; j++) {
1190                                         if (ilist[j] == fep->id) {
1191                                                 *v = 1;
1192                                                 break;
1193                                         }
1194                                 }
1195                                 return e;
1196                         }
1197                         partialsum += flp->nfiles;
1198                 }
1199         }
1200 #ifdef DEBUG
1201         fprintf(stderr, "fsstress: get_fname failure\n");
1202         abort();
1203 #endif
1204         return 0;
1205 }
1206
1207 void
1208 init_pathname(pathname_t *name)
1209 {
1210         name->len = 0;
1211         name->path = NULL;
1212 }
1213
1214 int
1215 lchown_path(pathname_t *name, uid_t owner, gid_t group)
1216 {
1217         char            buf[NAME_MAX + 1];
1218         pathname_t      newname;
1219         int             rval;
1220
1221         rval = lchown(name->path, owner, group);
1222         if (rval >= 0 || errno != ENAMETOOLONG)
1223                 return rval;
1224         separate_pathname(name, buf, &newname);
1225         if (chdir(buf) == 0) {
1226                 rval = lchown_path(&newname, owner, group);
1227                 assert(chdir("..") == 0);
1228         }
1229         free_pathname(&newname);
1230         return rval;
1231 }
1232
1233 int
1234 link_path(pathname_t *name1, pathname_t *name2)
1235 {
1236         char            buf1[NAME_MAX + 1];
1237         char            buf2[NAME_MAX + 1];
1238         int             down1;
1239         pathname_t      newname1;
1240         pathname_t      newname2;
1241         int             rval;
1242
1243         rval = link(name1->path, name2->path);
1244         if (rval >= 0 || errno != ENAMETOOLONG)
1245                 return rval;
1246         separate_pathname(name1, buf1, &newname1);
1247         separate_pathname(name2, buf2, &newname2);
1248         if (strcmp(buf1, buf2) == 0) {
1249                 if (chdir(buf1) == 0) {
1250                         rval = link_path(&newname1, &newname2);
1251                         assert(chdir("..") == 0);
1252                 }
1253         } else {
1254                 if (strcmp(buf1, "..") == 0)
1255                         down1 = 0;
1256                 else if (strcmp(buf2, "..") == 0)
1257                         down1 = 1;
1258                 else if (strlen(buf1) == 0)
1259                         down1 = 0;
1260                 else if (strlen(buf2) == 0)
1261                         down1 = 1;
1262                 else
1263                         down1 = MAX(newname1.len, 3 + name2->len) <=
1264                                 MAX(3 + name1->len, newname2.len);
1265                 if (down1) {
1266                         free_pathname(&newname2);
1267                         append_pathname(&newname2, "../");
1268                         append_pathname(&newname2, name2->path);
1269                         if (chdir(buf1) == 0) {
1270                                 rval = link_path(&newname1, &newname2);
1271                                 assert(chdir("..") == 0);
1272                         }
1273                 } else {
1274                         free_pathname(&newname1);
1275                         append_pathname(&newname1, "../");
1276                         append_pathname(&newname1, name1->path);
1277                         if (chdir(buf2) == 0) {
1278                                 rval = link_path(&newname1, &newname2);
1279                                 assert(chdir("..") == 0);
1280                         }
1281                 }
1282         }
1283         free_pathname(&newname1);
1284         free_pathname(&newname2);
1285         return rval;
1286 }
1287
1288 int
1289 lstat64_path(pathname_t *name, struct stat64 *sbuf)
1290 {
1291         char            buf[NAME_MAX + 1];
1292         pathname_t      newname;
1293         int             rval;
1294
1295         rval = lstat64(name->path, sbuf);
1296         if (rval >= 0 || errno != ENAMETOOLONG)
1297                 return rval;
1298         separate_pathname(name, buf, &newname);
1299         if (chdir(buf) == 0) {
1300                 rval = lstat64_path(&newname, sbuf);
1301                 assert(chdir("..") == 0);
1302         }
1303         free_pathname(&newname);
1304         return rval;
1305 }
1306
1307 void
1308 make_freq_table(void)
1309 {
1310         int             f;
1311         int             i;
1312         opdesc_t        *p;
1313
1314         for (p = ops, f = 0; p < ops_end; p++)
1315                 f += p->freq;
1316         freq_table = malloc(f * sizeof(*freq_table));
1317         freq_table_size = f;
1318         for (p = ops, i = 0; p < ops_end; p++) {
1319                 for (f = 0; f < p->freq; f++, i++)
1320                         freq_table[i] = p->op;
1321         }
1322 }
1323
1324 int
1325 mkdir_path(pathname_t *name, mode_t mode)
1326 {
1327         char            buf[NAME_MAX + 1];
1328         pathname_t      newname;
1329         int             rval;
1330
1331         rval = mkdir(name->path, mode);
1332         if (rval >= 0 || errno != ENAMETOOLONG)
1333                 return rval;
1334         separate_pathname(name, buf, &newname);
1335         if (chdir(buf) == 0) {
1336                 rval = mkdir_path(&newname, mode);
1337                 assert(chdir("..") == 0);
1338         }
1339         free_pathname(&newname);
1340         return rval;
1341 }
1342
1343 int
1344 mknod_path(pathname_t *name, mode_t mode, dev_t dev)
1345 {
1346         char            buf[NAME_MAX + 1];
1347         pathname_t      newname;
1348         int             rval;
1349
1350         rval = mknod(name->path, mode, dev);
1351         if (rval >= 0 || errno != ENAMETOOLONG)
1352                 return rval;
1353         separate_pathname(name, buf, &newname);
1354         if (chdir(buf) == 0) {
1355                 rval = mknod_path(&newname, mode, dev);
1356                 assert(chdir("..") == 0);
1357         }
1358         free_pathname(&newname);
1359         return rval;
1360 }
1361
1362 void
1363 namerandpad(int id, char *buf, int i)
1364 {
1365         int             bucket;
1366         static int      buckets[] =
1367                                 { 2, 4, 8, 16, 32, 64, 128, NAME_MAX };
1368         int             padlen;
1369         int             padmod;
1370
1371         if (namerand == 0)
1372                 return;
1373         bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0]));
1374         padmod = buckets[bucket] + 1 - i;
1375         if (padmod <= 0)
1376                 return;
1377         padlen = (id ^ namerand) % padmod;
1378         if (padlen) {
1379                 memset(&buf[i], 'X', padlen);
1380                 buf[i + padlen] = '\0';
1381         }
1382 }
1383
1384 int
1385 open_path(pathname_t *name, int oflag)
1386 {
1387         char            buf[NAME_MAX + 1];
1388         pathname_t      newname;
1389         int             rval;
1390
1391         rval = open(name->path, oflag);
1392         if (rval >= 0 || errno != ENAMETOOLONG)
1393                 return rval;
1394         separate_pathname(name, buf, &newname);
1395         if (chdir(buf) == 0) {
1396                 rval = open_path(&newname, oflag);
1397                 assert(chdir("..") == 0);
1398         }
1399         free_pathname(&newname);
1400         return rval;
1401 }
1402
1403 DIR *
1404 opendir_path(pathname_t *name)
1405 {
1406         char            buf[NAME_MAX + 1];
1407         pathname_t      newname;
1408         DIR             *rval;
1409
1410         rval = opendir(name->path);
1411         if (rval || errno != ENAMETOOLONG)
1412                 return rval;
1413         separate_pathname(name, buf, &newname);
1414         if (chdir(buf) == 0) {
1415                 rval = opendir_path(&newname);
1416                 assert(chdir("..") == 0);
1417         }
1418         free_pathname(&newname);
1419         return rval;
1420 }
1421
1422 void
1423 process_freq(char *arg)
1424 {
1425         opdesc_t        *p;
1426         char            *s;
1427
1428         s = strchr(arg, '=');
1429         if (s == NULL) {
1430                 fprintf(stderr, "bad argument '%s'\n", arg);
1431                 exit(1);
1432         }
1433         *s++ = '\0';
1434         for (p = ops; p < ops_end; p++) {
1435                 if (strcmp(arg, p->name) == 0) {
1436                         p->freq = atoi(s);
1437                         return;
1438                 }
1439         }
1440         fprintf(stderr, "can't find op type %s for -f\n", arg);
1441         exit(1);
1442 }
1443
1444 int
1445 readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz)
1446 {
1447         char            buf[NAME_MAX + 1];
1448         pathname_t      newname;
1449         int             rval;
1450
1451         rval = readlink(name->path, lbuf, lbufsiz);
1452         if (rval >= 0 || errno != ENAMETOOLONG)
1453                 return rval;
1454         separate_pathname(name, buf, &newname);
1455         if (chdir(buf) == 0) {
1456                 rval = readlink_path(&newname, lbuf, lbufsiz);
1457                 assert(chdir("..") == 0);
1458         }
1459         free_pathname(&newname);
1460         return rval;
1461 }
1462
1463 int
1464 rename_path(pathname_t *name1, pathname_t *name2)
1465 {
1466         char            buf1[NAME_MAX + 1];
1467         char            buf2[NAME_MAX + 1];
1468         int             down1;
1469         pathname_t      newname1;
1470         pathname_t      newname2;
1471         int             rval;
1472
1473         rval = rename(name1->path, name2->path);
1474         if (rval >= 0 || errno != ENAMETOOLONG)
1475                 return rval;
1476         separate_pathname(name1, buf1, &newname1);
1477         separate_pathname(name2, buf2, &newname2);
1478         if (strcmp(buf1, buf2) == 0) {
1479                 if (chdir(buf1) == 0) {
1480                         rval = rename_path(&newname1, &newname2);
1481                         assert(chdir("..") == 0);
1482                 }
1483         } else {
1484                 if (strcmp(buf1, "..") == 0)
1485                         down1 = 0;
1486                 else if (strcmp(buf2, "..") == 0)
1487                         down1 = 1;
1488                 else if (strlen(buf1) == 0)
1489                         down1 = 0;
1490                 else if (strlen(buf2) == 0)
1491                         down1 = 1;
1492                 else
1493                         down1 = MAX(newname1.len, 3 + name2->len) <=
1494                                 MAX(3 + name1->len, newname2.len);
1495                 if (down1) {
1496                         free_pathname(&newname2);
1497                         append_pathname(&newname2, "../");
1498                         append_pathname(&newname2, name2->path);
1499                         if (chdir(buf1) == 0) {
1500                                 rval = rename_path(&newname1, &newname2);
1501                                 assert(chdir("..") == 0);
1502                         }
1503                 } else {
1504                         free_pathname(&newname1);
1505                         append_pathname(&newname1, "../");
1506                         append_pathname(&newname1, name1->path);
1507                         if (chdir(buf2) == 0) {
1508                                 rval = rename_path(&newname1, &newname2);
1509                                 assert(chdir("..") == 0);
1510                         }
1511                 }
1512         }
1513         free_pathname(&newname1);
1514         free_pathname(&newname2);
1515         return rval;
1516 }
1517
1518 int
1519 rmdir_path(pathname_t *name)
1520 {
1521         char            buf[NAME_MAX + 1];
1522         pathname_t      newname;
1523         int             rval;
1524
1525         rval = rmdir(name->path);
1526         if (rval >= 0 || errno != ENAMETOOLONG)
1527                 return rval;
1528         separate_pathname(name, buf, &newname);
1529         if (chdir(buf) == 0) {
1530                 rval = rmdir_path(&newname);
1531                 assert(chdir("..") == 0);
1532         }
1533         free_pathname(&newname);
1534         return rval;
1535 }
1536
1537 void
1538 separate_pathname(pathname_t *name, char *buf, pathname_t *newname)
1539 {
1540         char    *slash;
1541
1542         init_pathname(newname);
1543         slash = strchr(name->path, '/');
1544         if (slash == NULL) {
1545                 buf[0] = '\0';
1546                 return;
1547         }
1548         *slash = '\0';
1549         strcpy(buf, name->path);
1550         *slash = '/';
1551         append_pathname(newname, slash + 1);
1552 }
1553
1554 #define WIDTH 80
1555
1556 void
1557 show_ops(int flag, char *lead_str)
1558 {
1559         opdesc_t        *p;
1560
1561         if (flag<0) {
1562                 /* print in list form */
1563                 int             x = WIDTH;
1564                 
1565                 for (p = ops; p < ops_end; p++) {
1566                         if (lead_str != NULL && x+strlen(p->name)>=WIDTH-5)
1567                                 x=printf("%s%s", (p==ops)?"":"\n", lead_str);
1568                         x+=printf("%s ", p->name);
1569                 }
1570                 printf("\n");
1571         } else if (flag == 0) {
1572                 /* Table view style */
1573                 int             f;
1574                 for (f = 0, p = ops; p < ops_end; p++)
1575                         f += p->freq;
1576
1577                 if (f == 0)
1578                         flag = 1;
1579
1580                 for (p = ops; p < ops_end; p++) {
1581                         if (flag != 0 || p->freq > 0) {
1582                                 if (lead_str != NULL)
1583                                         printf("%s", lead_str);
1584                                 printf("%20s %d/%d %s\n",
1585                                 p->name, p->freq, f,
1586                                 (p->iswrite == 0) ? " " : "write op");
1587                         }
1588                 }
1589         } else {
1590                 /* Command line style */
1591                 if (lead_str != NULL)
1592                         printf("%s", lead_str);
1593                 printf ("-z -s %ld -m %d -n %d -p %d \\\n", seed, idmodulo,
1594                         operations, nproc);
1595                 for (p = ops; p < ops_end; p++)
1596                         if (p->freq > 0)
1597                                 printf("-f %s=%d \\\n",p->name, p->freq);
1598         }
1599 }
1600
1601 int
1602 stat64_path(pathname_t *name, struct stat64 *sbuf)
1603 {
1604         char            buf[NAME_MAX + 1];
1605         pathname_t      newname;
1606         int             rval;
1607
1608         rval = stat64(name->path, sbuf);
1609         if (rval >= 0 || errno != ENAMETOOLONG)
1610                 return rval;
1611         separate_pathname(name, buf, &newname);
1612         if (chdir(buf) == 0) {
1613                 rval = stat64_path(&newname, sbuf);
1614                 assert(chdir("..") == 0);
1615         }
1616         free_pathname(&newname);
1617         return rval;
1618 }
1619
1620 int
1621 symlink_path(const char *name1, pathname_t *name)
1622 {
1623         char            buf[NAME_MAX + 1];
1624         pathname_t      newname;
1625         int             rval;
1626         
1627         if (!strcmp(name1, name->path)) {
1628             printf("yikes! %s %s\n", name1, name->path);
1629             return 0;
1630         }
1631
1632         rval = symlink(name1, name->path);
1633         if (rval >= 0 || errno != ENAMETOOLONG)
1634                 return rval;
1635         separate_pathname(name, buf, &newname);
1636         if (chdir(buf) == 0) {
1637                 rval = symlink_path(name1, &newname);
1638                 assert(chdir("..") == 0);
1639         }
1640         free_pathname(&newname);
1641         return rval;
1642 }
1643
1644 int
1645 truncate64_path(pathname_t *name, off64_t length)
1646 {
1647         char            buf[NAME_MAX + 1];
1648         pathname_t      newname;
1649         int             rval;
1650
1651         rval = truncate64(name->path, length);
1652         if (rval >= 0 || errno != ENAMETOOLONG)
1653                 return rval;
1654         separate_pathname(name, buf, &newname);
1655         if (chdir(buf) == 0) {
1656                 rval = truncate64_path(&newname, length);
1657                 assert(chdir("..") == 0);
1658         }
1659         free_pathname(&newname);
1660         return rval;
1661 }
1662
1663 int
1664 unlink_path(pathname_t *name)
1665 {
1666         char            buf[NAME_MAX + 1];
1667         pathname_t      newname;
1668         int             rval;
1669
1670         rval = unlink(name->path);
1671         if (rval >= 0 || errno != ENAMETOOLONG)
1672                 return rval;
1673         separate_pathname(name, buf, &newname);
1674         if (chdir(buf) == 0) {
1675                 rval = unlink_path(&newname);
1676                 assert(chdir("..") == 0);
1677         }
1678         free_pathname(&newname);
1679         return rval;
1680 }
1681
1682 void
1683 usage(void)
1684 {
1685         printf("Usage: %s -H   or\n", myprog);
1686         printf("       %s [-c][-d dir][-e errtg][-f op_name=freq][-l loops][-n nops]\n",
1687                 myprog);
1688         printf("          [-p nproc][-r len][-s seed][-v][-w][-x cmd][-z][-S][-X ncmd]\n");
1689         printf("where\n");
1690         printf("   -c               clean up the test directory after each run\n");
1691         printf("   -d dir           specifies the base directory for operations\n");
1692         printf("   -e errtg         specifies error injection stuff\n");
1693         printf("   -f op_name=freq  changes the frequency of option name to freq\n");
1694         printf("                    the valid operation names are:\n");
1695         show_ops(-1, "                        ");
1696         printf("   -i filenum       get verbose output for this nth file object\n");
1697         printf("   -l loops         specifies the no. of times the testrun should loop.\n");
1698         printf("                     *use 0 for infinite (default 1)\n");
1699         printf("   -m modulo        uid/gid modulo for chown/chgrp (default 32)\n");
1700         printf("   -n nops          specifies the no. of operations per process (default 1)\n");
1701         printf("   -o logfile       specifies logfile name\n");
1702         printf("   -p nproc         specifies the no. of processes (default 1)\n");
1703         printf("   -r               specifies random name padding\n");
1704         printf("   -s seed          specifies the seed for the random generator (default random)\n");
1705         printf("   -v               specifies verbose mode\n");
1706         printf("   -w               zeros frequencies of non-write operations\n");
1707         printf("   -x cmd           execute command in the middle of operations\n");
1708         printf("   -z               zeros frequencies of all operations\n");
1709         printf("   -S [c,t]         prints the list of operations (omitting zero frequency) in command line or table style\n");
1710         printf("   -V               specifies verifiable logging mode (omitting inode numbers)\n");
1711         printf("   -X ncmd          number of calls to the -x command (default 1)\n");
1712         printf("   -H               prints usage and exits\n");
1713 }
1714
1715 void
1716 write_freq(void)
1717 {
1718         opdesc_t        *p;
1719
1720         for (p = ops; p < ops_end; p++) {
1721                 if (!p->iswrite)
1722                         p->freq = 0;
1723         }
1724 }
1725
1726 void
1727 zero_freq(void)
1728 {
1729         opdesc_t        *p;
1730
1731         for (p = ops; p < ops_end; p++)
1732                 p->freq = 0;
1733 }
1734
1735 void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
1736 {
1737         if (verbose)
1738                 snprintf(str, sz, "[%ld %ld %d %d %lld %lld]",
1739                          verifiable_log ? -1: (long)s->st_ino,
1740                          (long)s->st_nlink,  s->st_uid, s->st_gid,
1741                          (long long) s->st_blocks, (long long) s->st_size);
1742 }
1743
1744 void
1745 afsync_f(int opno, long r)
1746 {
1747 #ifdef AIO
1748         int             e;
1749         pathname_t      f;
1750         int             fd;
1751         int             v;
1752         struct iocb     iocb;
1753         struct iocb     *iocbs[] = { &iocb };
1754         struct io_event event;
1755
1756         init_pathname(&f);
1757         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1758                 if (v)
1759                         printf("%d/%d: afsync - no filename\n", procid, opno);
1760                 free_pathname(&f);
1761                 return;
1762         }
1763         fd = open_path(&f, O_WRONLY | O_DIRECT);
1764         e = fd < 0 ? errno : 0;
1765         check_cwd();
1766         if (fd < 0) {
1767                 if (v)
1768                         printf("%d/%d: afsync - open %s failed %d\n",
1769                                procid, opno, f.path, e);
1770                 free_pathname(&f);
1771                 return;
1772         }
1773
1774         io_prep_fsync(&iocb, fd);
1775         if ((e = io_submit(io_ctx, 1, iocbs)) != 1) {
1776                 if (v)
1777                         printf("%d/%d: afsync - io_submit %s %d\n",
1778                                procid, opno, f.path, e);
1779                 free_pathname(&f);
1780                 close(fd);
1781                 return;
1782         }
1783         if ((e = io_getevents(io_ctx, 1, 1, &event, NULL)) != 1) {
1784                 if (v)
1785                         printf("%d/%d: afsync - io_getevents failed %d\n",
1786                                procid, opno, e);
1787                 free_pathname(&f);
1788                 close(fd);
1789                 return;
1790         }
1791
1792         e = event.res2;
1793         if (v)
1794                 printf("%d/%d: afsync %s %d\n", procid, opno, f.path, e);
1795         free_pathname(&f);
1796         close(fd);
1797 #endif
1798 }
1799
1800 void
1801 allocsp_f(int opno, long r)
1802 {
1803         int             e;
1804         pathname_t      f;
1805         int             fd;
1806         struct xfs_flock64      fl;
1807         int64_t         lr;
1808         off64_t         off;
1809         struct stat64   stb;
1810         int             v;
1811         char            st[1024];
1812
1813         init_pathname(&f);
1814         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1815                 if (v)
1816                         printf("%d/%d: allocsp - no filename\n", procid, opno);
1817                 free_pathname(&f);
1818                 return;
1819         }
1820         fd = open_path(&f, O_RDWR);
1821         e = fd < 0 ? errno : 0;
1822         check_cwd();
1823         if (fd < 0) {
1824                 if (v)
1825                         printf("%d/%d: allocsp - open %s failed %d\n",
1826                                 procid, opno, f.path, e);
1827                 free_pathname(&f);
1828                 return;
1829         }
1830         if (fstat64(fd, &stb) < 0) {
1831                 if (v)
1832                         printf("%d/%d: allocsp - fstat64 %s failed %d\n",
1833                                 procid, opno, f.path, errno);
1834                 free_pathname(&f);
1835                 close(fd);
1836                 return;
1837         }
1838         inode_info(st, sizeof(st), &stb, v);
1839         lr = ((int64_t)random() << 32) + random();
1840         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1841         off %= maxfsize;
1842         fl.l_whence = SEEK_SET;
1843         fl.l_start = off;
1844         fl.l_len = 0;
1845         e = xfsctl(f.path, fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
1846         if (v) {
1847                 printf("%d/%d: xfsctl(XFS_IOC_ALLOCSP64) %s%s %lld 0 %d\n",
1848                        procid, opno, f.path, st, (long long)off, e);
1849         }
1850         free_pathname(&f);
1851         close(fd);
1852 }
1853
1854 #ifdef AIO
1855 void
1856 do_aio_rw(int opno, long r, int flags)
1857 {
1858         int64_t         align;
1859         char            *buf;
1860         struct dioattr  diob;
1861         int             e;
1862         pathname_t      f;
1863         int             fd;
1864         size_t          len;
1865         int64_t         lr;
1866         off64_t         off;
1867         struct stat64   stb;
1868         int             v;
1869         char            st[1024];
1870         char            *dio_env;
1871         struct iocb     iocb;
1872         struct io_event event;
1873         struct iocb     *iocbs[] = { &iocb };
1874         int             iswrite = (flags & (O_WRONLY | O_RDWR)) ? 1 : 0;
1875
1876         init_pathname(&f);
1877         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
1878                 if (v)
1879                         printf("%d/%d: do_aio_rw - no filename\n", procid, opno);
1880                 free_pathname(&f);
1881                 return;
1882         }
1883         fd = open_path(&f, flags|O_DIRECT);
1884         e = fd < 0 ? errno : 0;
1885         check_cwd();
1886         if (fd < 0) {
1887                 if (v)
1888                         printf("%d/%d: do_aio_rw - open %s failed %d\n",
1889                                procid, opno, f.path, e);
1890                 free_pathname(&f);
1891                 return;
1892         }
1893         if (fstat64(fd, &stb) < 0) {
1894                 if (v)
1895                         printf("%d/%d: do_aio_rw - fstat64 %s failed %d\n",
1896                                procid, opno, f.path, errno);
1897                 free_pathname(&f);
1898                 close(fd);
1899                 return;
1900         }
1901         inode_info(st, sizeof(st), &stb, v);
1902         if (!iswrite && stb.st_size == 0) {
1903                 if (v)
1904                         printf("%d/%d: do_aio_rw - %s%s zero size\n", procid, opno,
1905                                f.path, st);
1906                 free_pathname(&f);
1907                 close(fd);
1908                 return;
1909         }
1910         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
1911                 if (v)
1912                         printf(
1913                         "%d/%d: do_aio_rw - xfsctl(XFS_IOC_DIOINFO) %s%s return %d,"
1914                         " fallback to stat()\n",
1915                                 procid, opno, f.path, st, errno);
1916                 diob.d_mem = diob.d_miniosz = stb.st_blksize;
1917                 diob.d_maxiosz = INT_MAX & ~(diob.d_miniosz - 1);
1918         }
1919         dio_env = getenv("XFS_DIO_MIN");
1920         if (dio_env)
1921                 diob.d_mem = diob.d_miniosz = atoi(dio_env);
1922         align = (int64_t)diob.d_miniosz;
1923         lr = ((int64_t)random() << 32) + random();
1924         len = (random() % FILELEN_MAX) + 1;
1925         len -= (len % align);
1926         if (len <= 0)
1927                 len = align;
1928         else if (len > diob.d_maxiosz)
1929                 len = diob.d_maxiosz;
1930         buf = memalign(diob.d_mem, len);
1931
1932         if (iswrite) {
1933                 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
1934                 off -= (off % align);
1935                 off %= maxfsize;
1936                 memset(buf, nameseq & 0xff, len);
1937                 io_prep_pwrite(&iocb, fd, buf, len, off);
1938         } else {
1939                 off = (off64_t)(lr % stb.st_size);
1940                 off -= (off % align);
1941                 io_prep_pread(&iocb, fd, buf, len, off);
1942         }
1943         if ((e = io_submit(io_ctx, 1, iocbs)) != 1) {
1944                 if (v)
1945                         printf("%d/%d: %s - io_submit failed %d\n",
1946                                procid, opno, iswrite ? "awrite" : "aread", e);
1947                 free_pathname(&f);
1948                 close(fd);
1949                 return;
1950         }
1951         if ((e = io_getevents(io_ctx, 1, 1, &event, NULL)) != 1) {
1952                 if (v)
1953                         printf("%d/%d: %s - io_getevents failed %d\n",
1954                                procid, opno, iswrite ? "awrite" : "aread", e);
1955                 free_pathname(&f);
1956                 close(fd);
1957                 return;
1958         }
1959
1960         e = event.res != len ? event.res2 : 0;
1961         free(buf);
1962         if (v)
1963                 printf("%d/%d: %s %s%s [%lld,%d] %d\n",
1964                        procid, opno, iswrite ? "awrite" : "aread",
1965                        f.path, st, (long long)off, (int)len, e);
1966         free_pathname(&f);
1967         close(fd);
1968 }
1969 #endif
1970
1971 void
1972 aread_f(int opno, long r)
1973 {
1974 #ifdef AIO
1975         do_aio_rw(opno, r, O_RDONLY);
1976 #endif
1977 }
1978
1979 void
1980 attr_remove_f(int opno, long r)
1981 {
1982         attrlist_ent_t          *aep;
1983         attrlist_t              *alist;
1984         char                    *aname;
1985         char                    buf[4096];
1986         attrlist_cursor_t       cursor;
1987         int                     e;
1988         int                     ent;
1989         pathname_t              f;
1990         int                     total;
1991         int                     v;
1992         int                     which;
1993
1994         init_pathname(&f);
1995         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
1996                 append_pathname(&f, ".");
1997         total = 0;
1998         bzero(&cursor, sizeof(cursor));
1999         do {
2000                 bzero(buf, sizeof(buf));
2001                 e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, &cursor);
2002                 check_cwd();
2003                 if (e)
2004                         break;
2005                 alist = (attrlist_t *)buf;
2006                 total += alist->al_count;
2007         } while (alist->al_more);
2008         if (total == 0) {
2009                 if (v)
2010                         printf("%d/%d: attr_remove - no attrs for %s\n",
2011                                 procid, opno, f.path);
2012                 free_pathname(&f);
2013                 return;
2014         }
2015         which = (int)(random() % total);
2016         bzero(&cursor, sizeof(cursor));
2017         ent = 0;
2018         aname = NULL;
2019         do {
2020                 bzero(buf, sizeof(buf));
2021                 e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, &cursor);
2022                 check_cwd();
2023                 if (e)
2024                         break;
2025                 alist = (attrlist_t *)buf;
2026                 if (which < ent + alist->al_count) {
2027                         aep = (attrlist_ent_t *)
2028                                 &buf[alist->al_offset[which - ent]];
2029                         aname = aep->a_name;
2030                         break;
2031                 }
2032                 ent += alist->al_count;
2033         } while (alist->al_more);
2034         if (aname == NULL) {
2035                 if (v)
2036                         printf(
2037                         "%d/%d: attr_remove - name %d not found at %s\n",
2038                                 procid, opno, which, f.path);
2039                 free_pathname(&f);
2040                 return;
2041         }
2042         e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0;
2043         check_cwd();
2044         if (v)
2045                 printf("%d/%d: attr_remove %s %s %d\n",
2046                         procid, opno, f.path, aname, e);
2047         free_pathname(&f);
2048 }
2049
2050 void
2051 attr_set_f(int opno, long r)
2052 {
2053         char            aname[10];
2054         char            *aval;
2055         int             e;
2056         pathname_t      f;
2057         int             len;
2058         static int      lengths[] = { 10, 100, 1000, 10000 };
2059         int             li;
2060         int             v;
2061
2062         init_pathname(&f);
2063         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2064                 append_pathname(&f, ".");
2065         sprintf(aname, "a%x", nameseq++);
2066         li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0])));
2067         len = (int)(random() % lengths[li]);
2068         if (len == 0)
2069                 len = 1;
2070         aval = malloc(len);
2071         memset(aval, nameseq & 0xff, len);
2072         e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ?
2073                 errno : 0;
2074         check_cwd();
2075         free(aval);
2076         if (v)
2077                 printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path,
2078                         aname, e);
2079         free_pathname(&f);
2080 }
2081
2082 void
2083 awrite_f(int opno, long r)
2084 {
2085 #ifdef AIO
2086         do_aio_rw(opno, r, O_WRONLY);
2087 #endif
2088 }
2089
2090 void
2091 bulkstat_f(int opno, long r)
2092 {
2093         int             count;
2094         int             fd;
2095         __u64           last;
2096         int             nent;
2097         xfs_bstat_t     *t;
2098         int64_t         total;
2099         xfs_fsop_bulkreq_t bsr;
2100
2101         last = 0;
2102         nent = (r % 999) + 2;
2103         t = malloc(nent * sizeof(*t));
2104         fd = open(".", O_RDONLY);
2105         total = 0;
2106
2107         bsr.lastip=&last;
2108         bsr.icount=nent;
2109         bsr.ubuffer=t;
2110         bsr.ocount=&count;
2111             
2112         while (xfsctl(".", fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
2113                 total += count;
2114         free(t);
2115         if (verbose)
2116                 printf("%d/%d: bulkstat nent %d total %lld\n",
2117                         procid, opno, nent, (long long)total);
2118         close(fd);
2119 }
2120
2121 void
2122 bulkstat1_f(int opno, long r)
2123 {
2124         int             e;
2125         pathname_t      f;
2126         int             fd;
2127         int             good;
2128         __u64           ino;
2129         struct stat64   s;
2130         xfs_bstat_t     t;
2131         int             v;
2132         xfs_fsop_bulkreq_t bsr;
2133         
2134
2135         good = random() & 1;
2136         if (good) {
2137                /* use an inode we know exists */
2138                 init_pathname(&f);
2139                 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2140                         append_pathname(&f, ".");
2141                 ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino;
2142                 check_cwd();
2143                 free_pathname(&f);
2144         } else {
2145                 /* 
2146                  * pick a random inode 
2147                  *
2148                  * note this can generate kernel warning messages
2149                  * since bulkstat_one will read the disk block that
2150                  * would contain a given inode even if that disk
2151                  * block doesn't contain inodes.
2152                  *
2153                  * this is detected later, but not until after the
2154                  * warning is displayed.
2155                  *
2156                  * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0"
2157                  *
2158                  */
2159                 ino = (ino64_t)r;
2160                 v = verbose;
2161         }
2162         fd = open(".", O_RDONLY);
2163         
2164         bsr.lastip=&ino;
2165         bsr.icount=1;
2166         bsr.ubuffer=&t;
2167         bsr.ocount=NULL;
2168         e = xfsctl(".", fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
2169         if (v)
2170                 printf("%d/%d: bulkstat1 %s ino %lld %d\n", 
2171                        procid, opno, good?"real":"random",
2172                        verifiable_log ? -1LL : (long long)ino, e);
2173         close(fd);
2174 }
2175
2176 void
2177 chown_f(int opno, long r)
2178 {
2179         int             e;
2180         pathname_t      f;
2181         int             nbits;
2182         uid_t           u;
2183         gid_t           g;
2184         int             v;
2185
2186         init_pathname(&f);
2187         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2188                 append_pathname(&f, ".");
2189         u = (uid_t)random();
2190         g = (gid_t)random();
2191         nbits = (int)(random() % idmodulo);
2192         u &= (1 << nbits) - 1;
2193         g &= (1 << nbits) - 1;
2194         e = lchown_path(&f, u, g) < 0 ? errno : 0;
2195         check_cwd();
2196         if (v)
2197                 printf("%d/%d: chown %s %d/%d %d\n", procid, opno, f.path, (int)u, (int)g, e);
2198         free_pathname(&f);
2199 }
2200
2201 /* reflink some arbitrary range of f1 to f2. */
2202 void
2203 clonerange_f(
2204         int                     opno,
2205         long                    r)
2206 {
2207 #ifdef FICLONERANGE
2208         struct file_clone_range fcr;
2209         struct pathname         fpath1;
2210         struct pathname         fpath2;
2211         struct stat64           stat1;
2212         struct stat64           stat2;
2213         char                    inoinfo1[1024];
2214         char                    inoinfo2[1024];
2215         off64_t                 lr;
2216         off64_t                 off1;
2217         off64_t                 off2;
2218         off64_t                 max_off2;
2219         size_t                  len;
2220         int                     v1;
2221         int                     v2;
2222         int                     fd1;
2223         int                     fd2;
2224         int                     ret;
2225         int                     e;
2226
2227         /* Load paths */
2228         init_pathname(&fpath1);
2229         if (!get_fname(FT_REGm, r, &fpath1, NULL, NULL, &v1)) {
2230                 if (v1)
2231                         printf("%d/%d: clonerange read - no filename\n",
2232                                 procid, opno);
2233                 goto out_fpath1;
2234         }
2235
2236         init_pathname(&fpath2);
2237         if (!get_fname(FT_REGm, random(), &fpath2, NULL, NULL, &v2)) {
2238                 if (v2)
2239                         printf("%d/%d: clonerange write - no filename\n",
2240                                 procid, opno);
2241                 goto out_fpath2;
2242         }
2243
2244         /* Open files */
2245         fd1 = open_path(&fpath1, O_RDONLY);
2246         e = fd1 < 0 ? errno : 0;
2247         check_cwd();
2248         if (fd1 < 0) {
2249                 if (v1)
2250                         printf("%d/%d: clonerange read - open %s failed %d\n",
2251                                 procid, opno, fpath1.path, e);
2252                 goto out_fpath2;
2253         }
2254
2255         fd2 = open_path(&fpath2, O_WRONLY);
2256         e = fd2 < 0 ? errno : 0;
2257         check_cwd();
2258         if (fd2 < 0) {
2259                 if (v2)
2260                         printf("%d/%d: clonerange write - open %s failed %d\n",
2261                                 procid, opno, fpath2.path, e);
2262                 goto out_fd1;
2263         }
2264
2265         /* Get file stats */
2266         if (fstat64(fd1, &stat1) < 0) {
2267                 if (v1)
2268                         printf("%d/%d: clonerange read - fstat64 %s failed %d\n",
2269                                 procid, opno, fpath1.path, errno);
2270                 goto out_fd2;
2271         }
2272         inode_info(inoinfo1, sizeof(inoinfo1), &stat1, v1);
2273
2274         if (fstat64(fd2, &stat2) < 0) {
2275                 if (v2)
2276                         printf("%d/%d: clonerange write - fstat64 %s failed %d\n",
2277                                 procid, opno, fpath2.path, errno);
2278                 goto out_fd2;
2279         }
2280         inode_info(inoinfo2, sizeof(inoinfo2), &stat2, v2);
2281
2282         /* Calculate offsets */
2283         len = (random() % FILELEN_MAX) + 1;
2284         len &= ~(stat1.st_blksize - 1);
2285         if (len == 0)
2286                 len = stat1.st_blksize;
2287         if (len > stat1.st_size)
2288                 len = stat1.st_size;
2289
2290         lr = ((int64_t)random() << 32) + random();
2291         if (stat1.st_size == len)
2292                 off1 = 0;
2293         else
2294                 off1 = (off64_t)(lr % MIN(stat1.st_size - len, MAXFSIZE));
2295         off1 %= maxfsize;
2296         off1 &= ~(stat1.st_blksize - 1);
2297
2298         /*
2299          * If srcfile == destfile, randomly generate destination ranges
2300          * until we find one that doesn't overlap the source range.
2301          */
2302         max_off2 = MIN(stat2.st_size + (1024ULL * stat2.st_blksize), MAXFSIZE);
2303         do {
2304                 lr = ((int64_t)random() << 32) + random();
2305                 off2 = (off64_t)(lr % max_off2);
2306                 off2 %= maxfsize;
2307                 off2 &= ~(stat2.st_blksize - 1);
2308         } while (stat1.st_ino == stat2.st_ino && llabs(off2 - off1) < len);
2309
2310         /* Clone data blocks */
2311         fcr.src_fd = fd1;
2312         fcr.src_offset = off1;
2313         fcr.src_length = len;
2314         fcr.dest_offset = off2;
2315
2316         ret = ioctl(fd2, FICLONERANGE, &fcr);
2317         e = ret < 0 ? errno : 0;
2318         if (v1 || v2) {
2319                 printf("%d/%d: clonerange %s%s [%lld,%lld] -> %s%s [%lld,%lld]",
2320                         procid, opno,
2321                         fpath1.path, inoinfo1, (long long)off1, (long long)len,
2322                         fpath2.path, inoinfo2, (long long)off2, (long long)len);
2323
2324                 if (ret < 0)
2325                         printf(" error %d", e);
2326                 printf("\n");
2327         }
2328
2329 out_fd2:
2330         close(fd2);
2331 out_fd1:
2332         close(fd1);
2333 out_fpath2:
2334         free_pathname(&fpath2);
2335 out_fpath1:
2336         free_pathname(&fpath1);
2337 #endif
2338 }
2339
2340 /* copy some arbitrary range of f1 to f2. */
2341 void
2342 copyrange_f(
2343         int                     opno,
2344         long                    r)
2345 {
2346 #ifdef HAVE_COPY_FILE_RANGE
2347         struct pathname         fpath1;
2348         struct pathname         fpath2;
2349         struct stat64           stat1;
2350         struct stat64           stat2;
2351         char                    inoinfo1[1024];
2352         char                    inoinfo2[1024];
2353         loff_t                  lr;
2354         loff_t                  off1;
2355         loff_t                  off2;
2356         loff_t                  max_off2;
2357         size_t                  len;
2358         int                     tries = 0;
2359         int                     v1;
2360         int                     v2;
2361         int                     fd1;
2362         int                     fd2;
2363         size_t                  ret;
2364         int                     e;
2365
2366         /* Load paths */
2367         init_pathname(&fpath1);
2368         if (!get_fname(FT_REGm, r, &fpath1, NULL, NULL, &v1)) {
2369                 if (v1)
2370                         printf("%d/%d: copyrange read - no filename\n",
2371                                 procid, opno);
2372                 goto out_fpath1;
2373         }
2374
2375         init_pathname(&fpath2);
2376         if (!get_fname(FT_REGm, random(), &fpath2, NULL, NULL, &v2)) {
2377                 if (v2)
2378                         printf("%d/%d: copyrange write - no filename\n",
2379                                 procid, opno);
2380                 goto out_fpath2;
2381         }
2382
2383         /* Open files */
2384         fd1 = open_path(&fpath1, O_RDONLY);
2385         e = fd1 < 0 ? errno : 0;
2386         check_cwd();
2387         if (fd1 < 0) {
2388                 if (v1)
2389                         printf("%d/%d: copyrange read - open %s failed %d\n",
2390                                 procid, opno, fpath1.path, e);
2391                 goto out_fpath2;
2392         }
2393
2394         fd2 = open_path(&fpath2, O_WRONLY);
2395         e = fd2 < 0 ? errno : 0;
2396         check_cwd();
2397         if (fd2 < 0) {
2398                 if (v2)
2399                         printf("%d/%d: copyrange write - open %s failed %d\n",
2400                                 procid, opno, fpath2.path, e);
2401                 goto out_fd1;
2402         }
2403
2404         /* Get file stats */
2405         if (fstat64(fd1, &stat1) < 0) {
2406                 if (v1)
2407                         printf("%d/%d: copyrange read - fstat64 %s failed %d\n",
2408                                 procid, opno, fpath1.path, errno);
2409                 goto out_fd2;
2410         }
2411         inode_info(inoinfo1, sizeof(inoinfo1), &stat1, v1);
2412
2413         if (fstat64(fd2, &stat2) < 0) {
2414                 if (v2)
2415                         printf("%d/%d: copyrange write - fstat64 %s failed %d\n",
2416                                 procid, opno, fpath2.path, errno);
2417                 goto out_fd2;
2418         }
2419         inode_info(inoinfo2, sizeof(inoinfo2), &stat2, v2);
2420
2421         /* Calculate offsets */
2422         len = (random() % FILELEN_MAX) + 1;
2423         if (len == 0)
2424                 len = stat1.st_blksize;
2425         if (len > stat1.st_size)
2426                 len = stat1.st_size;
2427
2428         lr = ((int64_t)random() << 32) + random();
2429         if (stat1.st_size == len)
2430                 off1 = 0;
2431         else
2432                 off1 = (off64_t)(lr % MIN(stat1.st_size - len, MAXFSIZE));
2433         off1 %= maxfsize;
2434
2435         /*
2436          * If srcfile == destfile, randomly generate destination ranges
2437          * until we find one that doesn't overlap the source range.
2438          */
2439         max_off2 = MIN(stat2.st_size + (1024ULL * stat2.st_blksize), MAXFSIZE);
2440         do {
2441                 lr = ((int64_t)random() << 32) + random();
2442                 off2 = (off64_t)(lr % max_off2);
2443                 off2 %= maxfsize;
2444         } while (stat1.st_ino == stat2.st_ino && llabs(off2 - off1) < len);
2445
2446         while (len > 0) {
2447                 ret = syscall(__NR_copy_file_range, fd1, &off1, fd2, &off2,
2448                               len, 0);
2449                 if (ret < 0) {
2450                         if (errno != EAGAIN || tries++ >= 300)
2451                                 break;
2452                 } else if (ret > len)
2453                         break;
2454                 else if (ret > 0)
2455                         len -= ret;
2456         }
2457         e = ret < 0 ? errno : 0;
2458         if (v1 || v2) {
2459                 printf("%d/%d: copyrange %s%s [%lld,%lld] -> %s%s [%lld,%lld]",
2460                         procid, opno,
2461                         fpath1.path, inoinfo1, (long long)off1, (long long)len,
2462                         fpath2.path, inoinfo2, (long long)off2, (long long)len);
2463
2464                 if (ret < 0)
2465                         printf(" error %d", e);
2466                 else if (len && ret > len)
2467                         printf(" asked for %lld, copied %lld??\n",
2468                                 (long long)len, (long long)ret);
2469                 printf("\n");
2470         }
2471
2472 out_fd2:
2473         close(fd2);
2474 out_fd1:
2475         close(fd1);
2476 out_fpath2:
2477         free_pathname(&fpath2);
2478 out_fpath1:
2479         free_pathname(&fpath1);
2480 #endif
2481 }
2482
2483 /* dedupe some arbitrary range of f1 to f2...fn. */
2484 void
2485 deduperange_f(
2486         int                     opno,
2487         long                    r)
2488 {
2489 #ifdef FIDEDUPERANGE
2490 #define INFO_SZ                 1024
2491         struct file_dedupe_range *fdr;
2492         struct pathname         *fpath;
2493         struct stat64           *stat;
2494         char                    *info;
2495         off64_t                 *off;
2496         int                     *v;
2497         int                     *fd;
2498         int                     nr;
2499         off64_t                 lr;
2500         size_t                  len;
2501         int                     ret;
2502         int                     i;
2503         int                     e;
2504
2505         if (flist[FT_REG].nfiles < 2)
2506                 return;
2507
2508         /* Pick somewhere between 2 and 128 files. */
2509         do {
2510                 nr = random() % (flist[FT_REG].nfiles + 1);
2511         } while (nr < 2 || nr > 128);
2512
2513         /* Alloc memory */
2514         fdr = malloc(nr * sizeof(struct file_dedupe_range_info) +
2515                      sizeof(struct file_dedupe_range));
2516         if (!fdr) {
2517                 printf("%d/%d: line %d error %d\n",
2518                         procid, opno, __LINE__, errno);
2519                 return;
2520         }
2521         memset(fdr, 0, (nr * sizeof(struct file_dedupe_range_info) +
2522                         sizeof(struct file_dedupe_range)));
2523
2524         fpath = calloc(nr, sizeof(struct pathname));
2525         if (!fpath) {
2526                 printf("%d/%d: line %d error %d\n",
2527                         procid, opno, __LINE__, errno);
2528                 goto out_fdr;
2529         }
2530
2531         stat = calloc(nr, sizeof(struct stat64));
2532         if (!stat) {
2533                 printf("%d/%d: line %d error %d\n",
2534                         procid, opno, __LINE__, errno);
2535                 goto out_paths;
2536         }
2537
2538         info = calloc(nr, INFO_SZ);
2539         if (!info) {
2540                 printf("%d/%d: line %d error %d\n",
2541                         procid, opno, __LINE__, errno);
2542                 goto out_stats;
2543         }
2544
2545         off = calloc(nr, sizeof(off64_t));
2546         if (!off) {
2547                 printf("%d/%d: line %d error %d\n",
2548                         procid, opno, __LINE__, errno);
2549                 goto out_info;
2550         }
2551
2552         v = calloc(nr, sizeof(int));
2553         if (!v) {
2554                 printf("%d/%d: line %d error %d\n",
2555                         procid, opno, __LINE__, errno);
2556                 goto out_offsets;
2557         }
2558         fd = calloc(nr, sizeof(int));
2559         if (!fd) {
2560                 printf("%d/%d: line %d error %d\n",
2561                         procid, opno, __LINE__, errno);
2562                 goto out_v;
2563         }
2564         memset(fd, 0xFF, nr * sizeof(int));
2565
2566         /* Get paths for all files */
2567         for (i = 0; i < nr; i++)
2568                 init_pathname(&fpath[i]);
2569
2570         if (!get_fname(FT_REGm, r, &fpath[0], NULL, NULL, &v[0])) {
2571                 if (v[0])
2572                         printf("%d/%d: deduperange read - no filename\n",
2573                                 procid, opno);
2574                 goto out_pathnames;
2575         }
2576
2577         for (i = 1; i < nr; i++) {
2578                 if (!get_fname(FT_REGm, random(), &fpath[i], NULL, NULL, &v[i])) {
2579                         if (v[i])
2580                                 printf("%d/%d: deduperange write - no filename\n",
2581                                         procid, opno);
2582                         goto out_pathnames;
2583                 }
2584         }
2585
2586         /* Open files */
2587         fd[0] = open_path(&fpath[0], O_RDONLY);
2588         e = fd[0] < 0 ? errno : 0;
2589         check_cwd();
2590         if (fd[0] < 0) {
2591                 if (v[0])
2592                         printf("%d/%d: deduperange read - open %s failed %d\n",
2593                                 procid, opno, fpath[0].path, e);
2594                 goto out_pathnames;
2595         }
2596
2597         for (i = 1; i < nr; i++) {
2598                 fd[i] = open_path(&fpath[i], O_WRONLY);
2599                 e = fd[i] < 0 ? errno : 0;
2600                 check_cwd();
2601                 if (fd[i] < 0) {
2602                         if (v[i])
2603                                 printf("%d/%d: deduperange write - open %s failed %d\n",
2604                                         procid, opno, fpath[i].path, e);
2605                         goto out_fds;
2606                 }
2607         }
2608
2609         /* Get file stats */
2610         if (fstat64(fd[0], &stat[0]) < 0) {
2611                 if (v[0])
2612                         printf("%d/%d: deduperange read - fstat64 %s failed %d\n",
2613                                 procid, opno, fpath[0].path, errno);
2614                 goto out_fds;
2615         }
2616
2617         inode_info(&info[0], INFO_SZ, &stat[0], v[0]);
2618
2619         for (i = 1; i < nr; i++) {
2620                 if (fstat64(fd[i], &stat[i]) < 0) {
2621                         if (v[i])
2622                                 printf("%d/%d: deduperange write - fstat64 %s failed %d\n",
2623                                         procid, opno, fpath[i].path, errno);
2624                         goto out_fds;
2625                 }
2626                 inode_info(&info[i * INFO_SZ], INFO_SZ, &stat[i], v[i]);
2627         }
2628
2629         /* Never try to dedupe more than half of the src file. */
2630         len = (random() % FILELEN_MAX) + 1;
2631         len &= ~(stat[0].st_blksize - 1);
2632         if (len == 0)
2633                 len = stat[0].st_blksize / 2;
2634         if (len > stat[0].st_size / 2)
2635                 len = stat[0].st_size / 2;
2636
2637         /* Calculate offsets */
2638         lr = ((int64_t)random() << 32) + random();
2639         if (stat[0].st_size == len)
2640                 off[0] = 0;
2641         else
2642                 off[0] = (off64_t)(lr % MIN(stat[0].st_size - len, MAXFSIZE));
2643         off[0] %= maxfsize;
2644         off[0] &= ~(stat[0].st_blksize - 1);
2645
2646         /*
2647          * If srcfile == destfile[i], randomly generate destination ranges
2648          * until we find one that doesn't overlap the source range.
2649          */
2650         for (i = 1; i < nr; i++) {
2651                 int     tries = 0;
2652
2653                 do {
2654                         lr = ((int64_t)random() << 32) + random();
2655                         if (stat[i].st_size <= len)
2656                                 off[i] = 0;
2657                         else
2658                                 off[i] = (off64_t)(lr % MIN(stat[i].st_size - len, MAXFSIZE));
2659                         off[i] %= maxfsize;
2660                         off[i] &= ~(stat[i].st_blksize - 1);
2661                 } while (stat[0].st_ino == stat[i].st_ino &&
2662                          llabs(off[i] - off[0]) < len &&
2663                          tries++ < 10);
2664         }
2665
2666         /* Clone data blocks */
2667         fdr->src_offset = off[0];
2668         fdr->src_length = len;
2669         fdr->dest_count = nr - 1;
2670         for (i = 1; i < nr; i++) {
2671                 fdr->info[i - 1].dest_fd = fd[i];
2672                 fdr->info[i - 1].dest_offset = off[i];
2673         }
2674
2675         ret = ioctl(fd[0], FIDEDUPERANGE, fdr);
2676         e = ret < 0 ? errno : 0;
2677         if (v[0]) {
2678                 printf("%d/%d: deduperange from %s%s [%lld,%lld]",
2679                         procid, opno,
2680                         fpath[0].path, &info[0], (long long)off[0],
2681                         (long long)len);
2682                 if (ret < 0)
2683                         printf(" error %d", e);
2684                 printf("\n");
2685         }
2686         if (ret < 0)
2687                 goto out_fds;
2688
2689         for (i = 1; i < nr; i++) {
2690                 e = fdr->info[i - 1].status < 0 ? fdr->info[i - 1].status : 0;
2691                 if (v[i]) {
2692                         printf("%d/%d: ...to %s%s [%lld,%lld]",
2693                                 procid, opno,
2694                                 fpath[i].path, &info[i * INFO_SZ],
2695                                 (long long)off[i], (long long)len);
2696                         if (fdr->info[i - 1].status < 0)
2697                                 printf(" error %d", e);
2698                         if (fdr->info[i - 1].status == FILE_DEDUPE_RANGE_SAME)
2699                                 printf(" %llu bytes deduplicated",
2700                                         fdr->info[i - 1].bytes_deduped);
2701                         if (fdr->info[i - 1].status == FILE_DEDUPE_RANGE_DIFFERS)
2702                                 printf(" differed");
2703                         printf("\n");
2704                 }
2705         }
2706
2707 out_fds:
2708         for (i = 0; i < nr; i++)
2709                 if (fd[i] >= 0)
2710                         close(fd[i]);
2711 out_pathnames:
2712         for (i = 0; i < nr; i++)
2713                 free_pathname(&fpath[i]);
2714
2715         free(fd);
2716 out_v:
2717         free(v);
2718 out_offsets:
2719         free(off);
2720 out_info:
2721         free(info);
2722 out_stats:
2723         free(stat);
2724 out_paths:
2725         free(fpath);
2726 out_fdr:
2727         free(fdr);
2728 #endif
2729 }
2730
2731 void
2732 setxattr_f(int opno, long r)
2733 {
2734 #ifdef XFS_XFLAG_EXTSIZE
2735         struct fsxattr  fsx;
2736         int             fd;
2737         int             e;
2738         pathname_t      f;
2739         int             nbits;
2740         uint            p;
2741         int             v;
2742
2743         init_pathname(&f);
2744         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2745                 append_pathname(&f, ".");
2746         fd = open_path(&f, O_RDWR);
2747         e = fd < 0 ? errno : 0;
2748         check_cwd();
2749
2750         /* project ID */
2751         p = (uint)random();
2752         e = MIN(idmodulo, XFS_PROJIDMODULO_MAX);
2753         nbits = (int)(random() % e);
2754         p &= (1 << nbits) - 1;
2755
2756         if ((e = xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &fsx)) == 0) {
2757                 fsx.fsx_projid = p;
2758                 e = xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &fsx);
2759         }
2760         if (v)
2761                 printf("%d/%d: setxattr %s %u %d\n", procid, opno, f.path, p, e);
2762         free_pathname(&f);
2763         close(fd);
2764 #endif
2765 }
2766
2767 void
2768 creat_f(int opno, long r)
2769 {
2770         struct fsxattr  a;
2771         int             e;
2772         int             e1;
2773         int             extsize;
2774         pathname_t      f;
2775         int             fd;
2776         fent_t          *fep;
2777         int             id;
2778         int             parid;
2779         int             type;
2780         int             v;
2781         int             v1;
2782
2783         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
2784                 parid = -1;
2785         else
2786                 parid = fep->id;
2787         init_pathname(&f);
2788         e1 = (random() % 100);
2789         type = rtpct ? ((e1 > rtpct) ? FT_REG : FT_RTF) : FT_REG;
2790 #ifdef NOTYET
2791         if (type == FT_RTF)     /* rt always gets an extsize */
2792                 extsize = (random() % 10) + 1;
2793         else if (e1 < 10)       /* one-in-ten get an extsize */
2794                 extsize = random() % 1024;
2795         else
2796 #endif
2797                 extsize = 0;
2798         e = generate_fname(fep, type, &f, &id, &v);
2799         v |= v1;
2800         if (!e) {
2801                 if (v) {
2802                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
2803                         printf("%d/%d: creat - no filename from %s\n",
2804                                 procid, opno, f.path);
2805                 }
2806                 free_pathname(&f);
2807                 return;
2808         }
2809         fd = creat_path(&f, 0666);
2810         e = fd < 0 ? errno : 0;
2811         e1 = 0;
2812         check_cwd();
2813         if (fd >= 0) {
2814                 if (extsize &&
2815                     xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
2816                         if (type == FT_RTF) {
2817                                 a.fsx_xflags |= XFS_XFLAG_REALTIME;
2818                                 a.fsx_extsize = extsize *
2819                                                 geom.rtextsize * geom.blocksize;
2820 #ifdef NOTYET
2821                         } else if (extsize) {
2822                                 a.fsx_xflags |= XFS_XFLAG_EXTSIZE;
2823                                 a.fsx_extsize = extsize * geom.blocksize;
2824 #endif
2825                         }
2826                         if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
2827                                 e1 = errno;
2828                 }
2829                 add_to_flist(type, id, parid);
2830                 close(fd);
2831         }
2832         if (v) {
2833                 printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
2834                         extsize ? a.fsx_extsize : 0, e, e1);
2835                 printf("%d/%d: creat add id=%d,parent=%d\n", procid, opno, id, parid);
2836         }
2837         free_pathname(&f);
2838 }
2839
2840 void
2841 dread_f(int opno, long r)
2842 {
2843         int64_t         align;
2844         char            *buf;
2845         struct dioattr  diob;
2846         int             e;
2847         pathname_t      f;
2848         int             fd;
2849         size_t          len;
2850         int64_t         lr;
2851         off64_t         off;
2852         struct stat64   stb;
2853         int             v;
2854         char            st[1024];
2855         char            *dio_env;
2856
2857         init_pathname(&f);
2858         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2859                 if (v)
2860                         printf("%d/%d: dread - no filename\n", procid, opno);
2861                 free_pathname(&f);
2862                 return;
2863         }
2864         fd = open_path(&f, O_RDONLY|O_DIRECT);
2865         e = fd < 0 ? errno : 0;
2866         check_cwd();
2867         if (fd < 0) {
2868                 if (v)
2869                         printf("%d/%d: dread - open %s failed %d\n",
2870                                 procid, opno, f.path, e);
2871                 free_pathname(&f);
2872                 return;
2873         }
2874         if (fstat64(fd, &stb) < 0) {
2875                 if (v)
2876                         printf("%d/%d: dread - fstat64 %s failed %d\n",
2877                                procid, opno, f.path, errno);
2878                 free_pathname(&f);
2879                 close(fd);
2880                 return;
2881         }
2882         inode_info(st, sizeof(st), &stb, v);
2883         if (stb.st_size == 0) {
2884                 if (v)
2885                         printf("%d/%d: dread - %s%s zero size\n", procid, opno,
2886                                f.path, st);
2887                 free_pathname(&f);
2888                 close(fd);
2889                 return;
2890         }
2891         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
2892                 if (v)
2893                         printf(
2894                         "%d/%d: dread - xfsctl(XFS_IOC_DIOINFO) %s%s return %d,"
2895                         " fallback to stat()\n",
2896                                 procid, opno, f.path, st, errno);
2897                 diob.d_mem = diob.d_miniosz = stb.st_blksize;
2898                 diob.d_maxiosz = INT_MAX & ~(diob.d_miniosz - 1);
2899         }
2900
2901         dio_env = getenv("XFS_DIO_MIN");
2902         if (dio_env)
2903                 diob.d_mem = diob.d_miniosz = atoi(dio_env);
2904
2905         align = (int64_t)diob.d_miniosz;
2906         lr = ((int64_t)random() << 32) + random();
2907         off = (off64_t)(lr % stb.st_size);
2908         off -= (off % align);
2909         lseek64(fd, off, SEEK_SET);
2910         len = (random() % FILELEN_MAX) + 1;
2911         len -= (len % align);
2912         if (len <= 0)
2913                 len = align;
2914         else if (len > diob.d_maxiosz) 
2915                 len = diob.d_maxiosz;
2916         buf = memalign(diob.d_mem, len);
2917         e = read(fd, buf, len) < 0 ? errno : 0;
2918         free(buf);
2919         if (v)
2920                 printf("%d/%d: dread %s%s [%lld,%d] %d\n",
2921                        procid, opno, f.path, st, (long long)off, (int)len, e);
2922         free_pathname(&f);
2923         close(fd);
2924 }
2925
2926 void
2927 dwrite_f(int opno, long r)
2928 {
2929         int64_t         align;
2930         char            *buf;
2931         struct dioattr  diob;
2932         int             e;
2933         pathname_t      f;
2934         int             fd;
2935         size_t          len;
2936         int64_t         lr;
2937         off64_t         off;
2938         struct stat64   stb;
2939         int             v;
2940         char            st[1024];
2941         char            *dio_env;
2942
2943         init_pathname(&f);
2944         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2945                 if (v)
2946                         printf("%d/%d: dwrite - no filename\n", procid, opno);
2947                 free_pathname(&f);
2948                 return;
2949         }
2950         fd = open_path(&f, O_WRONLY|O_DIRECT);
2951         e = fd < 0 ? errno : 0;
2952         check_cwd();
2953         if (fd < 0) {
2954                 if (v)
2955                         printf("%d/%d: dwrite - open %s failed %d\n",
2956                                 procid, opno, f.path, e);
2957                 free_pathname(&f);
2958                 return;
2959         }
2960         if (fstat64(fd, &stb) < 0) {
2961                 if (v)
2962                         printf("%d/%d: dwrite - fstat64 %s failed %d\n",
2963                                 procid, opno, f.path, errno);
2964                 free_pathname(&f);
2965                 close(fd);
2966                 return;
2967         }
2968         inode_info(st, sizeof(st), &stb, v);
2969         if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
2970                 if (v)
2971                         printf("%d/%d: dwrite - xfsctl(XFS_IOC_DIOINFO)"
2972                                 " %s%s return %d, fallback to stat()\n",
2973                                procid, opno, f.path, st, errno);
2974                 diob.d_mem = diob.d_miniosz = stb.st_blksize;
2975                 diob.d_maxiosz = INT_MAX & ~(diob.d_miniosz - 1);
2976         }
2977
2978         dio_env = getenv("XFS_DIO_MIN");
2979         if (dio_env)
2980                 diob.d_mem = diob.d_miniosz = atoi(dio_env);
2981
2982         align = (int64_t)diob.d_miniosz;
2983         lr = ((int64_t)random() << 32) + random();
2984         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2985         off -= (off % align);
2986         lseek64(fd, off, SEEK_SET);
2987         len = (random() % FILELEN_MAX) + 1;
2988         len -= (len % align);
2989         if (len <= 0)
2990                 len = align;
2991         else if (len > diob.d_maxiosz) 
2992                 len = diob.d_maxiosz;
2993         buf = memalign(diob.d_mem, len);
2994         off %= maxfsize;
2995         lseek64(fd, off, SEEK_SET);
2996         memset(buf, nameseq & 0xff, len);
2997         e = write(fd, buf, len) < 0 ? errno : 0;
2998         free(buf);
2999         if (v)
3000                 printf("%d/%d: dwrite %s%s [%lld,%d] %d\n",
3001                        procid, opno, f.path, st, (long long)off, (int)len, e);
3002         free_pathname(&f);
3003         close(fd);
3004 }
3005
3006
3007 #ifdef HAVE_LINUX_FALLOC_H
3008 struct print_flags falloc_flags [] = {
3009         { FALLOC_FL_KEEP_SIZE, "KEEP_SIZE"},
3010         { FALLOC_FL_PUNCH_HOLE, "PUNCH_HOLE"},
3011         { FALLOC_FL_NO_HIDE_STALE, "NO_HIDE_STALE"},
3012         { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"},
3013         { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"},
3014         { FALLOC_FL_INSERT_RANGE, "INSERT_RANGE"},
3015         { -1, NULL}
3016 };
3017
3018 #define translate_falloc_flags(mode)    \
3019         ({translate_flags(mode, "|", falloc_flags);})
3020 #endif
3021
3022 void
3023 do_fallocate(int opno, long r, int mode)
3024 {
3025 #ifdef HAVE_LINUX_FALLOC_H
3026         int             e;
3027         pathname_t      f;
3028         int             fd;
3029         int64_t         lr;
3030         off64_t         off;
3031         off64_t         len;
3032         struct stat64   stb;
3033         int             v;
3034         char            st[1024];
3035
3036         init_pathname(&f);
3037         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3038                 if (v)
3039                         printf("%d/%d: do_fallocate - no filename\n", procid, opno);
3040                 free_pathname(&f);
3041                 return;
3042         }
3043         fd = open_path(&f, O_RDWR);
3044         if (fd < 0) {
3045                 if (v)
3046                         printf("%d/%d: do_fallocate - open %s failed %d\n",
3047                                 procid, opno, f.path, errno);
3048                 free_pathname(&f);
3049                 return;
3050         }
3051         check_cwd();
3052         if (fstat64(fd, &stb) < 0) {
3053                 if (v)
3054                         printf("%d/%d: do_fallocate - fstat64 %s failed %d\n",
3055                                 procid, opno, f.path, errno);
3056                 free_pathname(&f);
3057                 close(fd);
3058                 return;
3059         }
3060         inode_info(st, sizeof(st), &stb, v);
3061         lr = ((int64_t)random() << 32) + random();
3062         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3063         off %= maxfsize;
3064         len = (off64_t)(random() % (1024 * 1024));
3065         /*
3066          * Collapse/insert range requires off and len to be block aligned,
3067          * make it more likely to be the case.
3068          */
3069         if ((mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)) &&
3070                 (opno % 2)) {
3071                 off = ((off + stb.st_blksize - 1) & ~(stb.st_blksize - 1));
3072                 len = ((len + stb.st_blksize - 1) & ~(stb.st_blksize - 1));
3073         }
3074         mode |= FALLOC_FL_KEEP_SIZE & random();
3075         e = fallocate(fd, mode, (loff_t)off, (loff_t)len) < 0 ? errno : 0;
3076         if (v)
3077                 printf("%d/%d: fallocate(%s) %s %st %lld %lld %d\n",
3078                        procid, opno, translate_falloc_flags(mode),
3079                        f.path, st, (long long)off, (long long)len, e);
3080         free_pathname(&f);
3081         close(fd);
3082 #endif
3083 }
3084
3085 void
3086 fallocate_f(int opno, long r)
3087 {
3088 #ifdef HAVE_LINUX_FALLOC_H
3089         do_fallocate(opno, r, 0);
3090 #endif
3091 }
3092
3093 void
3094 fdatasync_f(int opno, long r)
3095 {
3096         int             e;
3097         pathname_t      f;
3098         int             fd;
3099         int             v;
3100
3101         init_pathname(&f);
3102         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3103                 if (v)
3104                         printf("%d/%d: fdatasync - no filename\n",
3105                                 procid, opno);
3106                 free_pathname(&f);
3107                 return;
3108         }
3109         fd = open_path(&f, O_WRONLY);
3110         e = fd < 0 ? errno : 0;
3111         check_cwd();
3112         if (fd < 0) {
3113                 if (v)
3114                         printf("%d/%d: fdatasync - open %s failed %d\n",
3115                                 procid, opno, f.path, e);
3116                 free_pathname(&f);
3117                 return;
3118         }
3119         e = fdatasync(fd) < 0 ? errno : 0;
3120         if (v)
3121                 printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e);
3122         free_pathname(&f);
3123         close(fd);
3124 }
3125
3126 #ifdef HAVE_LINUX_FIEMAP_H
3127 struct print_flags fiemap_flags[] = {
3128         { FIEMAP_FLAG_SYNC, "SYNC"},
3129         { FIEMAP_FLAG_XATTR, "XATTR"},
3130         { -1, NULL}
3131 };
3132
3133 #define translate_fiemap_flags(mode)    \
3134         ({translate_flags(mode, "|", fiemap_flags);})
3135 #endif
3136
3137 void
3138 fiemap_f(int opno, long r)
3139 {
3140 #ifdef HAVE_LINUX_FIEMAP_H
3141         int             e;
3142         pathname_t      f;
3143         int             fd;
3144         int64_t         lr;
3145         off64_t         off;
3146         struct stat64   stb;
3147         int             v;
3148         char            st[1024];
3149         int blocks_to_map;
3150         struct fiemap *fiemap;
3151
3152         init_pathname(&f);
3153         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3154                 if (v)
3155                         printf("%d/%d: fiemap - no filename\n", procid, opno);
3156                 free_pathname(&f);
3157                 return;
3158         }
3159         fd = open_path(&f, O_RDWR);
3160         e = fd < 0 ? errno : 0;
3161         check_cwd();
3162         if (fd < 0) {
3163                 if (v)
3164                         printf("%d/%d: fiemap - open %s failed %d\n",
3165                                 procid, opno, f.path, e);
3166                 free_pathname(&f);
3167                 return;
3168         }
3169         if (fstat64(fd, &stb) < 0) {
3170                 if (v)
3171                         printf("%d/%d: fiemap - fstat64 %s failed %d\n",
3172                                 procid, opno, f.path, errno);
3173                 free_pathname(&f);
3174                 close(fd);
3175                 return;
3176         }
3177         inode_info(st, sizeof(st), &stb, v);
3178         blocks_to_map = random() & 0xffff;
3179         fiemap = (struct fiemap *)malloc(sizeof(struct fiemap) +
3180                         (blocks_to_map * sizeof(struct fiemap_extent)));
3181         if (!fiemap) {
3182                 if (v)
3183                         printf("%d/%d: malloc failed \n", procid, opno);
3184                 free_pathname(&f);
3185                 close(fd);
3186                 return;
3187         }
3188         lr = ((int64_t)random() << 32) + random();
3189         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3190         off %= maxfsize;
3191         fiemap->fm_flags = random() & (FIEMAP_FLAGS_COMPAT | 0x10000);
3192         fiemap->fm_extent_count = blocks_to_map;
3193         fiemap->fm_mapped_extents = random() & 0xffff;
3194         fiemap->fm_start = off;
3195         fiemap->fm_length = ((int64_t)random() << 32) + random();
3196
3197         e = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
3198         if (v)
3199                 printf("%d/%d: ioctl(FIEMAP) %s%s %lld %lld (%s) %d\n",
3200                        procid, opno, f.path, st, (long long)fiemap->fm_start,
3201                        (long long) fiemap->fm_length,
3202                        translate_fiemap_flags(fiemap->fm_flags), e);
3203         free(fiemap);
3204         free_pathname(&f);
3205         close(fd);
3206 #endif
3207 }
3208
3209 void
3210 freesp_f(int opno, long r)
3211 {
3212         int             e;
3213         pathname_t      f;
3214         int             fd;
3215         struct xfs_flock64      fl;
3216         int64_t         lr;
3217         off64_t         off;
3218         struct stat64   stb;
3219         int             v;
3220         char            st[1024];
3221
3222         init_pathname(&f);
3223         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3224                 if (v)
3225                         printf("%d/%d: freesp - no filename\n", procid, opno);
3226                 free_pathname(&f);
3227                 return;
3228         }
3229         fd = open_path(&f, O_RDWR);
3230         e = fd < 0 ? errno : 0;
3231         check_cwd();
3232         if (fd < 0) {
3233                 if (v)
3234                         printf("%d/%d: freesp - open %s failed %d\n",
3235                                 procid, opno, f.path, e);
3236                 free_pathname(&f);
3237                 return;
3238         }
3239         if (fstat64(fd, &stb) < 0) {
3240                 if (v)
3241                         printf("%d/%d: freesp - fstat64 %s failed %d\n",
3242                                 procid, opno, f.path, errno);
3243                 free_pathname(&f);
3244                 close(fd);
3245                 return;
3246         }
3247         inode_info(st, sizeof(st), &stb, v);
3248         lr = ((int64_t)random() << 32) + random();
3249         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3250         off %= maxfsize;
3251         fl.l_whence = SEEK_SET;
3252         fl.l_start = off;
3253         fl.l_len = 0;
3254         e = xfsctl(f.path, fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
3255         if (v)
3256                 printf("%d/%d: xfsctl(XFS_IOC_FREESP64) %s%s %lld 0 %d\n",
3257                        procid, opno, f.path, st, (long long)off, e);
3258         free_pathname(&f);
3259         close(fd);
3260 }
3261
3262 void
3263 fsync_f(int opno, long r)
3264 {
3265         int             e;
3266         pathname_t      f;
3267         int             fd;
3268         int             v;
3269
3270         init_pathname(&f);
3271         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3272                 if (v)
3273                         printf("%d/%d: fsync - no filename\n", procid, opno);
3274                 free_pathname(&f);
3275                 return;
3276         }
3277         fd = open_path(&f, O_WRONLY);
3278         e = fd < 0 ? errno : 0;
3279         check_cwd();
3280         if (fd < 0) {
3281                 if (v)
3282                         printf("%d/%d: fsync - open %s failed %d\n",
3283                                 procid, opno, f.path, e);
3284                 free_pathname(&f);
3285                 return;
3286         }
3287         e = fsync(fd) < 0 ? errno : 0;
3288         if (v)
3289                 printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e);
3290         free_pathname(&f);
3291         close(fd);
3292 }
3293
3294 void
3295 getattr_f(int opno, long r)
3296 {
3297         int             fd;
3298         int             e;
3299         pathname_t      f;
3300         uint            fl;
3301         int             v;
3302
3303         init_pathname(&f);
3304         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
3305                 append_pathname(&f, ".");
3306         fd = open_path(&f, O_RDWR);
3307         e = fd < 0 ? errno : 0;
3308         check_cwd();
3309
3310         e = ioctl(fd, FS_IOC_GETFLAGS, &fl);
3311         if (v)
3312                 printf("%d/%d: getattr %s %u %d\n", procid, opno, f.path, fl, e);
3313         free_pathname(&f);
3314         close(fd);
3315 }
3316
3317 void
3318 getdents_f(int opno, long r)
3319 {
3320         DIR             *dir;
3321         pathname_t      f;
3322         int             v;
3323
3324         init_pathname(&f);
3325         if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
3326                 append_pathname(&f, ".");
3327         dir = opendir_path(&f);
3328         check_cwd();
3329         if (dir == NULL) {
3330                 if (v)
3331                         printf("%d/%d: getdents - can't open %s\n",
3332                                 procid, opno, f.path);
3333                 free_pathname(&f);
3334                 return;
3335         }
3336         while (readdir64(dir) != NULL)
3337                 continue;
3338         if (v)
3339                 printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
3340         free_pathname(&f);
3341         closedir(dir);
3342 }
3343
3344 void
3345 link_f(int opno, long r)
3346 {
3347         int             e;
3348         pathname_t      f;
3349         fent_t          *fep;
3350         flist_t         *flp;
3351         int             id;
3352         pathname_t      l;
3353         int             parid;
3354         int             v;
3355         int             v1;
3356
3357         init_pathname(&f);
3358         if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
3359                 if (v1)
3360                         printf("%d/%d: link - no file\n", procid, opno);
3361                 free_pathname(&f);
3362                 return;
3363         }
3364         if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
3365                 parid = -1;
3366         else
3367                 parid = fep->id;
3368         v |= v1;
3369         init_pathname(&l);
3370         e = generate_fname(fep, flp - flist, &l, &id, &v1);
3371         v |= v1;
3372         if (!e) {
3373                 if (v) {
3374                         (void)fent_to_name(&l, &flist[FT_DIR], fep);
3375                         printf("%d/%d: link - no filename from %s\n",
3376                                 procid, opno, l.path);
3377                 }
3378                 free_pathname(&l);
3379                 free_pathname(&f);
3380                 return;
3381         }
3382         e = link_path(&f, &l) < 0 ? errno : 0;
3383         check_cwd();
3384         if (e == 0)
3385                 add_to_flist(flp - flist, id, parid);
3386         if (v) {
3387                 printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
3388                         e);
3389                 printf("%d/%d: link add id=%d,parent=%d\n", procid, opno, id, parid);
3390         }
3391         free_pathname(&l);
3392         free_pathname(&f);
3393 }
3394
3395 void
3396 mkdir_f(int opno, long r)
3397 {
3398         int             e;
3399         pathname_t      f;
3400         fent_t          *fep;
3401         int             id;
3402         int             parid;
3403         int             v;
3404         int             v1;
3405
3406         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
3407                 parid = -1;
3408         else
3409                 parid = fep->id;
3410         init_pathname(&f);
3411         e = generate_fname(fep, FT_DIR, &f, &id, &v1);
3412         v |= v1;
3413         if (!e) {
3414                 if (v) {
3415                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
3416                         printf("%d/%d: mkdir - no filename from %s\n",
3417                                 procid, opno, f.path);
3418                 }
3419                 free_pathname(&f);
3420                 return;
3421         }
3422         e = mkdir_path(&f, 0777) < 0 ? errno : 0;
3423         check_cwd();
3424         if (e == 0)
3425                 add_to_flist(FT_DIR, id, parid);
3426         if (v) {
3427                 printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
3428                 printf("%d/%d: mkdir add id=%d,parent=%d\n", procid, opno, id, parid);
3429         }
3430         free_pathname(&f);
3431 }
3432
3433 void
3434 mknod_f(int opno, long r)
3435 {
3436         int             e;
3437         pathname_t      f;
3438         fent_t          *fep;
3439         int             id;
3440         int             parid;
3441         int             v;
3442         int             v1;
3443
3444         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
3445                 parid = -1;
3446         else
3447                 parid = fep->id;
3448         init_pathname(&f);
3449         e = generate_fname(fep, FT_DEV, &f, &id, &v1);
3450         v |= v1;
3451         if (!e) {
3452                 if (v) {
3453                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
3454                         printf("%d/%d: mknod - no filename from %s\n",
3455                                 procid, opno, f.path);
3456                 }
3457                 free_pathname(&f);
3458                 return;
3459         }
3460         e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
3461         check_cwd();
3462         if (e == 0)
3463                 add_to_flist(FT_DEV, id, parid);
3464         if (v) {
3465                 printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
3466                 printf("%d/%d: mknod add id=%d,parent=%d\n", procid, opno, id, parid);
3467         }
3468         free_pathname(&f);
3469 }
3470
3471 #ifdef HAVE_SYS_MMAN_H
3472 struct print_flags mmap_flags[] = {
3473         { MAP_SHARED, "SHARED"},
3474         { MAP_PRIVATE, "PRIVATE"},
3475         { -1, NULL}
3476 };
3477
3478 #define translate_mmap_flags(flags)       \
3479         ({translate_flags(flags, "|", mmap_flags);})
3480 #endif
3481
3482 void
3483 do_mmap(int opno, long r, int prot)
3484 {
3485 #ifdef HAVE_SYS_MMAN_H
3486         char            *addr;
3487         int             e;
3488         pathname_t      f;
3489         int             fd;
3490         size_t          len;
3491         int64_t         lr;
3492         off64_t         off;
3493         int             flags;
3494         struct stat64   stb;
3495         int             v;
3496         char            st[1024];
3497         sigjmp_buf      sigbus_jmpbuf;
3498
3499         init_pathname(&f);
3500         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3501                 if (v)
3502                         printf("%d/%d: do_mmap - no filename\n", procid, opno);
3503                 free_pathname(&f);
3504                 return;
3505         }
3506         fd = open_path(&f, O_RDWR);
3507         e = fd < 0 ? errno : 0;
3508         check_cwd();
3509         if (fd < 0) {
3510                 if (v)
3511                         printf("%d/%d: do_mmap - open %s failed %d\n",
3512                                procid, opno, f.path, e);
3513                 free_pathname(&f);
3514                 return;
3515         }
3516         if (fstat64(fd, &stb) < 0) {
3517                 if (v)
3518                         printf("%d/%d: do_mmap - fstat64 %s failed %d\n",
3519                                procid, opno, f.path, errno);
3520                 free_pathname(&f);
3521                 close(fd);
3522                 return;
3523         }
3524         inode_info(st, sizeof(st), &stb, v);
3525         if (stb.st_size == 0) {
3526                 if (v)
3527                         printf("%d/%d: do_mmap - %s%s zero size\n", procid, opno,
3528                                f.path, st);
3529                 free_pathname(&f);
3530                 close(fd);
3531                 return;
3532         }
3533
3534         lr = ((int64_t)random() << 32) + random();
3535         off = (off64_t)(lr % stb.st_size);
3536         off &= (off64_t)(~(sysconf(_SC_PAGE_SIZE) - 1));
3537         len = (size_t)(random() % MIN(stb.st_size - off, FILELEN_MAX)) + 1;
3538
3539         flags = (random() % 2) ? MAP_SHARED : MAP_PRIVATE;
3540         addr = mmap(NULL, len, prot, flags, fd, off);
3541         e = (addr == MAP_FAILED) ? errno : 0;
3542         if (e) {
3543                 if (v)
3544                         printf("%d/%d: do_mmap - mmap failed %s%s [%lld,%d,%s] %d\n",
3545                                procid, opno, f.path, st, (long long)off,
3546                                (int)len, translate_mmap_flags(flags), e);
3547                 free_pathname(&f);
3548                 close(fd);
3549                 return;
3550         }
3551
3552         if (prot & PROT_WRITE) {
3553                 if ((e = sigsetjmp(sigbus_jmpbuf, 1)) == 0) {
3554                         sigbus_jmp = &sigbus_jmpbuf;
3555                         memset(addr, nameseq & 0xff, len);
3556                 }
3557         } else {
3558                 char *buf;
3559                 if ((buf = malloc(len)) != NULL) {
3560                         memcpy(buf, addr, len);
3561                         free(buf);
3562                 }
3563         }
3564         munmap(addr, len);
3565         /* set NULL to stop other functions from doing siglongjmp */
3566         sigbus_jmp = NULL;
3567
3568         if (v)
3569                 printf("%d/%d: %s %s%s [%lld,%d,%s] %s\n",
3570                        procid, opno, (prot & PROT_WRITE) ? "mwrite" : "mread",
3571                        f.path, st, (long long)off, (int)len,
3572                        translate_mmap_flags(flags),
3573                        (e == 0) ? "0" : "Bus error");
3574
3575         free_pathname(&f);
3576         close(fd);
3577 #endif
3578 }
3579
3580 void
3581 mread_f(int opno, long r)
3582 {
3583 #ifdef HAVE_SYS_MMAN_H
3584         do_mmap(opno, r, PROT_READ);
3585 #endif
3586 }
3587
3588 void
3589 mwrite_f(int opno, long r)
3590 {
3591 #ifdef HAVE_SYS_MMAN_H
3592         do_mmap(opno, r, PROT_WRITE);
3593 #endif
3594 }
3595
3596 void
3597 punch_f(int opno, long r)
3598 {
3599 #ifdef HAVE_LINUX_FALLOC_H
3600         do_fallocate(opno, r, FALLOC_FL_PUNCH_HOLE);
3601 #endif
3602 }
3603
3604 void
3605 zero_f(int opno, long r)
3606 {
3607 #ifdef HAVE_LINUX_FALLOC_H
3608         do_fallocate(opno, r, FALLOC_FL_ZERO_RANGE);
3609 #endif
3610 }
3611
3612 void
3613 collapse_f(int opno, long r)
3614 {
3615 #ifdef HAVE_LINUX_FALLOC_H
3616         do_fallocate(opno, r, FALLOC_FL_COLLAPSE_RANGE);
3617 #endif
3618 }
3619
3620 void
3621 insert_f(int opno, long r)
3622 {
3623 #ifdef HAVE_LINUX_FALLOC_H
3624         do_fallocate(opno, r, FALLOC_FL_INSERT_RANGE);
3625 #endif
3626 }
3627
3628 void
3629 read_f(int opno, long r)
3630 {
3631         char            *buf;
3632         int             e;
3633         pathname_t      f;
3634         int             fd;
3635         size_t          len;
3636         int64_t         lr;
3637         off64_t         off;
3638         struct stat64   stb;
3639         int             v;
3640         char            st[1024];
3641
3642         init_pathname(&f);
3643         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3644                 if (v)
3645                         printf("%d/%d: read - no filename\n", procid, opno);
3646                 free_pathname(&f);
3647                 return;
3648         }
3649         fd = open_path(&f, O_RDONLY);
3650         e = fd < 0 ? errno : 0;
3651         check_cwd();
3652         if (fd < 0) {
3653                 if (v)
3654                         printf("%d/%d: read - open %s failed %d\n",
3655                                 procid, opno, f.path, e);
3656                 free_pathname(&f);
3657                 return;
3658         }
3659         if (fstat64(fd, &stb) < 0) {
3660                 if (v)
3661                         printf("%d/%d: read - fstat64 %s failed %d\n",
3662                                 procid, opno, f.path, errno);
3663                 free_pathname(&f);
3664                 close(fd);
3665                 return;
3666         }
3667         inode_info(st, sizeof(st), &stb, v);
3668         if (stb.st_size == 0) {
3669                 if (v)
3670                         printf("%d/%d: read - %s%s zero size\n", procid, opno,
3671                                f.path, st);
3672                 free_pathname(&f);
3673                 close(fd);
3674                 return;
3675         }
3676         lr = ((int64_t)random() << 32) + random();
3677         off = (off64_t)(lr % stb.st_size);
3678         lseek64(fd, off, SEEK_SET);
3679         len = (random() % FILELEN_MAX) + 1;
3680         buf = malloc(len);
3681         e = read(fd, buf, len) < 0 ? errno : 0;
3682         free(buf);
3683         if (v)
3684                 printf("%d/%d: read %s%s [%lld,%d] %d\n",
3685                        procid, opno, f.path, st, (long long)off, (int)len, e);
3686         free_pathname(&f);
3687         close(fd);
3688 }
3689
3690 void
3691 readlink_f(int opno, long r)
3692 {
3693         char            buf[PATH_MAX];
3694         int             e;
3695         pathname_t      f;
3696         int             v;
3697
3698         init_pathname(&f);
3699         if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
3700                 if (v)
3701                         printf("%d/%d: readlink - no filename\n", procid, opno);
3702                 free_pathname(&f);
3703                 return;
3704         }
3705         e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
3706         check_cwd();
3707         if (v)
3708                 printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e);
3709         free_pathname(&f);
3710 }
3711
3712 void
3713 readv_f(int opno, long r)
3714 {
3715         char            *buf;
3716         int             e;
3717         pathname_t      f;
3718         int             fd;
3719         size_t          len;
3720         int64_t         lr;
3721         off64_t         off;
3722         struct stat64   stb;
3723         int             v;
3724         char            st[1024];
3725         struct iovec    *iov = NULL;
3726         int             iovcnt;
3727         size_t          iovb;
3728         size_t          iovl;
3729         int             i;
3730
3731         init_pathname(&f);
3732         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3733                 if (v)
3734                         printf("%d/%d: readv - no filename\n", procid, opno);
3735                 free_pathname(&f);
3736                 return;
3737         }
3738         fd = open_path(&f, O_RDONLY);
3739         e = fd < 0 ? errno : 0;
3740         check_cwd();
3741         if (fd < 0) {
3742                 if (v)
3743                         printf("%d/%d: readv - open %s failed %d\n",
3744                                 procid, opno, f.path, e);
3745                 free_pathname(&f);
3746                 return;
3747         }
3748         if (fstat64(fd, &stb) < 0) {
3749                 if (v)
3750                         printf("%d/%d: readv - fstat64 %s failed %d\n",
3751                                 procid, opno, f.path, errno);
3752                 free_pathname(&f);
3753                 close(fd);
3754                 return;
3755         }
3756         inode_info(st, sizeof(st), &stb, v);
3757         if (stb.st_size == 0) {
3758                 if (v)
3759                         printf("%d/%d: readv - %s%s zero size\n", procid, opno,
3760                                f.path, st);
3761                 free_pathname(&f);
3762                 close(fd);
3763                 return;
3764         }
3765         lr = ((int64_t)random() << 32) + random();
3766         off = (off64_t)(lr % stb.st_size);
3767         lseek64(fd, off, SEEK_SET);
3768         len = (random() % FILELEN_MAX) + 1;
3769         buf = malloc(len);
3770
3771         iovcnt = (random() % MIN(len, IOV_MAX)) + 1;
3772         iov = calloc(iovcnt, sizeof(struct iovec));
3773         iovl = len / iovcnt;
3774         iovb = 0;
3775         for (i=0; i<iovcnt; i++) {
3776                 (iov + i)->iov_base = (buf + iovb);
3777                 (iov + i)->iov_len  = iovl;
3778                 iovb += iovl;
3779         }
3780
3781         e = readv(fd, iov, iovcnt) < 0 ? errno : 0;
3782         free(buf);
3783         if (v)
3784                 printf("%d/%d: readv %s%s [%lld,%d,%d] %d\n",
3785                        procid, opno, f.path, st, (long long)off, (int)iovl,
3786                        iovcnt, e);
3787         free_pathname(&f);
3788         close(fd);
3789 }
3790
3791 void
3792 rename_f(int opno, long r)
3793 {
3794         fent_t          *dfep;
3795         int             e;
3796         pathname_t      f;
3797         fent_t          *fep;
3798         flist_t         *flp;
3799         int             id;
3800         pathname_t      newf;
3801         int             oldid;
3802         int             parid;
3803         int             v;
3804         int             v1;
3805
3806         /* get an existing path for the source of the rename */
3807         init_pathname(&f);
3808         if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
3809                 if (v1)
3810                         printf("%d/%d: rename - no filename\n", procid, opno);
3811                 free_pathname(&f);
3812                 return;
3813         }
3814
3815         /* get an existing directory for the destination parent directory name */
3816         if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
3817                 parid = -1;
3818         else
3819                 parid = dfep->id;
3820         v |= v1;
3821
3822         /* generate a new path using an existing parent directory in name */
3823         init_pathname(&newf);
3824         e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
3825         v |= v1;
3826         if (!e) {
3827                 if (v) {
3828                         (void)fent_to_name(&f, &flist[FT_DIR], dfep);
3829                         printf("%d/%d: rename - no filename from %s\n",
3830                                 procid, opno, f.path);
3831                 }
3832                 free_pathname(&newf);
3833                 free_pathname(&f);
3834                 return;
3835         }
3836         e = rename_path(&f, &newf) < 0 ? errno : 0;
3837         check_cwd();
3838         if (e == 0) {
3839                 if (flp - flist == FT_DIR) {
3840                         oldid = fep->id;
3841                         fix_parent(oldid, id);
3842                 }
3843                 del_from_flist(flp - flist, fep - flp->fents);
3844                 add_to_flist(flp - flist, id, parid);
3845         }
3846         if (v) {
3847                 printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
3848                         newf.path, e);
3849                 if (e == 0) {
3850                         printf("%d/%d: rename del entry: id=%d,parent=%d\n",
3851                                 procid, opno, fep->id, fep->parent);
3852                         printf("%d/%d: rename add entry: id=%d,parent=%d\n",
3853                                 procid, opno, id, parid);
3854                 }
3855         }
3856         free_pathname(&newf);
3857         free_pathname(&f);
3858 }
3859
3860 void
3861 resvsp_f(int opno, long r)
3862 {
3863         int             e;
3864         pathname_t      f;
3865         int             fd;
3866         struct xfs_flock64      fl;
3867         int64_t         lr;
3868         off64_t         off;
3869         struct stat64   stb;
3870         int             v;
3871         char            st[1024];
3872
3873         init_pathname(&f);
3874         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3875                 if (v)
3876                         printf("%d/%d: resvsp - no filename\n", procid, opno);
3877                 free_pathname(&f);
3878                 return;
3879         }
3880         fd = open_path(&f, O_RDWR);
3881         e = fd < 0 ? errno : 0;
3882         check_cwd();
3883         if (fd < 0) {
3884                 if (v)
3885                         printf("%d/%d: resvsp - open %s failed %d\n",
3886                                 procid, opno, f.path, e);
3887                 free_pathname(&f);
3888                 return;
3889         }
3890         if (fstat64(fd, &stb) < 0) {
3891                 if (v)
3892                         printf("%d/%d: resvsp - fstat64 %s failed %d\n",
3893                                 procid, opno, f.path, errno);
3894                 free_pathname(&f);
3895                 close(fd);
3896                 return;
3897         }
3898         inode_info(st, sizeof(st), &stb, v);
3899         lr = ((int64_t)random() << 32) + random();
3900         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3901         off %= maxfsize;
3902         fl.l_whence = SEEK_SET;
3903         fl.l_start = off;
3904         fl.l_len = (off64_t)(random() % (1024 * 1024));
3905         e = xfsctl(f.path, fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
3906         if (v)
3907                 printf("%d/%d: xfsctl(XFS_IOC_RESVSP64) %s%s %lld %lld %d\n",
3908                        procid, opno, f.path, st,
3909                         (long long)off, (long long)fl.l_len, e);
3910         free_pathname(&f);
3911         close(fd);
3912 }
3913
3914 void
3915 rmdir_f(int opno, long r)
3916 {
3917         int             e;
3918         pathname_t      f;
3919         fent_t          *fep;
3920         int             v;
3921
3922         init_pathname(&f);
3923         if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
3924                 if (v)
3925                         printf("%d/%d: rmdir - no directory\n", procid, opno);
3926                 free_pathname(&f);
3927                 return;
3928         }
3929         e = rmdir_path(&f) < 0 ? errno : 0;
3930         check_cwd();
3931         if (e == 0)
3932                 del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
3933         if (v) {
3934                 printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e);
3935                 if (e == 0)
3936                         printf("%d/%d: rmdir del entry: id=%d,parent=%d\n",
3937                                 procid, opno, fep->id, fep->parent);
3938         }
3939         free_pathname(&f);
3940 }
3941
3942 void
3943 setattr_f(int opno, long r)
3944 {
3945         int             fd;
3946         int             e;
3947         pathname_t      f;
3948         uint            fl;
3949         int             v;
3950
3951         init_pathname(&f);
3952         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
3953                 append_pathname(&f, ".");
3954         fd = open_path(&f, O_RDWR);
3955         e = fd < 0 ? errno : 0;
3956         check_cwd();
3957
3958         fl = attr_mask & (uint)random();
3959         e = ioctl(fd, FS_IOC_SETFLAGS, &fl);
3960         if (v)
3961                 printf("%d/%d: setattr %s %x %d\n", procid, opno, f.path, fl, e);
3962         free_pathname(&f);
3963         close(fd);
3964 }
3965
3966 void
3967 stat_f(int opno, long r)
3968 {
3969         int             e;
3970         pathname_t      f;
3971         struct stat64   stb;
3972         int             v;
3973
3974         init_pathname(&f);
3975         if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
3976                 if (v)
3977                         printf("%d/%d: stat - no entries\n", procid, opno);
3978                 free_pathname(&f);
3979                 return;
3980         }
3981         e = lstat64_path(&f, &stb) < 0 ? errno : 0;
3982         check_cwd();
3983         if (v)
3984                 printf("%d/%d: stat %s %d\n", procid, opno, f.path, e);
3985         free_pathname(&f);
3986 }
3987
3988 void
3989 symlink_f(int opno, long r)
3990 {
3991         int             e;
3992         pathname_t      f;
3993         fent_t          *fep;
3994         int             i;
3995         int             id;
3996         int             len;
3997         int             parid;
3998         int             v;
3999         int             v1;
4000         char            *val;
4001
4002         if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
4003                 parid = -1;
4004         else
4005                 parid = fep->id;
4006         init_pathname(&f);
4007         e = generate_fname(fep, FT_SYM, &f, &id, &v1);
4008         v |= v1;
4009         if (!e) {
4010                 if (v) {
4011                         (void)fent_to_name(&f, &flist[FT_DIR], fep);
4012                         printf("%d/%d: symlink - no filename from %s\n",
4013                                 procid, opno, f.path);
4014                 }
4015                 free_pathname(&f);
4016                 return;
4017         }
4018         len = (int)(random() % PATH_MAX);
4019         val = malloc(len + 1);
4020         if (len)
4021                 memset(val, 'x', len);
4022         val[len] = '\0';
4023         for (i = 10; i < len - 1; i += 10)
4024                 val[i] = '/';
4025         e = symlink_path(val, &f) < 0 ? errno : 0;
4026         check_cwd();
4027         if (e == 0)
4028                 add_to_flist(FT_SYM, id, parid);
4029         free(val);
4030         if (v) {
4031                 printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
4032                 printf("%d/%d: symlink add id=%d,parent=%d\n", procid, opno, id, parid);
4033         }
4034         free_pathname(&f);
4035 }
4036
4037 /* ARGSUSED */
4038 void
4039 sync_f(int opno, long r)
4040 {
4041         sync();
4042         if (verbose)
4043                 printf("%d/%d: sync\n", procid, opno);
4044 }
4045
4046 void
4047 truncate_f(int opno, long r)
4048 {
4049         int             e;
4050         pathname_t      f;
4051         int64_t         lr;
4052         off64_t         off;
4053         struct stat64   stb;
4054         int             v;
4055         char            st[1024];
4056
4057         init_pathname(&f);
4058         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
4059                 if (v)
4060                         printf("%d/%d: truncate - no filename\n", procid, opno);
4061                 free_pathname(&f);
4062                 return;
4063         }
4064         e = stat64_path(&f, &stb) < 0 ? errno : 0;
4065         check_cwd();
4066         if (e > 0) {
4067                 if (v)
4068                         printf("%d/%d: truncate - stat64 %s failed %d\n",
4069                                 procid, opno, f.path, e);
4070                 free_pathname(&f);
4071                 return;
4072         }
4073         inode_info(st, sizeof(st), &stb, v);
4074         lr = ((int64_t)random() << 32) + random();
4075         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
4076         off %= maxfsize;
4077         e = truncate64_path(&f, off) < 0 ? errno : 0;
4078         check_cwd();
4079         if (v)
4080                 printf("%d/%d: truncate %s%s %lld %d\n", procid, opno, f.path,
4081                        st, (long long)off, e);
4082         free_pathname(&f);
4083 }
4084
4085 void
4086 unlink_f(int opno, long r)
4087 {
4088         int             e;
4089         pathname_t      f;
4090         fent_t          *fep;
4091         flist_t         *flp;
4092         int             v;
4093
4094         init_pathname(&f);
4095         if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
4096                 if (v)
4097                         printf("%d/%d: unlink - no file\n", procid, opno);
4098                 free_pathname(&f);
4099                 return;
4100         }
4101         e = unlink_path(&f) < 0 ? errno : 0;
4102         check_cwd();
4103         if (e == 0)
4104                 del_from_flist(flp - flist, fep - flp->fents);
4105         if (v) {
4106                 printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e);
4107                 if (e == 0)
4108                         printf("%d/%d: unlink del entry: id=%d,parent=%d\n",
4109                                 procid, opno, fep->id, fep->parent);
4110         }
4111         free_pathname(&f);
4112 }
4113
4114 void
4115 unresvsp_f(int opno, long r)
4116 {
4117         int             e;
4118         pathname_t      f;
4119         int             fd;
4120         struct xfs_flock64      fl;
4121         int64_t         lr;
4122         off64_t         off;
4123         struct stat64   stb;
4124         int             v;
4125         char            st[1024];
4126
4127         init_pathname(&f);
4128         if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
4129                 if (v)
4130                         printf("%d/%d: unresvsp - no filename\n", procid, opno);
4131                 free_pathname(&f);
4132                 return;
4133         }
4134         fd = open_path(&f, O_RDWR);
4135         e = fd < 0 ? errno : 0;
4136         check_cwd();
4137         if (fd < 0) {
4138                 if (v)
4139                         printf("%d/%d: unresvsp - open %s failed %d\n",
4140                                 procid, opno, f.path, e);
4141                 free_pathname(&f);
4142                 return;
4143         }
4144         if (fstat64(fd, &stb) < 0) {
4145                 if (v)
4146                         printf("%d/%d: unresvsp - fstat64 %s failed %d\n",
4147                                 procid, opno, f.path, errno);
4148                 free_pathname(&f);
4149                 close(fd);
4150                 return;
4151         }
4152         inode_info(st, sizeof(st), &stb, v);
4153         lr = ((int64_t)random() << 32) + random();
4154         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
4155         off %= maxfsize;
4156         fl.l_whence = SEEK_SET;
4157         fl.l_start = off;
4158         fl.l_len = (off64_t)(random() % (1 << 20));
4159         e = xfsctl(f.path, fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
4160         if (v)
4161                 printf("%d/%d: xfsctl(XFS_IOC_UNRESVSP64) %s%s %lld %lld %d\n",
4162                        procid, opno, f.path, st,
4163                         (long long)off, (long long)fl.l_len, e);
4164         free_pathname(&f);
4165         close(fd);
4166 }
4167
4168 void
4169 write_f(int opno, long r)
4170 {
4171         char            *buf;
4172         int             e;
4173         pathname_t      f;
4174         int             fd;
4175         size_t          len;
4176         int64_t         lr;
4177         off64_t         off;
4178         struct stat64   stb;
4179         int             v;
4180         char            st[1024];
4181
4182         init_pathname(&f);
4183         if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
4184                 if (v)
4185                         printf("%d/%d: write - no filename\n", procid, opno);
4186                 free_pathname(&f);
4187                 return;
4188         }
4189         fd = open_path(&f, O_WRONLY);
4190         e = fd < 0 ? errno : 0;
4191         check_cwd();
4192         if (fd < 0) {
4193                 if (v)
4194                         printf("%d/%d: write - open %s failed %d\n",
4195                                 procid, opno, f.path, e);
4196                 free_pathname(&f);
4197                 return;
4198         }
4199         if (fstat64(fd, &stb) < 0) {
4200                 if (v)
4201                         printf("%d/%d: write - fstat64 %s failed %d\n",
4202                                 procid, opno, f.path, errno);
4203                 free_pathname(&f);
4204                 close(fd);
4205                 return;
4206         }
4207         inode_info(st, sizeof(st), &stb, v);
4208         lr = ((int64_t)random() << 32) + random();
4209         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
4210         off %= maxfsize;
4211         lseek64(fd, off, SEEK_SET);
4212         len = (random() % FILELEN_MAX) + 1;
4213         buf = malloc(len);
4214         memset(buf, nameseq & 0xff, len);
4215         e = write(fd, buf, len) < 0 ? errno : 0;
4216         free(buf);
4217         if (v)
4218                 printf("%d/%d: write %s%s [%lld,%d] %d\n",
4219                        procid, opno, f.path, st, (long long)off, (int)len, e);
4220         free_pathname(&f);
4221         close(fd);
4222 }
4223
4224 void
4225 writev_f(int opno, long r)
4226 {
4227         char            *buf;
4228         int             e;
4229         pathname_t      f;
4230         int             fd;
4231         size_t          len;
4232         int64_t         lr;
4233         off64_t         off;
4234         struct stat64   stb;
4235         int             v;
4236         char            st[1024];
4237         struct iovec    *iov = NULL;
4238         int             iovcnt;
4239         size_t          iovb;
4240         size_t          iovl;
4241         int             i;
4242
4243         init_pathname(&f);
4244         if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
4245                 if (v)
4246                         printf("%d/%d: writev - no filename\n", procid, opno);
4247                 free_pathname(&f);
4248                 return;
4249         }
4250         fd = open_path(&f, O_WRONLY);
4251         e = fd < 0 ? errno : 0;
4252         check_cwd();
4253         if (fd < 0) {
4254                 if (v)
4255                         printf("%d/%d: writev - open %s failed %d\n",
4256                                 procid, opno, f.path, e);
4257                 free_pathname(&f);
4258                 return;
4259         }
4260         if (fstat64(fd, &stb) < 0) {
4261                 if (v)
4262                         printf("%d/%d: writev - fstat64 %s failed %d\n",
4263                                 procid, opno, f.path, errno);
4264                 free_pathname(&f);
4265                 close(fd);
4266                 return;
4267         }
4268         inode_info(st, sizeof(st), &stb, v);
4269         lr = ((int64_t)random() << 32) + random();
4270         off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
4271         off %= maxfsize;
4272         lseek64(fd, off, SEEK_SET);
4273         len = (random() % FILELEN_MAX) + 1;
4274         buf = malloc(len);
4275         memset(buf, nameseq & 0xff, len);
4276
4277         iovcnt = (random() % MIN(len, IOV_MAX)) + 1;
4278         iov = calloc(iovcnt, sizeof(struct iovec));
4279         iovl = len / iovcnt;
4280         iovb = 0;
4281         for (i=0; i<iovcnt; i++) {
4282                 (iov + i)->iov_base = (buf + iovb);
4283                 (iov + i)->iov_len  = iovl;
4284                 iovb += iovl;
4285         }
4286
4287         e = writev(fd, iov, iovcnt) < 0 ? errno : 0;
4288         free(buf);
4289         free(iov);
4290         if (v)
4291                 printf("%d/%d: writev %s%s [%lld,%d,%d] %d\n",
4292                        procid, opno, f.path, st, (long long)off, (int)iovl,
4293                        iovcnt, e);
4294         free_pathname(&f);
4295         close(fd);
4296 }