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