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