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