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