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