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