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