1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2002 Silicon Graphics, Inc.
15 #ifdef HAVE_BTRFSUTIL_H
16 #include <btrfsutil.h>
18 #ifdef HAVE_LINUX_FIEMAP_H
19 #include <linux/fiemap.h>
21 #ifdef HAVE_SYS_PRCTL_H
22 #include <sys/prctl.h>
31 #define URING_ENTRIES 1
33 bool have_io_uring; /* to indicate runtime availability */
35 #include <sys/syscall.h>
36 #include <sys/xattr.h>
38 #ifndef FS_IOC_GETFLAGS
39 #define FS_IOC_GETFLAGS _IOR('f', 1, long)
41 #ifndef FS_IOC_SETFLAGS
42 #define FS_IOC_SETFLAGS _IOW('f', 2, long)
46 #define XFS_ERRTAG_MAX 17
47 #define XFS_IDMODULO_MAX 31 /* user/group IDs (1 << x) */
48 #define XFS_PROJIDMODULO_MAX 16 /* project IDs (1 << x) */
53 #ifndef HAVE_RENAMEAT2
54 #if !defined(SYS_renameat2) && defined(__x86_64__)
55 #define SYS_renameat2 316
58 #if !defined(SYS_renameat2) && defined(__i386__)
59 #define SYS_renameat2 353
62 static int renameat2(int dfd1, const char *path1,
63 int dfd2, const char *path2,
67 return syscall(SYS_renameat2, dfd1, path1, dfd2, path2, flags);
75 #ifndef RENAME_NOREPLACE
76 #define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */
78 #ifndef RENAME_EXCHANGE
79 #define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
81 #ifndef RENAME_WHITEOUT
82 #define RENAME_WHITEOUT (1 << 2) /* Whiteout source */
85 #define FILELEN_MAX (32*4096)
149 typedef long long opnum_t;
151 typedef void (*opfnc_t)(opnum_t, long);
153 typedef struct opdesc {
160 typedef struct fent {
167 typedef struct flist {
174 typedef struct pathname {
184 struct print_string {
191 #define FT_DIRm (1 << FT_DIR)
193 #define FT_REGm (1 << FT_REG)
195 #define FT_SYMm (1 << FT_SYM)
197 #define FT_DEVm (1 << FT_DEV)
199 #define FT_RTFm (1 << FT_RTF)
201 #define FT_SUBVOLm (1 << FT_SUBVOL)
203 #define FT_ANYm ((1 << FT_nft) - 1)
204 #define FT_REGFILE (FT_REGm | FT_RTFm)
205 #define FT_NOTDIR (FT_ANYm & (~FT_DIRm & ~FT_SUBVOLm))
206 #define FT_ANYDIR (FT_DIRm | FT_SUBVOLm)
208 #define FLIST_SLOT_INCR 16
211 #define MAXFSIZE ((1ULL << 63) - 1ULL)
212 #define MAXFSIZE32 ((1ULL << 40) - 1ULL)
214 #define XATTR_NAME_BUF_SIZE 18
216 void afsync_f(opnum_t, long);
217 void aread_f(opnum_t, long);
218 void attr_remove_f(opnum_t, long);
219 void attr_set_f(opnum_t, long);
220 void awrite_f(opnum_t, long);
221 void bulkstat_f(opnum_t, long);
222 void bulkstat1_f(opnum_t, long);
223 void chown_f(opnum_t, long);
224 void clonerange_f(opnum_t, long);
225 void copyrange_f(opnum_t, long);
226 void creat_f(opnum_t, long);
227 void deduperange_f(opnum_t, long);
228 void dread_f(opnum_t, long);
229 void dwrite_f(opnum_t, long);
230 void fallocate_f(opnum_t, long);
231 void fdatasync_f(opnum_t, long);
232 void fiemap_f(opnum_t, long);
233 void fsync_f(opnum_t, long);
234 char *gen_random_string(int);
235 void getattr_f(opnum_t, long);
236 void getdents_f(opnum_t, long);
237 void getfattr_f(opnum_t, long);
238 void link_f(opnum_t, long);
239 void listfattr_f(opnum_t, long);
240 void mkdir_f(opnum_t, long);
241 void mknod_f(opnum_t, long);
242 void mread_f(opnum_t, long);
243 void mwrite_f(opnum_t, long);
244 void punch_f(opnum_t, long);
245 void zero_f(opnum_t, long);
246 void collapse_f(opnum_t, long);
247 void insert_f(opnum_t, long);
248 void read_f(opnum_t, long);
249 void readlink_f(opnum_t, long);
250 void readv_f(opnum_t, long);
251 void removefattr_f(opnum_t, long);
252 void rename_f(opnum_t, long);
253 void rnoreplace_f(opnum_t, long);
254 void rexchange_f(opnum_t, long);
255 void rwhiteout_f(opnum_t, long);
256 void resvsp_f(opnum_t, long);
257 void rmdir_f(opnum_t, long);
258 void setattr_f(opnum_t, long);
259 void setfattr_f(opnum_t, long);
260 void setxattr_f(opnum_t, long);
261 void snapshot_f(opnum_t, long);
262 void splice_f(opnum_t, long);
263 void stat_f(opnum_t, long);
264 void subvol_create_f(opnum_t, long);
265 void subvol_delete_f(opnum_t, long);
266 void symlink_f(opnum_t, long);
267 void sync_f(opnum_t, long);
268 void truncate_f(opnum_t, long);
269 void unlink_f(opnum_t, long);
270 void unresvsp_f(opnum_t, long);
271 void uring_read_f(opnum_t, long);
272 void uring_write_f(opnum_t, long);
273 void write_f(opnum_t, long);
274 void writev_f(opnum_t, long);
275 char *xattr_flag_to_string(int);
277 struct opdesc ops[OP_LAST] = {
278 /* [OP_ENUM] = {"name", function, freq, iswrite }, */
279 [OP_AFSYNC] = {"afsync", afsync_f, 0, 1 },
280 [OP_AREAD] = {"aread", aread_f, 1, 0 },
281 [OP_ATTR_REMOVE] = {"attr_remove", attr_remove_f, 0, 1 },
282 [OP_ATTR_SET] = {"attr_set", attr_set_f, 0, 1 },
283 [OP_AWRITE] = {"awrite", awrite_f, 1, 1 },
284 [OP_BULKSTAT] = {"bulkstat", bulkstat_f, 1, 0 },
285 [OP_BULKSTAT1] = {"bulkstat1", bulkstat1_f, 1, 0 },
286 [OP_CHOWN] = {"chown", chown_f, 3, 1 },
287 [OP_CLONERANGE] = {"clonerange", clonerange_f, 4, 1 },
288 [OP_COPYRANGE] = {"copyrange", copyrange_f, 4, 1 },
289 [OP_CREAT] = {"creat", creat_f, 4, 1 },
290 [OP_DEDUPERANGE] = {"deduperange", deduperange_f, 4, 1 },
291 [OP_DREAD] = {"dread", dread_f, 4, 0 },
292 [OP_DWRITE] = {"dwrite", dwrite_f, 4, 1 },
293 [OP_FALLOCATE] = {"fallocate", fallocate_f, 1, 1 },
294 [OP_FDATASYNC] = {"fdatasync", fdatasync_f, 1, 1 },
295 [OP_FIEMAP] = {"fiemap", fiemap_f, 1, 1 },
296 [OP_FSYNC] = {"fsync", fsync_f, 1, 1 },
297 [OP_GETATTR] = {"getattr", getattr_f, 1, 0 },
298 [OP_GETDENTS] = {"getdents", getdents_f, 1, 0 },
299 /* get extended attribute */
300 [OP_GETFATTR] = {"getfattr", getfattr_f, 1, 0 },
301 [OP_LINK] = {"link", link_f, 1, 1 },
302 /* list extent attributes */
303 [OP_LISTFATTR] = {"listfattr", listfattr_f, 1, 0 },
304 [OP_MKDIR] = {"mkdir", mkdir_f, 2, 1 },
305 [OP_MKNOD] = {"mknod", mknod_f, 2, 1 },
306 [OP_MREAD] = {"mread", mread_f, 2, 0 },
307 [OP_MWRITE] = {"mwrite", mwrite_f, 2, 1 },
308 [OP_PUNCH] = {"punch", punch_f, 1, 1 },
309 [OP_ZERO] = {"zero", zero_f, 1, 1 },
310 [OP_COLLAPSE] = {"collapse", collapse_f, 1, 1 },
311 [OP_INSERT] = {"insert", insert_f, 1, 1 },
312 [OP_READ] = {"read", read_f, 1, 0 },
313 [OP_READLINK] = {"readlink", readlink_f, 1, 0 },
314 [OP_READV] = {"readv", readv_f, 1, 0 },
315 /* remove (delete) extended attribute */
316 [OP_REMOVEFATTR] = {"removefattr", removefattr_f, 1, 1 },
317 [OP_RENAME] = {"rename", rename_f, 2, 1 },
318 [OP_RNOREPLACE] = {"rnoreplace", rnoreplace_f, 2, 1 },
319 [OP_REXCHANGE] = {"rexchange", rexchange_f, 2, 1 },
320 [OP_RWHITEOUT] = {"rwhiteout", rwhiteout_f, 2, 1 },
321 [OP_RESVSP] = {"resvsp", resvsp_f, 1, 1 },
322 [OP_RMDIR] = {"rmdir", rmdir_f, 1, 1 },
323 /* set attribute flag (FS_IOC_SETFLAGS ioctl) */
324 [OP_SETATTR] = {"setattr", setattr_f, 0, 1 },
325 /* set extended attribute */
326 [OP_SETFATTR] = {"setfattr", setfattr_f, 2, 1 },
327 /* set project id (XFS_IOC_FSSETXATTR ioctl) */
328 [OP_SETXATTR] = {"setxattr", setxattr_f, 1, 1 },
329 [OP_SNAPSHOT] = {"snapshot", snapshot_f, 1, 1 },
330 [OP_SPLICE] = {"splice", splice_f, 1, 1 },
331 [OP_STAT] = {"stat", stat_f, 1, 0 },
332 [OP_SUBVOL_CREATE] = {"subvol_create", subvol_create_f, 1, 1 },
333 [OP_SUBVOL_DELETE] = {"subvol_delete", subvol_delete_f, 1, 1 },
334 [OP_SYMLINK] = {"symlink", symlink_f, 2, 1 },
335 [OP_SYNC] = {"sync", sync_f, 1, 1 },
336 [OP_TRUNCATE] = {"truncate", truncate_f, 2, 1 },
337 [OP_UNLINK] = {"unlink", unlink_f, 1, 1 },
338 [OP_UNRESVSP] = {"unresvsp", unresvsp_f, 1, 1 },
339 [OP_URING_READ] = {"uring_read", uring_read_f, 1, 0 },
340 [OP_URING_WRITE] = {"uring_write", uring_write_f, 1, 1 },
341 [OP_WRITE] = {"write", write_f, 4, 1 },
342 [OP_WRITEV] = {"writev", writev_f, 4, 1 },
345 flist_t flist[FT_nft] = {
359 struct xfs_fsop_geom geom;
369 opnum_t operations = 1;
370 unsigned int idmodulo = XFS_IDMODULO_MAX;
371 unsigned int attr_mask = ~0;
374 unsigned long seed = 0;
378 int verifiable_log = 0;
379 sig_atomic_t should_stop = 0;
380 sigjmp_buf *sigbus_jmp = NULL;
381 char *execute_cmd = NULL;
382 int execute_freq = 1;
383 struct print_string flag_str = {0};
385 void add_to_flist(int, int, int, int);
386 void append_pathname(pathname_t *, char *);
387 int attr_list_path(pathname_t *, char *, const int);
388 int attr_remove_path(pathname_t *, const char *);
389 int attr_set_path(pathname_t *, const char *, const char *, const int);
390 void check_cwd(void);
391 void cleanup_flist(void);
392 int creat_path(pathname_t *, mode_t);
393 void dcache_enter(int, int);
394 void dcache_init(void);
395 fent_t *dcache_lookup(int);
396 void dcache_purge(int, int);
397 void del_from_flist(int, int);
398 int dirid_to_name(char *, int);
400 int fent_to_name(pathname_t *, fent_t *);
401 bool fents_ancestor_check(fent_t *, fent_t *);
402 void fix_parent(int, int, bool);
403 void free_pathname(pathname_t *);
404 int generate_fname(fent_t *, int, pathname_t *, int *, int *);
405 int generate_xattr_name(int, char *, int);
406 int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
407 void init_pathname(pathname_t *);
408 int lchown_path(pathname_t *, uid_t, gid_t);
409 int link_path(pathname_t *, pathname_t *);
410 int lstat64_path(pathname_t *, struct stat64 *);
411 void make_freq_table(void);
412 int mkdir_path(pathname_t *, mode_t);
413 int mknod_path(pathname_t *, mode_t, dev_t);
414 void namerandpad(int, char *, int);
415 int open_file_or_dir(pathname_t *, int);
416 int open_path(pathname_t *, int);
417 DIR *opendir_path(pathname_t *);
418 void process_freq(char *);
419 int readlink_path(pathname_t *, char *, size_t);
420 int rename_path(pathname_t *, pathname_t *, int);
421 int rmdir_path(pathname_t *);
422 void separate_pathname(pathname_t *, char *, pathname_t *);
423 void show_ops(int, char *);
424 int stat64_path(pathname_t *, struct stat64 *);
425 int symlink_path(const char *, pathname_t *);
426 int truncate64_path(pathname_t *, off64_t);
427 int unlink_path(pathname_t *);
429 void write_freq(void);
430 void zero_freq(void);
431 void non_btrfs_freq(const char *);
433 void sg_handler(int signum)
441 * Only handle SIGBUS when mmap write to a hole and no
442 * block can be allocated due to ENOSPC, abort otherwise.
445 siglongjmp(*sigbus_jmp, -1);
447 printf("Unknown SIGBUS is caught, Abort!\n");
450 /* should not reach here */
457 int main(int argc, char **argv)
461 char *dirname = NULL;
462 char *logname = NULL;
463 char rpath[PATH_MAX];
472 xfs_error_injection_t err_inj;
473 struct sigaction action;
475 const char *allopts = "cd:e:f:i:l:m:M:n:o:p:rs:S:vVwx:X:zH";
477 errrange = errtag = 0;
479 nops = sizeof(ops) / sizeof(ops[0]);
480 ops_end = &ops[nops];
482 while ((c = getopt(argc, argv, allopts)) != -1) {
491 sscanf(optarg, "%d", &errtag);
495 } else if (errtag == 0)
497 if (errtag >= XFS_ERRTAG_MAX) {
499 "error tag %d too large (max %d)\n",
500 errtag, XFS_ERRTAG_MAX - 1);
505 process_freq(optarg);
508 ilist = realloc(ilist, ++ilistlen * sizeof(*ilist));
509 ilist[ilistlen - 1] = strtol(optarg, &p, 16);
512 idmodulo = strtoul(optarg, NULL, 0);
513 if (idmodulo > XFS_IDMODULO_MAX) {
515 "chown modulo %d too big (max %d)\n",
516 idmodulo, XFS_IDMODULO_MAX);
521 loops = atoi(optarg);
525 operations = strtoll(optarg, NULL, 0);
536 nproc = atoi(optarg);
542 seed = strtoul(optarg, NULL, 0);
551 execute_cmd = optarg;
557 attr_mask = strtoul(optarg, NULL, 0);
561 if (optarg[0] == 'c')
572 execute_freq = strtoul(optarg, NULL, 0);
575 fprintf(stderr, "%s - invalid parameters\n",
585 /* no directory specified */
586 if (!nousage) usage();
590 non_btrfs_freq(dirname);
591 (void)mkdir(dirname, 0777);
592 if (logname && logname[0] != '/') {
593 if (!getcwd(rpath, sizeof(rpath))){
594 perror("getcwd failed");
600 if (chdir(dirname) < 0) {
605 char path[PATH_MAX + NAME_MAX + 1];
606 snprintf(path, sizeof(path), "%s/%s", rpath, logname);
607 if (freopen(path, "a", stdout) == NULL) {
608 perror("freopen logfile failed");
612 sprintf(buf, "fss%x", (unsigned int)getpid());
613 fd = creat(buf, 0666);
614 if (lseek64(fd, (off64_t)(MAXFSIZE32 + 1ULL), SEEK_SET) < 0)
615 maxfsize = (off64_t)MAXFSIZE32;
617 maxfsize = (off64_t)MAXFSIZE;
622 gettimeofday(&t, (void *)NULL);
623 seed = (int)t.tv_sec ^ (int)t.tv_usec;
624 printf("seed = %ld\n", seed);
626 i = xfsctl(buf, fd, XFS_IOC_FSGEOMETRY, &geom);
627 if (i >= 0 && geom.rtblocks)
628 rtpct = MIN(MAX(geom.rtblocks * 100 /
629 (geom.rtblocks + geom.datablocks), 1), 99);
638 for (i = 0; i < j; i++)
641 errtag = (random() % (XFS_ERRTAG_MAX-1)) + 1;
647 for (i = 0; i < j; i++)
650 errtag += (random() % (XFS_ERRTAG_MAX - errtag));
652 printf("Injecting failure on tag #%d\n", errtag);
653 err_inj.errtag = errtag;
655 srval = xfsctl(buf, fd, XFS_IOC_ERROR_INJECTION, &err_inj);
657 perror("fsstress - XFS_SYSSGI error injection call");
666 action.sa_handler = sg_handler;
667 sigemptyset(&action.sa_mask);
669 if (sigaction(SIGTERM, &action, 0)) {
670 perror("sigaction failed");
674 for (i = 0; i < nproc; i++) {
676 sigemptyset(&action.sa_mask);
677 action.sa_handler = SIG_DFL;
678 if (sigaction(SIGTERM, &action, 0))
680 action.sa_handler = sg_handler;
681 if (sigaction(SIGBUS, &action, 0))
683 #ifdef HAVE_SYS_PRCTL_H
684 prctl(PR_SET_PDEATHSIG, SIGKILL);
685 if (getppid() == 1) /* parent died already? */
689 char path[PATH_MAX + NAME_MAX + 2 + 11];
690 snprintf(path, sizeof(path), "%s/%s.%d",
692 if (freopen(path, "a", stdout) == NULL) {
693 perror("freopen logfile failed");
699 if (io_setup(AIO_ENTRIES, &io_ctx) != 0) {
700 fprintf(stderr, "io_setup failed\n");
705 have_io_uring = true;
706 /* If ENOSYS, just ignore uring, other errors are fatal. */
707 if (io_uring_queue_init(URING_ENTRIES, &ring, 0)) {
708 if (errno == ENOSYS) {
709 have_io_uring = false;
711 fprintf(stderr, "io_uring_queue_init failed\n");
716 for (i = 0; !loops || (i < loops); i++)
719 if(io_destroy(io_ctx) != 0) {
720 fprintf(stderr, "io_destroy failed");
726 io_uring_queue_exit(&ring);
733 while (wait(&stat) > 0 && !should_stop) {
736 action.sa_flags = SA_RESTART;
737 sigaction(SIGTERM, &action, 0);
738 kill(-getpid(), SIGTERM);
739 while (wait(&stat) > 0)
745 srval = xfsctl(buf, fd, XFS_IOC_ERROR_CLEARALL, &err_inj);
747 fprintf(stderr, "Bad ej clear on %s fd=%d (%d).\n",
749 perror("xfsctl(XFS_IOC_ERROR_CLEARALL)");
762 add_string(struct print_string *str, const char *add)
764 int len = strlen(add);
769 if (len > (str->max - 1) - str->len) {
770 str->len = str->max - 1;
774 memcpy(str->buffer + str->len, add, len);
776 str->buffer[str->len] = '\0';
782 translate_flags(int flags, const char *delim,
783 const struct print_flags *flag_array)
785 int i, mask, first = 1;
788 if (!flag_str.buffer) {
789 flag_str.buffer = malloc(4096);
793 if (!flag_str.buffer)
796 flag_str.buffer[0] = '\0';
798 for (i = 0; flag_array[i].name && flags; i++) {
799 mask = flag_array[i].mask;
800 if ((flags & mask) != mask)
803 add = flag_array[i].name;
806 add_string(&flag_str, delim);
809 add_string(&flag_str, add);
812 /* Check whether there are any leftover flags. */
818 add_string(&flag_str, delim);
820 ret = snprintf(number, 11, "0x%x", flags) > 0;
821 if (ret > 0 && ret <= 11)
822 add_string(&flag_str, number);
825 return flag_str.buffer;
829 add_to_flist(int ft, int id, int parent, int xattr_counter)
835 if (ftp->nfiles == ftp->nslots) {
836 ftp->nslots += FLIST_SLOT_INCR;
837 ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t));
839 fep = &ftp->fents[ftp->nfiles++];
842 fep->parent = parent;
843 fep->xattr_counter = xattr_counter;
847 append_pathname(pathname_t *name, char *str)
853 /* attempting to append to a dir a zero length path */
854 if (len && *str == '/' && name->len == 0) {
855 fprintf(stderr, "fsstress: append_pathname failure\n");
856 assert(chdir(homedir) == 0);
861 name->path = realloc(name->path, name->len + 1 + len);
862 strcpy(&name->path[name->len], str);
867 attr_list_count(char *buffer, int buffersize)
870 char *end = buffer + buffersize;
873 while (p < end && *p != 0) {
882 attr_list_path(pathname_t *name,
884 const int buffersize)
886 char buf[NAME_MAX + 1];
890 rval = llistxattr(name->path, buffer, buffersize);
891 if (rval >= 0 || errno != ENAMETOOLONG)
893 separate_pathname(name, buf, &newname);
894 if (chdir(buf) == 0) {
895 rval = attr_list_path(&newname, buffer, buffersize);
896 assert(chdir("..") == 0);
898 free_pathname(&newname);
903 attr_remove_path(pathname_t *name, const char *attrname)
905 char buf[NAME_MAX + 1];
909 rval = lremovexattr(name->path, attrname);
910 if (rval >= 0 || errno != ENAMETOOLONG)
912 separate_pathname(name, buf, &newname);
913 if (chdir(buf) == 0) {
914 rval = attr_remove_path(&newname, attrname);
915 assert(chdir("..") == 0);
917 free_pathname(&newname);
922 attr_set_path(pathname_t *name, const char *attrname, const char *attrvalue,
923 const int valuelength)
925 char buf[NAME_MAX + 1];
929 rval = lsetxattr(name->path, attrname, attrvalue, valuelength, 0);
930 if (rval >= 0 || errno != ENAMETOOLONG)
932 separate_pathname(name, buf, &newname);
933 if (chdir(buf) == 0) {
934 rval = attr_set_path(&newname, attrname, attrvalue,
936 assert(chdir("..") == 0);
938 free_pathname(&newname);
946 struct stat64 statbuf;
949 ret = stat64(".", &statbuf);
951 fprintf(stderr, "fsstress: check_cwd stat64() returned %d with errno: %d (%s)\n",
952 ret, errno, strerror(errno));
956 if (statbuf.st_ino == top_ino)
959 fprintf(stderr, "fsstress: check_cwd statbuf.st_ino (%llu) != top_ino (%llu)\n",
960 (unsigned long long) statbuf.st_ino,
961 (unsigned long long) top_ino);
963 assert(chdir(homedir) == 0);
964 fprintf(stderr, "fsstress: check_cwd failure\n");
971 * go thru flist and release all entries
973 * NOTE: this function shouldn't be called until the end of a process
981 for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
990 creat_path(pathname_t *name, mode_t mode)
992 char buf[NAME_MAX + 1];
996 rval = creat(name->path, mode);
997 if (rval >= 0 || errno != ENAMETOOLONG)
999 separate_pathname(name, buf, &newname);
1000 if (chdir(buf) == 0) {
1001 rval = creat_path(&newname, mode);
1002 assert(chdir("..") == 0);
1004 free_pathname(&newname);
1009 dcache_enter(int dirid, int slot)
1011 dcache[dirid % NDCACHE] = slot;
1019 for (i = 0; i < NDCACHE; i++)
1024 dcache_lookup(int dirid)
1029 i = dcache[dirid % NDCACHE];
1030 if (i >= 0 && i < flist[FT_DIR].nfiles &&
1031 (fep = &flist[FT_DIR].fents[i])->id == dirid)
1033 if (i >= 0 && i < flist[FT_SUBVOL].nfiles &&
1034 (fep = &flist[FT_SUBVOL].fents[i])->id == dirid)
1040 dcache_purge(int dirid, int ft)
1043 dcp = &dcache[dirid % NDCACHE];
1044 if (*dcp >= 0 && *dcp < flist[ft].nfiles &&
1045 flist[ft].fents[*dcp].id == dirid)
1050 * Delete the item from the list by
1051 * moving last entry over the deleted one;
1052 * unless deleted entry is the last one.
1053 * Input: which file list array and which slot in array
1056 del_from_flist(int ft, int slot)
1061 if (ft == FT_DIR || ft == FT_SUBVOL)
1062 dcache_purge(ftp->fents[slot].id, ft);
1063 if (slot != ftp->nfiles - 1) {
1064 if (ft == FT_DIR || ft == FT_SUBVOL)
1065 dcache_purge(ftp->fents[ftp->nfiles - 1].id, ft);
1066 ftp->fents[slot] = ftp->fents[--ftp->nfiles];
1072 delete_subvol_children(int parid)
1077 for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1079 for (c = 0; c < flp->nfiles; c++) {
1080 if (flp->fents[c].parent == parid) {
1081 int id = flp->fents[c].id;
1082 del_from_flist(i, c);
1083 if (i == FT_DIR || i == FT_SUBVOL)
1084 delete_subvol_children(id);
1092 dirid_to_fent(int dirid)
1099 if ((fep = dcache_lookup(dirid)))
1103 for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
1104 if (fep->id == dirid) {
1105 dcache_enter(dirid, fep - flp->fents);
1119 struct stat64 statbuf;
1127 dividend = (operations + execute_freq) / (execute_freq + 1);
1128 sprintf(buf, "p%x", procid);
1129 (void)mkdir(buf, 0777);
1130 if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) {
1134 top_ino = statbuf.st_ino;
1135 homedir = getcwd(NULL, 0);
1137 perror("getcwd failed");
1143 namerand = random();
1144 for (opno = 0; opno < operations; opno++) {
1145 if (execute_cmd && opno && opno % dividend == 0) {
1147 printf("%lld: execute command %s\n", opno,
1149 rval = system(execute_cmd);
1151 fprintf(stderr, "execute command failed with "
1154 p = &ops[freq_table[random() % freq_table_size]];
1155 p->func(opno, random());
1157 * test for forced shutdown by stat'ing the test
1158 * directory. If this stat returns EIO, assume
1159 * the forced shutdown happened.
1161 if (errtag != 0 && opno % 100 == 0) {
1162 rval = stat64(".", &statbuf);
1164 fprintf(stderr, "Detected EIO\n");
1170 assert(chdir("..") == 0);
1175 sprintf(cmd, "rm -rf %s", buf);
1178 perror("cleaning up");
1184 * build up a pathname going thru the file entry and all
1185 * its parent entries
1186 * Return 0 on error, 1 on success;
1189 fent_to_name(pathname_t *name, fent_t *fep)
1191 flist_t *flp = &flist[fep->ft];
1192 char buf[NAME_MAX + 1];
1200 /* build up parent directory name */
1201 if (fep->parent != -1) {
1202 pfep = dirid_to_fent(fep->parent);
1205 fprintf(stderr, "%d: fent-id = %d: can't find parent id: %d\n",
1206 procid, fep->id, fep->parent);
1211 e = fent_to_name(name, pfep);
1214 append_pathname(name, "/");
1217 i = sprintf(buf, "%c%x", flp->tag, fep->id);
1218 namerandpad(fep->id, buf, i);
1219 append_pathname(name, buf);
1224 fents_ancestor_check(fent_t *fep, fent_t *dfep)
1228 for (tmpfep = fep; tmpfep->parent != -1;
1229 tmpfep = dirid_to_fent(tmpfep->parent)) {
1230 if (tmpfep->parent == dfep->id)
1238 fix_parent(int oldid, int newid, bool swap)
1245 for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1246 for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
1247 if (fep->parent == oldid)
1248 fep->parent = newid;
1249 else if (swap && fep->parent == newid)
1250 fep->parent = oldid;
1256 free_pathname(pathname_t *name)
1266 * Generate a filename of type ft.
1267 * If we have a fep which should be a directory then use it
1268 * as the parent path for this new filename i.e. prepend with it.
1271 generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
1273 char buf[NAME_MAX + 1];
1282 len = sprintf(buf, "%c%x", flp->tag, id = nameseq++);
1283 namerandpad(id, buf, len);
1285 /* prepend fep parent dir-name to it */
1287 e = fent_to_name(name, fep);
1290 append_pathname(name, "/");
1292 append_pathname(name, buf);
1296 for (j = 0; !*v && j < ilistlen; j++) {
1297 if (ilist[j] == id) {
1305 int generate_xattr_name(int xattr_num, char *buffer, int buflen)
1309 ret = snprintf(buffer, buflen, "user.x%d", xattr_num);
1319 * Input: "which" to choose the file-types eg. non-directory
1320 * Input: "r" to choose which file
1321 * Output: file-list, file-entry, name for the chosen file.
1322 * Output: verbose if chosen file is on the ilist.
1325 get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
1328 int totalsum = 0; /* total number of matching files */
1329 int partialsum = 0; /* partial sum of matching files */
1335 int e = 1; /* success */
1338 * go thru flist and add up number of files for each
1339 * category that matches with <which>.
1341 for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1342 if (which & (1 << i))
1343 totalsum += flp->nfiles;
1345 if (totalsum == 0) {
1355 * Now we have possible matches between 0..totalsum-1.
1356 * And we use r to help us choose which one we want,
1357 * which when bounded by totalsum becomes x.
1359 x = (int)(r % totalsum);
1360 for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
1361 if (which & (1 << i)) {
1362 if (x < partialsum + flp->nfiles) {
1364 /* found the matching file entry */
1365 fep = &flp->fents[x - partialsum];
1367 /* fill-in what we were asked for */
1369 e = fent_to_name(name, fep);
1372 fprintf(stderr, "%d: failed to get path for entry:"
1373 " id=%d,parent=%d\n",
1374 procid, fep->id, fep->parent);
1383 /* turn on verbose if its an ilisted file */
1385 for (j = 0; !*v && j < ilistlen; j++) {
1386 if (ilist[j] == fep->id) {
1393 partialsum += flp->nfiles;
1397 fprintf(stderr, "fsstress: get_fname failure\n");
1404 init_pathname(pathname_t *name)
1411 lchown_path(pathname_t *name, uid_t owner, gid_t group)
1413 char buf[NAME_MAX + 1];
1417 rval = lchown(name->path, owner, group);
1418 if (rval >= 0 || errno != ENAMETOOLONG)
1420 separate_pathname(name, buf, &newname);
1421 if (chdir(buf) == 0) {
1422 rval = lchown_path(&newname, owner, group);
1423 assert(chdir("..") == 0);
1425 free_pathname(&newname);
1430 link_path(pathname_t *name1, pathname_t *name2)
1432 char buf1[NAME_MAX + 1];
1433 char buf2[NAME_MAX + 1];
1435 pathname_t newname1;
1436 pathname_t newname2;
1439 rval = link(name1->path, name2->path);
1440 if (rval >= 0 || errno != ENAMETOOLONG)
1442 separate_pathname(name1, buf1, &newname1);
1443 separate_pathname(name2, buf2, &newname2);
1444 if (strcmp(buf1, buf2) == 0) {
1445 if (chdir(buf1) == 0) {
1446 rval = link_path(&newname1, &newname2);
1447 assert(chdir("..") == 0);
1450 if (strcmp(buf1, "..") == 0)
1452 else if (strcmp(buf2, "..") == 0)
1454 else if (strlen(buf1) == 0)
1456 else if (strlen(buf2) == 0)
1459 down1 = MAX(newname1.len, 3 + name2->len) <=
1460 MAX(3 + name1->len, newname2.len);
1462 free_pathname(&newname2);
1463 append_pathname(&newname2, "../");
1464 append_pathname(&newname2, name2->path);
1465 if (chdir(buf1) == 0) {
1466 rval = link_path(&newname1, &newname2);
1467 assert(chdir("..") == 0);
1470 free_pathname(&newname1);
1471 append_pathname(&newname1, "../");
1472 append_pathname(&newname1, name1->path);
1473 if (chdir(buf2) == 0) {
1474 rval = link_path(&newname1, &newname2);
1475 assert(chdir("..") == 0);
1479 free_pathname(&newname1);
1480 free_pathname(&newname2);
1485 lstat64_path(pathname_t *name, struct stat64 *sbuf)
1487 char buf[NAME_MAX + 1];
1491 rval = lstat64(name->path, sbuf);
1492 if (rval >= 0 || errno != ENAMETOOLONG)
1494 separate_pathname(name, buf, &newname);
1495 if (chdir(buf) == 0) {
1496 rval = lstat64_path(&newname, sbuf);
1497 assert(chdir("..") == 0);
1499 free_pathname(&newname);
1504 make_freq_table(void)
1510 for (p = ops, f = 0; p < ops_end; p++)
1512 freq_table = malloc(f * sizeof(*freq_table));
1513 freq_table_size = f;
1514 for (p = ops, i = 0; p < ops_end; p++) {
1515 for (f = 0; f < p->freq; f++, i++)
1516 freq_table[i] = p - ops;
1521 mkdir_path(pathname_t *name, mode_t mode)
1523 char buf[NAME_MAX + 1];
1527 rval = mkdir(name->path, mode);
1528 if (rval >= 0 || errno != ENAMETOOLONG)
1530 separate_pathname(name, buf, &newname);
1531 if (chdir(buf) == 0) {
1532 rval = mkdir_path(&newname, mode);
1533 assert(chdir("..") == 0);
1535 free_pathname(&newname);
1540 mknod_path(pathname_t *name, mode_t mode, dev_t dev)
1542 char buf[NAME_MAX + 1];
1546 rval = mknod(name->path, mode, dev);
1547 if (rval >= 0 || errno != ENAMETOOLONG)
1549 separate_pathname(name, buf, &newname);
1550 if (chdir(buf) == 0) {
1551 rval = mknod_path(&newname, mode, dev);
1552 assert(chdir("..") == 0);
1554 free_pathname(&newname);
1559 namerandpad(int id, char *buf, int i)
1562 static int buckets[] =
1563 { 2, 4, 8, 16, 32, 64, 128, NAME_MAX };
1569 bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0]));
1570 padmod = buckets[bucket] + 1 - i;
1573 padlen = (id ^ namerand) % padmod;
1575 memset(&buf[i], 'X', padlen);
1576 buf[i + padlen] = '\0';
1581 open_file_or_dir(pathname_t *name, int flags)
1585 fd = open_path(name, flags);
1588 if (fd == -1 && errno != EISDIR)
1590 /* Directories can not be opened in write mode nor direct mode. */
1591 flags &= ~(O_WRONLY | O_DIRECT);
1592 flags |= O_RDONLY | O_DIRECTORY;
1593 return open_path(name, flags);
1597 open_path(pathname_t *name, int oflag)
1599 char buf[NAME_MAX + 1];
1603 rval = open(name->path, oflag);
1604 if (rval >= 0 || errno != ENAMETOOLONG)
1606 separate_pathname(name, buf, &newname);
1607 if (chdir(buf) == 0) {
1608 rval = open_path(&newname, oflag);
1609 assert(chdir("..") == 0);
1611 free_pathname(&newname);
1616 opendir_path(pathname_t *name)
1618 char buf[NAME_MAX + 1];
1622 rval = opendir(name->path);
1623 if (rval || errno != ENAMETOOLONG)
1625 separate_pathname(name, buf, &newname);
1626 if (chdir(buf) == 0) {
1627 rval = opendir_path(&newname);
1628 assert(chdir("..") == 0);
1630 free_pathname(&newname);
1635 process_freq(char *arg)
1640 s = strchr(arg, '=');
1642 fprintf(stderr, "bad argument '%s'\n", arg);
1646 for (p = ops; p < ops_end; p++) {
1647 if (strcmp(arg, p->name) == 0) {
1652 fprintf(stderr, "can't find op type %s for -f\n", arg);
1657 readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz)
1659 char buf[NAME_MAX + 1];
1663 rval = readlink(name->path, lbuf, lbufsiz);
1664 if (rval >= 0 || errno != ENAMETOOLONG)
1666 separate_pathname(name, buf, &newname);
1667 if (chdir(buf) == 0) {
1668 rval = readlink_path(&newname, lbuf, lbufsiz);
1669 assert(chdir("..") == 0);
1671 free_pathname(&newname);
1676 rename_path(pathname_t *name1, pathname_t *name2, int mode)
1678 char buf1[NAME_MAX + 1];
1679 char buf2[NAME_MAX + 1];
1681 pathname_t newname1;
1682 pathname_t newname2;
1686 rval = rename(name1->path, name2->path);
1688 rval = renameat2(AT_FDCWD, name1->path,
1689 AT_FDCWD, name2->path, mode);
1690 if (rval >= 0 || errno != ENAMETOOLONG)
1692 separate_pathname(name1, buf1, &newname1);
1693 separate_pathname(name2, buf2, &newname2);
1694 if (strcmp(buf1, buf2) == 0) {
1695 if (chdir(buf1) == 0) {
1696 rval = rename_path(&newname1, &newname2, mode);
1697 assert(chdir("..") == 0);
1700 if (strcmp(buf1, "..") == 0)
1702 else if (strcmp(buf2, "..") == 0)
1704 else if (strlen(buf1) == 0)
1706 else if (strlen(buf2) == 0)
1709 down1 = MAX(newname1.len, 3 + name2->len) <=
1710 MAX(3 + name1->len, newname2.len);
1712 free_pathname(&newname2);
1713 append_pathname(&newname2, "../");
1714 append_pathname(&newname2, name2->path);
1715 if (chdir(buf1) == 0) {
1716 rval = rename_path(&newname1, &newname2, mode);
1717 assert(chdir("..") == 0);
1720 free_pathname(&newname1);
1721 append_pathname(&newname1, "../");
1722 append_pathname(&newname1, name1->path);
1723 if (chdir(buf2) == 0) {
1724 rval = rename_path(&newname1, &newname2, mode);
1725 assert(chdir("..") == 0);
1729 free_pathname(&newname1);
1730 free_pathname(&newname2);
1735 rmdir_path(pathname_t *name)
1737 char buf[NAME_MAX + 1];
1741 rval = rmdir(name->path);
1742 if (rval >= 0 || errno != ENAMETOOLONG)
1744 separate_pathname(name, buf, &newname);
1745 if (chdir(buf) == 0) {
1746 rval = rmdir_path(&newname);
1747 assert(chdir("..") == 0);
1749 free_pathname(&newname);
1754 separate_pathname(pathname_t *name, char *buf, pathname_t *newname)
1758 init_pathname(newname);
1759 slash = strchr(name->path, '/');
1760 if (slash == NULL) {
1765 strcpy(buf, name->path);
1767 append_pathname(newname, slash + 1);
1773 show_ops(int flag, char *lead_str)
1778 /* print in list form */
1781 for (p = ops; p < ops_end; p++) {
1782 if (lead_str != NULL && x+strlen(p->name)>=WIDTH-5)
1783 x=printf("%s%s", (p==ops)?"":"\n", lead_str);
1784 x+=printf("%s ", p->name);
1787 } else if (flag == 0) {
1788 /* Table view style */
1790 for (f = 0, p = ops; p < ops_end; p++)
1796 for (p = ops; p < ops_end; p++) {
1797 if (flag != 0 || p->freq > 0) {
1798 if (lead_str != NULL)
1799 printf("%s", lead_str);
1800 printf("%20s %d/%d %s\n",
1801 p->name, p->freq, f,
1802 (p->iswrite == 0) ? " " : "write op");
1806 /* Command line style */
1807 if (lead_str != NULL)
1808 printf("%s", lead_str);
1809 printf ("-z -s %ld -m %d -n %lld -p %d \\\n", seed, idmodulo,
1811 for (p = ops; p < ops_end; p++)
1813 printf("-f %s=%d \\\n",p->name, p->freq);
1818 stat64_path(pathname_t *name, struct stat64 *sbuf)
1820 char buf[NAME_MAX + 1];
1824 rval = stat64(name->path, sbuf);
1825 if (rval >= 0 || errno != ENAMETOOLONG)
1827 separate_pathname(name, buf, &newname);
1828 if (chdir(buf) == 0) {
1829 rval = stat64_path(&newname, sbuf);
1830 assert(chdir("..") == 0);
1832 free_pathname(&newname);
1837 symlink_path(const char *name1, pathname_t *name)
1839 char buf[NAME_MAX + 1];
1843 if (!strcmp(name1, name->path)) {
1844 printf("yikes! %s %s\n", name1, name->path);
1848 rval = symlink(name1, name->path);
1849 if (rval >= 0 || errno != ENAMETOOLONG)
1851 separate_pathname(name, buf, &newname);
1852 if (chdir(buf) == 0) {
1853 rval = symlink_path(name1, &newname);
1854 assert(chdir("..") == 0);
1856 free_pathname(&newname);
1861 truncate64_path(pathname_t *name, off64_t length)
1863 char buf[NAME_MAX + 1];
1867 rval = truncate64(name->path, length);
1868 if (rval >= 0 || errno != ENAMETOOLONG)
1870 separate_pathname(name, buf, &newname);
1871 if (chdir(buf) == 0) {
1872 rval = truncate64_path(&newname, length);
1873 assert(chdir("..") == 0);
1875 free_pathname(&newname);
1880 unlink_path(pathname_t *name)
1882 char buf[NAME_MAX + 1];
1886 rval = unlink(name->path);
1887 if (rval >= 0 || errno != ENAMETOOLONG)
1889 separate_pathname(name, buf, &newname);
1890 if (chdir(buf) == 0) {
1891 rval = unlink_path(&newname);
1892 assert(chdir("..") == 0);
1894 free_pathname(&newname);
1901 printf("Usage: %s -H or\n", myprog);
1902 printf(" %s [-c][-d dir][-e errtg][-f op_name=freq][-l loops][-n nops]\n",
1904 printf(" [-p nproc][-r len][-s seed][-v][-w][-x cmd][-z][-S][-X ncmd]\n");
1906 printf(" -c clean up the test directory after each run\n");
1907 printf(" -d dir specifies the base directory for operations\n");
1908 printf(" -e errtg specifies error injection stuff\n");
1909 printf(" -f op_name=freq changes the frequency of option name to freq\n");
1910 printf(" the valid operation names are:\n");
1912 printf(" -i filenum get verbose output for this nth file object\n");
1913 printf(" -l loops specifies the no. of times the testrun should loop.\n");
1914 printf(" *use 0 for infinite (default 1)\n");
1915 printf(" -m modulo uid/gid modulo for chown/chgrp (default 32)\n");
1916 printf(" -n nops specifies the no. of operations per process (default 1)\n");
1917 printf(" -o logfile specifies logfile name\n");
1918 printf(" -p nproc specifies the no. of processes (default 1)\n");
1919 printf(" -r specifies random name padding\n");
1920 printf(" -s seed specifies the seed for the random generator (default random)\n");
1921 printf(" -v specifies verbose mode\n");
1922 printf(" -w zeros frequencies of non-write operations\n");
1923 printf(" -x cmd execute command in the middle of operations\n");
1924 printf(" -z zeros frequencies of all operations\n");
1925 printf(" -S [c,t] prints the list of operations (omitting zero frequency) in command line or table style\n");
1926 printf(" -V specifies verifiable logging mode (omitting inode numbers)\n");
1927 printf(" -X ncmd number of calls to the -x command (default 1)\n");
1928 printf(" -H prints usage and exits\n");
1936 for (p = ops; p < ops_end; p++) {
1947 for (p = ops; p < ops_end; p++)
1951 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
1953 opty_t btrfs_ops[] = {
1960 non_btrfs_freq(const char *path)
1963 #ifdef HAVE_BTRFSUTIL_H
1964 enum btrfs_util_error e;
1966 e = btrfs_util_is_subvolume(path);
1967 if (e != BTRFS_UTIL_ERROR_NOT_BTRFS)
1970 for (i = 0; i < ARRAY_SIZE(btrfs_ops); i++)
1971 ops[btrfs_ops[i]].freq = 0;
1974 void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
1977 snprintf(str, sz, "[%ld %ld %d %d %lld %lld]",
1978 verifiable_log ? -1: (long)s->st_ino,
1979 (long)s->st_nlink, s->st_uid, s->st_gid,
1980 (long long) s->st_blocks, (long long) s->st_size);
1984 afsync_f(opnum_t opno, long r)
1992 struct iocb *iocbs[] = { &iocb };
1993 struct io_event event;
1996 if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, NULL, &v)) {
1998 printf("%d/%lld: afsync - no filename\n", procid, opno);
2002 fd = open_file_or_dir(&f, O_WRONLY | O_DIRECT);
2003 e = fd < 0 ? errno : 0;
2007 printf("%d/%lld: afsync - open %s failed %d\n",
2008 procid, opno, f.path, e);
2013 io_prep_fsync(&iocb, fd);
2014 if ((e = io_submit(io_ctx, 1, iocbs)) != 1) {
2016 printf("%d/%lld: afsync - io_submit %s %d\n",
2017 procid, opno, f.path, e);
2022 if ((e = io_getevents(io_ctx, 1, 1, &event, NULL)) != 1) {
2024 printf("%d/%lld: afsync - io_getevents failed %d\n",
2033 printf("%d/%lld: afsync %s %d\n", procid, opno, f.path, e);
2041 do_aio_rw(opnum_t opno, long r, int flags)
2045 struct dioattr diob;
2057 struct io_event event;
2058 struct iocb *iocbs[] = { &iocb };
2059 int iswrite = (flags & (O_WRONLY | O_RDWR)) ? 1 : 0;
2062 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2064 printf("%d/%lld: do_aio_rw - no filename\n", procid, opno);
2067 fd = open_path(&f, flags|O_DIRECT);
2068 e = fd < 0 ? errno : 0;
2072 printf("%d/%lld: do_aio_rw - open %s failed %d\n",
2073 procid, opno, f.path, e);
2076 if (fstat64(fd, &stb) < 0) {
2078 printf("%d/%lld: do_aio_rw - fstat64 %s failed %d\n",
2079 procid, opno, f.path, errno);
2082 inode_info(st, sizeof(st), &stb, v);
2083 if (!iswrite && stb.st_size == 0) {
2085 printf("%d/%lld: do_aio_rw - %s%s zero size\n", procid, opno,
2089 if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
2092 "%d/%lld: do_aio_rw - xfsctl(XFS_IOC_DIOINFO) %s%s return %d,"
2093 " fallback to stat()\n",
2094 procid, opno, f.path, st, errno);
2095 diob.d_mem = diob.d_miniosz = stb.st_blksize;
2096 diob.d_maxiosz = rounddown_64(INT_MAX, diob.d_miniosz);
2098 dio_env = getenv("XFS_DIO_MIN");
2100 diob.d_mem = diob.d_miniosz = atoi(dio_env);
2101 align = (int64_t)diob.d_miniosz;
2102 lr = ((int64_t)random() << 32) + random();
2103 len = (random() % FILELEN_MAX) + 1;
2104 len -= (len % align);
2107 else if (len > diob.d_maxiosz)
2108 len = diob.d_maxiosz;
2109 buf = memalign(diob.d_mem, len);
2112 printf("%d/%lld: do_aio_rw - memalign failed\n",
2118 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2119 off -= (off % align);
2121 memset(buf, nameseq & 0xff, len);
2122 io_prep_pwrite(&iocb, fd, buf, len, off);
2124 off = (off64_t)(lr % stb.st_size);
2125 off -= (off % align);
2126 io_prep_pread(&iocb, fd, buf, len, off);
2128 if ((e = io_submit(io_ctx, 1, iocbs)) != 1) {
2130 printf("%d/%lld: %s - io_submit failed %d\n",
2131 procid, opno, iswrite ? "awrite" : "aread", e);
2134 if ((e = io_getevents(io_ctx, 1, 1, &event, NULL)) != 1) {
2136 printf("%d/%lld: %s - io_getevents failed %d\n",
2137 procid, opno, iswrite ? "awrite" : "aread", e);
2141 e = event.res != len ? event.res2 : 0;
2143 printf("%d/%lld: %s %s%s [%lld,%d] %d\n",
2144 procid, opno, iswrite ? "awrite" : "aread",
2145 f.path, st, (long long)off, (int)len, e);
2157 do_uring_rw(opnum_t opno, long r, int flags)
2169 struct io_uring_sqe *sqe;
2170 struct io_uring_cqe *cqe;
2172 int iswrite = (flags & (O_WRONLY | O_RDWR)) ? 1 : 0;
2178 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
2180 printf("%d/%lld: do_uring_rw - no filename\n", procid, opno);
2183 fd = open_path(&f, flags);
2184 e = fd < 0 ? errno : 0;
2188 printf("%d/%lld: do_uring_rw - open %s failed %d\n",
2189 procid, opno, f.path, e);
2192 if (fstat64(fd, &stb) < 0) {
2194 printf("%d/%lld: do_uring_rw - fstat64 %s failed %d\n",
2195 procid, opno, f.path, errno);
2198 inode_info(st, sizeof(st), &stb, v);
2199 if (!iswrite && stb.st_size == 0) {
2201 printf("%d/%lld: do_uring_rw - %s%s zero size\n", procid, opno,
2205 sqe = io_uring_get_sqe(&ring);
2208 printf("%d/%lld: do_uring_rw - io_uring_get_sqe failed\n",
2212 lr = ((int64_t)random() << 32) + random();
2213 len = (random() % FILELEN_MAX) + 1;
2217 printf("%d/%lld: do_uring_rw - malloc failed\n",
2221 iovec.iov_base = buf;
2222 iovec.iov_len = len;
2224 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
2226 memset(buf, nameseq & 0xff, len);
2227 io_uring_prep_writev(sqe, fd, &iovec, 1, off);
2229 off = (off64_t)(lr % stb.st_size);
2230 io_uring_prep_readv(sqe, fd, &iovec, 1, off);
2233 if ((e = io_uring_submit_and_wait(&ring, 1)) != 1) {
2235 printf("%d/%lld: %s - io_uring_submit failed %d\n", procid, opno,
2236 iswrite ? "uring_write" : "uring_read", e);
2239 if ((e = io_uring_wait_cqe(&ring, &cqe)) < 0) {
2241 printf("%d/%lld: %s - io_uring_wait_cqe failed %d\n", procid, opno,
2242 iswrite ? "uring_write" : "uring_read", e);
2246 printf("%d/%lld: %s %s%s [%lld, %d(res=%d)] %d\n",
2247 procid, opno, iswrite ? "uring_write" : "uring_read",
2248 f.path, st, (long long)off, (int)len, cqe->res, e);
2249 io_uring_cqe_seen(&ring, cqe);
2261 aread_f(opnum_t opno, long r)
2264 do_aio_rw(opno, r, O_RDONLY);
2269 attr_remove_f(opnum_t opno, long r)
2274 char buf[XATTR_LIST_MAX];
2283 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2284 append_pathname(&f, ".");
2285 e = attr_list_path(&f, buf, sizeof(buf));
2288 total = attr_list_count(buf, e);
2291 printf("%d/%lld: attr_remove - no attrs for %s\n",
2292 procid, opno, f.path);
2297 which = (int)(random() % total);
2301 while (bufname < bufend) {
2307 bufname += strlen(bufname) + 1;
2309 if (aname == NULL) {
2312 "%d/%lld: attr_remove - name %d not found at %s\n",
2313 procid, opno, which, f.path);
2317 if (attr_remove_path(&f, aname) < 0)
2323 printf("%d/%lld: attr_remove %s %s %d\n",
2324 procid, opno, f.path, aname, e);
2329 attr_set_f(opnum_t opno, long r)
2336 static int lengths[] = { 10, 100, 1000, 10000 };
2341 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2342 append_pathname(&f, ".");
2343 sprintf(aname, "a%x", nameseq++);
2344 li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0])));
2345 len = (int)(random() % lengths[li]);
2349 memset(aval, nameseq & 0xff, len);
2350 if (attr_set_path(&f, aname, aval, len) < 0)
2357 printf("%d/%lld: attr_set %s %s %d\n", procid, opno, f.path,
2363 awrite_f(opnum_t opno, long r)
2366 do_aio_rw(opno, r, O_WRONLY);
2371 bulkstat_f(opnum_t opno, long r)
2377 struct xfs_bstat *t;
2379 struct xfs_fsop_bulkreq bsr;
2382 nent = (r % 999) + 2;
2383 t = malloc(nent * sizeof(*t));
2384 fd = open(".", O_RDONLY);
2392 while (xfsctl(".", fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
2396 printf("%d/%lld: bulkstat nent %d total %lld\n",
2397 procid, opno, nent, (long long)total);
2402 bulkstat1_f(opnum_t opno, long r)
2412 struct xfs_fsop_bulkreq bsr;
2415 good = random() & 1;
2417 /* use an inode we know exists */
2419 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2420 append_pathname(&f, ".");
2421 ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino;
2426 * pick a random inode
2428 * note this can generate kernel warning messages
2429 * since bulkstat_one will read the disk block that
2430 * would contain a given inode even if that disk
2431 * block doesn't contain inodes.
2433 * this is detected later, but not until after the
2434 * warning is displayed.
2436 * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0"
2442 fd = open(".", O_RDONLY);
2448 e = xfsctl(".", fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
2450 printf("%d/%lld: bulkstat1 %s ino %lld %d\n",
2451 procid, opno, good?"real":"random",
2452 verifiable_log ? -1LL : (long long)ino, e);
2457 chown_f(opnum_t opno, long r)
2467 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
2468 append_pathname(&f, ".");
2469 u = (uid_t)random();
2470 g = (gid_t)random();
2471 nbits = (int)(random() % idmodulo);
2472 u &= (1 << nbits) - 1;
2473 g &= (1 << nbits) - 1;
2474 e = lchown_path(&f, u, g) < 0 ? errno : 0;
2477 printf("%d/%lld: chown %s %d/%d %d\n", procid, opno, f.path, (int)u, (int)g, e);
2481 /* reflink some arbitrary range of f1 to f2. */
2488 struct file_clone_range fcr;
2489 struct pathname fpath1;
2490 struct pathname fpath2;
2491 struct stat64 stat1;
2492 struct stat64 stat2;
2493 char inoinfo1[1024];
2494 char inoinfo2[1024];
2508 init_pathname(&fpath1);
2509 if (!get_fname(FT_REGm, r, &fpath1, NULL, NULL, &v1)) {
2511 printf("%d/%lld: clonerange read - no filename\n",
2516 init_pathname(&fpath2);
2517 if (!get_fname(FT_REGm, random(), &fpath2, NULL, NULL, &v2)) {
2519 printf("%d/%lld: clonerange write - no filename\n",
2525 fd1 = open_path(&fpath1, O_RDONLY);
2526 e = fd1 < 0 ? errno : 0;
2530 printf("%d/%lld: clonerange read - open %s failed %d\n",
2531 procid, opno, fpath1.path, e);
2535 fd2 = open_path(&fpath2, O_WRONLY);
2536 e = fd2 < 0 ? errno : 0;
2540 printf("%d/%lld: clonerange write - open %s failed %d\n",
2541 procid, opno, fpath2.path, e);
2545 /* Get file stats */
2546 if (fstat64(fd1, &stat1) < 0) {
2548 printf("%d/%lld: clonerange read - fstat64 %s failed %d\n",
2549 procid, opno, fpath1.path, errno);
2552 inode_info(inoinfo1, sizeof(inoinfo1), &stat1, v1);
2554 if (fstat64(fd2, &stat2) < 0) {
2556 printf("%d/%lld: clonerange write - fstat64 %s failed %d\n",
2557 procid, opno, fpath2.path, errno);
2560 inode_info(inoinfo2, sizeof(inoinfo2), &stat2, v2);
2562 /* Calculate offsets */
2563 len = (random() % FILELEN_MAX) + 1;
2564 len = rounddown_64(len, stat1.st_blksize);
2566 len = stat1.st_blksize;
2567 if (len > stat1.st_size)
2568 len = stat1.st_size;
2570 lr = ((int64_t)random() << 32) + random();
2571 if (stat1.st_size == len)
2574 off1 = (off64_t)(lr % MIN(stat1.st_size - len, MAXFSIZE));
2576 off1 = rounddown_64(off1, stat1.st_blksize);
2579 * If srcfile == destfile, randomly generate destination ranges
2580 * until we find one that doesn't overlap the source range.
2582 max_off2 = MIN(stat2.st_size + (1024ULL * stat2.st_blksize), MAXFSIZE);
2584 lr = ((int64_t)random() << 32) + random();
2585 off2 = (off64_t)(lr % max_off2);
2587 off2 = rounddown_64(off2, stat2.st_blksize);
2588 } while (stat1.st_ino == stat2.st_ino && llabs(off2 - off1) < len);
2590 /* Clone data blocks */
2592 fcr.src_offset = off1;
2593 fcr.src_length = len;
2594 fcr.dest_offset = off2;
2596 ret = ioctl(fd2, FICLONERANGE, &fcr);
2597 e = ret < 0 ? errno : 0;
2599 printf("%d/%lld: clonerange %s%s [%lld,%lld] -> %s%s [%lld,%lld]",
2601 fpath1.path, inoinfo1, (long long)off1, (long long)len,
2602 fpath2.path, inoinfo2, (long long)off2, (long long)len);
2605 printf(" error %d", e);
2614 free_pathname(&fpath2);
2616 free_pathname(&fpath1);
2620 /* copy some arbitrary range of f1 to f2. */
2626 #ifdef HAVE_COPY_FILE_RANGE
2627 struct pathname fpath1;
2628 struct pathname fpath2;
2629 struct stat64 stat1;
2630 struct stat64 stat2;
2631 char inoinfo1[1024];
2632 char inoinfo2[1024];
2650 init_pathname(&fpath1);
2651 if (!get_fname(FT_REGm, r, &fpath1, NULL, NULL, &v1)) {
2653 printf("%d/%lld: copyrange read - no filename\n",
2658 init_pathname(&fpath2);
2659 if (!get_fname(FT_REGm, random(), &fpath2, NULL, NULL, &v2)) {
2661 printf("%d/%lld: copyrange write - no filename\n",
2667 fd1 = open_path(&fpath1, O_RDONLY);
2668 e = fd1 < 0 ? errno : 0;
2672 printf("%d/%lld: copyrange read - open %s failed %d\n",
2673 procid, opno, fpath1.path, e);
2677 fd2 = open_path(&fpath2, O_WRONLY);
2678 e = fd2 < 0 ? errno : 0;
2682 printf("%d/%lld: copyrange write - open %s failed %d\n",
2683 procid, opno, fpath2.path, e);
2687 /* Get file stats */
2688 if (fstat64(fd1, &stat1) < 0) {
2690 printf("%d/%lld: copyrange read - fstat64 %s failed %d\n",
2691 procid, opno, fpath1.path, errno);
2694 inode_info(inoinfo1, sizeof(inoinfo1), &stat1, v1);
2696 if (fstat64(fd2, &stat2) < 0) {
2698 printf("%d/%lld: copyrange write - fstat64 %s failed %d\n",
2699 procid, opno, fpath2.path, errno);
2702 inode_info(inoinfo2, sizeof(inoinfo2), &stat2, v2);
2704 /* Calculate offsets */
2705 len = (random() % FILELEN_MAX) + 1;
2707 len = stat1.st_blksize;
2708 if (len > stat1.st_size)
2709 len = stat1.st_size;
2711 lr = ((int64_t)random() << 32) + random();
2712 if (stat1.st_size == len)
2715 off1 = (off64_t)(lr % MIN(stat1.st_size - len, MAXFSIZE));
2719 * If srcfile == destfile, randomly generate destination ranges
2720 * until we find one that doesn't overlap the source range.
2722 max_off2 = MIN(stat2.st_size + (1024ULL * stat2.st_blksize), MAXFSIZE);
2724 lr = ((int64_t)random() << 32) + random();
2725 off2 = (off64_t)(lr % max_off2);
2727 } while (stat1.st_ino == stat2.st_ino && llabs(off2 - off1) < len);
2730 * Since len, off1 and off2 will be changed later, preserve their
2738 ret = syscall(__NR_copy_file_range, fd1, &off1, fd2, &off2,
2741 if (errno != EAGAIN || tries++ >= 300)
2743 } else if (ret > len || ret == 0)
2748 e = ret < 0 ? errno : 0;
2750 printf("%d/%lld: copyrange %s%s [%lld,%lld] -> %s%s [%lld,%lld]",
2752 fpath1.path, inoinfo1,
2753 (long long)offset1, (long long)length,
2754 fpath2.path, inoinfo2,
2755 (long long)offset2, (long long)length);
2758 printf(" error %d", e);
2759 else if (len && ret > len)
2760 printf(" asked for %lld, copied %lld??\n",
2761 (long long)len, (long long)ret);
2770 free_pathname(&fpath2);
2772 free_pathname(&fpath1);
2776 /* dedupe some arbitrary range of f1 to f2...fn. */
2782 #ifdef FIDEDUPERANGE
2783 #define INFO_SZ 1024
2784 struct file_dedupe_range *fdr;
2785 struct pathname *fpath;
2786 struct stat64 *stat;
2798 if (flist[FT_REG].nfiles < 2)
2801 /* Pick somewhere between 2 and 128 files. */
2803 nr = random() % (flist[FT_REG].nfiles + 1);
2804 } while (nr < 2 || nr > 128);
2807 fdr = malloc(nr * sizeof(struct file_dedupe_range_info) +
2808 sizeof(struct file_dedupe_range));
2810 printf("%d/%lld: line %d error %d\n",
2811 procid, opno, __LINE__, errno);
2814 memset(fdr, 0, (nr * sizeof(struct file_dedupe_range_info) +
2815 sizeof(struct file_dedupe_range)));
2817 fpath = calloc(nr, sizeof(struct pathname));
2819 printf("%d/%lld: line %d error %d\n",
2820 procid, opno, __LINE__, errno);
2824 stat = calloc(nr, sizeof(struct stat64));
2826 printf("%d/%lld: line %d error %d\n",
2827 procid, opno, __LINE__, errno);
2831 info = calloc(nr, INFO_SZ);
2833 printf("%d/%lld: line %d error %d\n",
2834 procid, opno, __LINE__, errno);
2838 off = calloc(nr, sizeof(off64_t));
2840 printf("%d/%lld: line %d error %d\n",
2841 procid, opno, __LINE__, errno);
2845 v = calloc(nr, sizeof(int));
2847 printf("%d/%lld: line %d error %d\n",
2848 procid, opno, __LINE__, errno);
2851 fd = calloc(nr, sizeof(int));
2853 printf("%d/%lld: line %d error %d\n",
2854 procid, opno, __LINE__, errno);
2857 memset(fd, 0xFF, nr * sizeof(int));
2859 /* Get paths for all files */
2860 for (i = 0; i < nr; i++)
2861 init_pathname(&fpath[i]);
2863 if (!get_fname(FT_REGm, r, &fpath[0], NULL, NULL, &v[0])) {
2865 printf("%d/%lld: deduperange read - no filename\n",
2870 for (i = 1; i < nr; i++) {
2871 if (!get_fname(FT_REGm, random(), &fpath[i], NULL, NULL, &v[i])) {
2873 printf("%d/%lld: deduperange write - no filename\n",
2880 fd[0] = open_path(&fpath[0], O_RDONLY);
2881 e = fd[0] < 0 ? errno : 0;
2885 printf("%d/%lld: deduperange read - open %s failed %d\n",
2886 procid, opno, fpath[0].path, e);
2890 for (i = 1; i < nr; i++) {
2891 fd[i] = open_path(&fpath[i], O_WRONLY);
2892 e = fd[i] < 0 ? errno : 0;
2896 printf("%d/%lld: deduperange write - open %s failed %d\n",
2897 procid, opno, fpath[i].path, e);
2902 /* Get file stats */
2903 if (fstat64(fd[0], &stat[0]) < 0) {
2905 printf("%d/%lld: deduperange read - fstat64 %s failed %d\n",
2906 procid, opno, fpath[0].path, errno);
2910 inode_info(&info[0], INFO_SZ, &stat[0], v[0]);
2912 for (i = 1; i < nr; i++) {
2913 if (fstat64(fd[i], &stat[i]) < 0) {
2915 printf("%d/%lld: deduperange write - fstat64 %s failed %d\n",
2916 procid, opno, fpath[i].path, errno);
2919 inode_info(&info[i * INFO_SZ], INFO_SZ, &stat[i], v[i]);
2922 /* Never try to dedupe more than half of the src file. */
2923 len = (random() % FILELEN_MAX) + 1;
2924 len = rounddown_64(len, stat[0].st_blksize);
2926 len = stat[0].st_blksize / 2;
2927 if (len > stat[0].st_size / 2)
2928 len = stat[0].st_size / 2;
2930 /* Calculate offsets */
2931 lr = ((int64_t)random() << 32) + random();
2932 if (stat[0].st_size == len)
2935 off[0] = (off64_t)(lr % MIN(stat[0].st_size - len, MAXFSIZE));
2937 off[0] = rounddown_64(off[0], stat[0].st_blksize);
2940 * If srcfile == destfile[i], randomly generate destination ranges
2941 * until we find one that doesn't overlap the source range.
2943 for (i = 1; i < nr; i++) {
2947 lr = ((int64_t)random() << 32) + random();
2948 if (stat[i].st_size <= len)
2951 off[i] = (off64_t)(lr % MIN(stat[i].st_size - len, MAXFSIZE));
2953 off[i] = rounddown_64(off[i], stat[i].st_blksize);
2954 } while (stat[0].st_ino == stat[i].st_ino &&
2955 llabs(off[i] - off[0]) < len &&
2959 /* Clone data blocks */
2960 fdr->src_offset = off[0];
2961 fdr->src_length = len;
2962 fdr->dest_count = nr - 1;
2963 for (i = 1; i < nr; i++) {
2964 fdr->info[i - 1].dest_fd = fd[i];
2965 fdr->info[i - 1].dest_offset = off[i];
2968 ret = ioctl(fd[0], FIDEDUPERANGE, fdr);
2969 e = ret < 0 ? errno : 0;
2971 printf("%d/%lld: deduperange from %s%s [%lld,%lld]",
2973 fpath[0].path, &info[0], (long long)off[0],
2976 printf(" error %d", e);
2982 for (i = 1; i < nr; i++) {
2983 e = fdr->info[i - 1].status < 0 ? fdr->info[i - 1].status : 0;
2985 printf("%d/%lld: ...to %s%s [%lld,%lld]",
2987 fpath[i].path, &info[i * INFO_SZ],
2988 (long long)off[i], (long long)len);
2989 if (fdr->info[i - 1].status < 0)
2990 printf(" error %d", e);
2991 if (fdr->info[i - 1].status == FILE_DEDUPE_RANGE_SAME)
2992 printf(" %llu bytes deduplicated",
2993 fdr->info[i - 1].bytes_deduped);
2994 if (fdr->info[i - 1].status == FILE_DEDUPE_RANGE_DIFFERS)
2995 printf(" differed");
3001 for (i = 0; i < nr; i++)
3005 for (i = 0; i < nr; i++)
3006 free_pathname(&fpath[i]);
3025 setxattr_f(opnum_t opno, long r)
3027 #ifdef XFS_XFLAG_EXTSIZE
3037 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
3038 append_pathname(&f, ".");
3039 fd = open_path(&f, O_RDWR);
3040 e = fd < 0 ? errno : 0;
3045 e = MIN(idmodulo, XFS_PROJIDMODULO_MAX);
3046 nbits = (int)(random() % e);
3047 p &= (1 << nbits) - 1;
3049 if ((e = xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &fsx)) == 0) {
3051 e = xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &fsx);
3054 printf("%d/%lld: setxattr %s %u %d\n", procid, opno, f.path, p, e);
3061 splice_f(opnum_t opno, long r)
3063 struct pathname fpath1;
3064 struct pathname fpath2;
3065 struct stat64 stat1;
3066 struct stat64 stat2;
3067 char inoinfo1[1024];
3068 char inoinfo2[1024];
3072 loff_t offset1, offset2;
3079 ssize_t ret1 = 0, ret2 = 0;
3085 init_pathname(&fpath1);
3086 if (!get_fname(FT_REGm, r, &fpath1, NULL, NULL, &v1)) {
3088 printf("%d/%lld: splice read - no filename\n",
3093 init_pathname(&fpath2);
3094 if (!get_fname(FT_REGm, random(), &fpath2, NULL, NULL, &v2)) {
3096 printf("%d/%lld: splice write - no filename\n",
3102 fd1 = open_path(&fpath1, O_RDONLY);
3103 e = fd1 < 0 ? errno : 0;
3107 printf("%d/%lld: splice read - open %s failed %d\n",
3108 procid, opno, fpath1.path, e);
3112 fd2 = open_path(&fpath2, O_WRONLY);
3113 e = fd2 < 0 ? errno : 0;
3117 printf("%d/%lld: splice write - open %s failed %d\n",
3118 procid, opno, fpath2.path, e);
3122 /* Get file stats */
3123 if (fstat64(fd1, &stat1) < 0) {
3125 printf("%d/%lld: splice read - fstat64 %s failed %d\n",
3126 procid, opno, fpath1.path, errno);
3129 inode_info(inoinfo1, sizeof(inoinfo1), &stat1, v1);
3131 if (fstat64(fd2, &stat2) < 0) {
3133 printf("%d/%lld: splice write - fstat64 %s failed %d\n",
3134 procid, opno, fpath2.path, errno);
3137 inode_info(inoinfo2, sizeof(inoinfo2), &stat2, v2);
3139 /* Calculate offsets */
3140 len = (random() % FILELEN_MAX) + 1;
3142 len = stat1.st_blksize;
3143 if (len > stat1.st_size)
3144 len = stat1.st_size;
3146 lr = ((int64_t)random() << 32) + random();
3147 if (stat1.st_size == len)
3150 off1 = (off64_t)(lr % MIN(stat1.st_size - len, MAXFSIZE));
3154 * splice can overlap write, so the offset of the target file can be
3155 * any number. But to avoid too large offset, add a clamp of 1024 blocks
3156 * past the current dest file EOF
3158 lr = ((int64_t)random() << 32) + random();
3159 off2 = (off64_t)(lr % MIN(stat2.st_size + (1024ULL * stat2.st_blksize), MAXFSIZE));
3162 * Since len, off1 and off2 will be changed later, preserve their
3169 /* Pipe initialize */
3170 if (pipe(filedes) < 0) {
3172 printf("%d/%lld: splice - pipe failed %d\n",
3173 procid, opno, errno);
3181 /* move to pipe buffer */
3182 ret1 = splice(fd1, &off1, filedes[1], NULL, len, 0);
3188 /* move from pipe buffer to dst file */
3190 ret2 = splice(filedes[0], NULL, fd2, &off2, bytes, 0);
3203 if (ret1 < 0 || ret2 < 0)
3208 printf("%d/%lld: splice %s%s [%lld,%lld] -> %s%s [%lld,%lld] %d",
3210 fpath1.path, inoinfo1, (long long)offset1, (long long)length,
3211 fpath2.path, inoinfo2, (long long)offset2, (long long)length, e);
3213 if (length && length > total)
3214 printf(" asked for %lld, spliced %lld??\n",
3215 (long long)length, (long long)total);
3226 free_pathname(&fpath2);
3228 free_pathname(&fpath1);
3232 creat_f(opnum_t opno, long r)
3247 if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v1))
3252 e1 = (random() % 100);
3253 type = rtpct ? ((e1 > rtpct) ? FT_REG : FT_RTF) : FT_REG;
3255 if (type == FT_RTF) /* rt always gets an extsize */
3256 extsize = (random() % 10) + 1;
3257 else if (e1 < 10) /* one-in-ten get an extsize */
3258 extsize = random() % 1024;
3262 e = generate_fname(fep, type, &f, &id, &v);
3266 (void)fent_to_name(&f, fep);
3267 printf("%d/%lld: creat - no filename from %s\n",
3268 procid, opno, f.path);
3273 fd = creat_path(&f, 0666);
3274 e = fd < 0 ? errno : 0;
3279 xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
3280 if (type == FT_RTF) {
3281 a.fsx_xflags |= XFS_XFLAG_REALTIME;
3282 a.fsx_extsize = extsize *
3283 geom.rtextsize * geom.blocksize;
3285 } else if (extsize) {
3286 a.fsx_xflags |= XFS_XFLAG_EXTSIZE;
3287 a.fsx_extsize = extsize * geom.blocksize;
3290 if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
3293 add_to_flist(type, id, parid, 0);
3297 printf("%d/%lld: creat %s x:%d %d %d\n", procid, opno, f.path,
3298 extsize ? a.fsx_extsize : 0, e, e1);
3299 printf("%d/%lld: creat add id=%d,parent=%d\n", procid, opno, id, parid);
3305 dread_f(opnum_t opno, long r)
3309 struct dioattr diob;
3322 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3324 printf("%d/%lld: dread - no filename\n", procid, opno);
3328 fd = open_path(&f, O_RDONLY|O_DIRECT);
3329 e = fd < 0 ? errno : 0;
3333 printf("%d/%lld: dread - open %s failed %d\n",
3334 procid, opno, f.path, e);
3338 if (fstat64(fd, &stb) < 0) {
3340 printf("%d/%lld: dread - fstat64 %s failed %d\n",
3341 procid, opno, f.path, errno);
3346 inode_info(st, sizeof(st), &stb, v);
3347 if (stb.st_size == 0) {
3349 printf("%d/%lld: dread - %s%s zero size\n", procid, opno,
3355 if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
3358 "%d/%lld: dread - xfsctl(XFS_IOC_DIOINFO) %s%s return %d,"
3359 " fallback to stat()\n",
3360 procid, opno, f.path, st, errno);
3361 diob.d_mem = diob.d_miniosz = stb.st_blksize;
3362 diob.d_maxiosz = rounddown_64(INT_MAX, diob.d_miniosz);
3365 dio_env = getenv("XFS_DIO_MIN");
3367 diob.d_mem = diob.d_miniosz = atoi(dio_env);
3369 align = (int64_t)diob.d_miniosz;
3370 lr = ((int64_t)random() << 32) + random();
3371 off = (off64_t)(lr % stb.st_size);
3372 off -= (off % align);
3373 lseek64(fd, off, SEEK_SET);
3374 len = (random() % FILELEN_MAX) + 1;
3375 len -= (len % align);
3378 else if (len > diob.d_maxiosz)
3379 len = diob.d_maxiosz;
3380 buf = memalign(diob.d_mem, len);
3381 e = read(fd, buf, len) < 0 ? errno : 0;
3384 printf("%d/%lld: dread %s%s [%lld,%d] %d\n",
3385 procid, opno, f.path, st, (long long)off, (int)len, e);
3391 dwrite_f(opnum_t opno, long r)
3395 struct dioattr diob;
3408 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3410 printf("%d/%lld: dwrite - no filename\n", procid, opno);
3414 fd = open_path(&f, O_WRONLY|O_DIRECT);
3415 e = fd < 0 ? errno : 0;
3419 printf("%d/%lld: dwrite - open %s failed %d\n",
3420 procid, opno, f.path, e);
3424 if (fstat64(fd, &stb) < 0) {
3426 printf("%d/%lld: dwrite - fstat64 %s failed %d\n",
3427 procid, opno, f.path, errno);
3432 inode_info(st, sizeof(st), &stb, v);
3433 if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
3435 printf("%d/%lld: dwrite - xfsctl(XFS_IOC_DIOINFO)"
3436 " %s%s return %d, fallback to stat()\n",
3437 procid, opno, f.path, st, errno);
3438 diob.d_mem = diob.d_miniosz = stb.st_blksize;
3439 diob.d_maxiosz = rounddown_64(INT_MAX, diob.d_miniosz);
3442 dio_env = getenv("XFS_DIO_MIN");
3444 diob.d_mem = diob.d_miniosz = atoi(dio_env);
3446 align = (int64_t)diob.d_miniosz;
3447 lr = ((int64_t)random() << 32) + random();
3448 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3449 off -= (off % align);
3450 lseek64(fd, off, SEEK_SET);
3451 len = (random() % FILELEN_MAX) + 1;
3452 len -= (len % align);
3455 else if (len > diob.d_maxiosz)
3456 len = diob.d_maxiosz;
3457 buf = memalign(diob.d_mem, len);
3459 lseek64(fd, off, SEEK_SET);
3460 memset(buf, nameseq & 0xff, len);
3461 e = write(fd, buf, len) < 0 ? errno : 0;
3464 printf("%d/%lld: dwrite %s%s [%lld,%d] %d\n",
3465 procid, opno, f.path, st, (long long)off, (int)len, e);
3471 #ifdef HAVE_LINUX_FALLOC_H
3472 struct print_flags falloc_flags [] = {
3473 { FALLOC_FL_KEEP_SIZE, "KEEP_SIZE"},
3474 { FALLOC_FL_PUNCH_HOLE, "PUNCH_HOLE"},
3475 { FALLOC_FL_NO_HIDE_STALE, "NO_HIDE_STALE"},
3476 { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"},
3477 { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"},
3478 { FALLOC_FL_INSERT_RANGE, "INSERT_RANGE"},
3482 #define translate_falloc_flags(mode) \
3483 ({translate_flags(mode, "|", falloc_flags);})
3487 do_fallocate(opnum_t opno, long r, int mode)
3489 #ifdef HAVE_LINUX_FALLOC_H
3501 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3503 printf("%d/%lld: do_fallocate - no filename\n", procid, opno);
3507 fd = open_path(&f, O_RDWR);
3510 printf("%d/%lld: do_fallocate - open %s failed %d\n",
3511 procid, opno, f.path, errno);
3516 if (fstat64(fd, &stb) < 0) {
3518 printf("%d/%lld: do_fallocate - fstat64 %s failed %d\n",
3519 procid, opno, f.path, errno);
3524 inode_info(st, sizeof(st), &stb, v);
3525 lr = ((int64_t)random() << 32) + random();
3526 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3528 len = (off64_t)(random() % (1024 * 1024));
3530 * Collapse/insert range requires off and len to be block aligned,
3531 * make it more likely to be the case.
3533 if ((mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)) &&
3535 off = roundup_64(off, stb.st_blksize);
3536 len = roundup_64(len, stb.st_blksize);
3538 mode |= FALLOC_FL_KEEP_SIZE & random();
3539 e = fallocate(fd, mode, (loff_t)off, (loff_t)len) < 0 ? errno : 0;
3541 printf("%d/%lld: fallocate(%s) %s %st %lld %lld %d\n",
3542 procid, opno, translate_falloc_flags(mode),
3543 f.path, st, (long long)off, (long long)len, e);
3550 fallocate_f(opnum_t opno, long r)
3552 #ifdef HAVE_LINUX_FALLOC_H
3553 do_fallocate(opno, r, 0);
3558 fdatasync_f(opnum_t opno, long r)
3566 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3568 printf("%d/%lld: fdatasync - no filename\n",
3573 fd = open_path(&f, O_WRONLY);
3574 e = fd < 0 ? errno : 0;
3578 printf("%d/%lld: fdatasync - open %s failed %d\n",
3579 procid, opno, f.path, e);
3583 e = fdatasync(fd) < 0 ? errno : 0;
3585 printf("%d/%lld: fdatasync %s %d\n", procid, opno, f.path, e);
3590 #ifdef HAVE_LINUX_FIEMAP_H
3591 struct print_flags fiemap_flags[] = {
3592 { FIEMAP_FLAG_SYNC, "SYNC"},
3593 { FIEMAP_FLAG_XATTR, "XATTR"},
3597 #define translate_fiemap_flags(mode) \
3598 ({translate_flags(mode, "|", fiemap_flags);})
3602 fiemap_f(opnum_t opno, long r)
3604 #ifdef HAVE_LINUX_FIEMAP_H
3614 struct fiemap *fiemap;
3617 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
3619 printf("%d/%lld: fiemap - no filename\n", procid, opno);
3623 fd = open_path(&f, O_RDWR);
3624 e = fd < 0 ? errno : 0;
3628 printf("%d/%lld: fiemap - open %s failed %d\n",
3629 procid, opno, f.path, e);
3633 if (fstat64(fd, &stb) < 0) {
3635 printf("%d/%lld: fiemap - fstat64 %s failed %d\n",
3636 procid, opno, f.path, errno);
3641 inode_info(st, sizeof(st), &stb, v);
3642 blocks_to_map = random() & 0xffff;
3643 fiemap = (struct fiemap *)malloc(sizeof(struct fiemap) +
3644 (blocks_to_map * sizeof(struct fiemap_extent)));
3647 printf("%d/%lld: malloc failed \n", procid, opno);
3652 lr = ((int64_t)random() << 32) + random();
3653 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
3655 fiemap->fm_flags = random() & (FIEMAP_FLAGS_COMPAT | 0x10000);
3656 fiemap->fm_extent_count = blocks_to_map;
3657 fiemap->fm_mapped_extents = random() & 0xffff;
3658 fiemap->fm_start = off;
3659 fiemap->fm_length = ((int64_t)random() << 32) + random();
3661 e = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
3663 printf("%d/%lld: ioctl(FIEMAP) %s%s %lld %lld (%s) %d\n",
3664 procid, opno, f.path, st, (long long)fiemap->fm_start,
3665 (long long) fiemap->fm_length,
3666 translate_fiemap_flags(fiemap->fm_flags), e);
3674 fsync_f(opnum_t opno, long r)
3682 if (!get_fname(FT_REGFILE | FT_DIRm, r, &f, NULL, NULL, &v)) {
3684 printf("%d/%lld: fsync - no filename\n", procid, opno);
3688 fd = open_file_or_dir(&f, O_WRONLY);
3689 e = fd < 0 ? errno : 0;
3693 printf("%d/%lld: fsync - open %s failed %d\n",
3694 procid, opno, f.path, e);
3698 e = fsync(fd) < 0 ? errno : 0;
3700 printf("%d/%lld: fsync %s %d\n", procid, opno, f.path, e);
3706 gen_random_string(int len)
3708 static const char charset[] = "0123456789"
3709 "abcdefghijklmnopqrstuvwxyz"
3710 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
3721 for (i = 0; i < len; i++)
3722 s[i] = charset[random() % sizeof(charset)];
3728 getattr_f(opnum_t opno, long r)
3737 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
3738 append_pathname(&f, ".");
3739 fd = open_path(&f, O_RDWR);
3740 e = fd < 0 ? errno : 0;
3743 e = ioctl(fd, FS_IOC_GETFLAGS, &fl);
3745 printf("%d/%lld: getattr %s %u %d\n", procid, opno, f.path, fl, e);
3751 getdents_f(opnum_t opno, long r)
3758 if (!get_fname(FT_ANYDIR, r, &f, NULL, NULL, &v))
3759 append_pathname(&f, ".");
3760 dir = opendir_path(&f);
3764 printf("%d/%lld: getdents - can't open %s\n",
3765 procid, opno, f.path);
3769 while (readdir64(dir) != NULL)
3772 printf("%d/%lld: getdents %s 0\n", procid, opno, f.path);
3778 getfattr_f(opnum_t opno, long r)
3784 char name[XATTR_NAME_BUF_SIZE];
3790 if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
3792 printf("%d/%lld: getfattr - no filename\n", procid, opno);
3798 * If the file/dir has xattrs, pick one randomly, otherwise attempt
3799 * to read a xattr that doesn't exist (fgetxattr should fail with
3800 * errno set to ENOATTR (61) in this case).
3802 if (fep->xattr_counter > 0)
3803 xattr_num = (random() % fep->xattr_counter) + 1;
3807 e = generate_xattr_name(xattr_num, name, sizeof(name));
3809 printf("%d/%lld: getfattr - file %s failed to generate xattr name: %d\n",
3810 procid, opno, f.path, e);
3814 value_len = getxattr(f.path, name, NULL, 0);
3815 if (value_len < 0) {
3817 printf("%d/%lld: getfattr file %s name %s failed %d\n",
3818 procid, opno, f.path, name, errno);
3822 /* A xattr without value.*/
3823 if (value_len == 0) {
3828 value = malloc(value_len);
3831 printf("%d/%lld: getfattr file %s failed to allocate buffer with %d bytes\n",
3832 procid, opno, f.path, value_len);
3836 e = getxattr(f.path, name, value, value_len) < 0 ? errno : 0;
3839 printf("%d/%lld: getfattr file %s name %s value length %d %d\n",
3840 procid, opno, f.path, name, value_len, e);
3847 link_f(opnum_t opno, long r)
3861 if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep_src, &v1)) {
3863 printf("%d/%lld: link - no file\n", procid, opno);
3867 if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
3873 e = generate_fname(fep, flp - flist, &l, &id, &v1);
3877 (void)fent_to_name(&l, fep);
3878 printf("%d/%lld: link - no filename from %s\n",
3879 procid, opno, l.path);
3885 e = link_path(&f, &l) < 0 ? errno : 0;
3888 add_to_flist(flp - flist, id, parid, fep_src->xattr_counter);
3890 printf("%d/%lld: link %s %s %d\n", procid, opno, f.path, l.path,
3892 printf("%d/%lld: link add id=%d,parent=%d\n", procid, opno, id, parid);
3899 listfattr_f(opnum_t opno, long r)
3905 char *buffer = NULL;
3909 if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
3911 printf("%d/%lld: listfattr - no filename\n", procid, opno);
3916 e = listxattr(f.path, NULL, 0);
3919 printf("%d/%lld: listfattr %s failed %d\n",
3920 procid, opno, f.path, errno);
3924 if (buffer_len == 0) {
3926 printf("%d/%lld: listfattr %s - has no extended attributes\n",
3927 procid, opno, f.path);
3931 buffer = malloc(buffer_len);
3934 printf("%d/%lld: listfattr %s failed to allocate buffer with %d bytes\n",
3935 procid, opno, f.path, buffer_len);
3939 e = listxattr(f.path, buffer, buffer_len) < 0 ? errno : 0;
3941 printf("%d/%lld: listfattr %s buffer length %d %d\n",
3942 procid, opno, f.path, buffer_len, e);
3949 mkdir_f(opnum_t opno, long r)
3959 if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
3964 e = generate_fname(fep, FT_DIR, &f, &id, &v1);
3968 (void)fent_to_name(&f, fep);
3969 printf("%d/%lld: mkdir - no filename from %s\n",
3970 procid, opno, f.path);
3975 e = mkdir_path(&f, 0777) < 0 ? errno : 0;
3978 add_to_flist(FT_DIR, id, parid, 0);
3980 printf("%d/%lld: mkdir %s %d\n", procid, opno, f.path, e);
3981 printf("%d/%lld: mkdir add id=%d,parent=%d\n", procid, opno, id, parid);
3987 mknod_f(opnum_t opno, long r)
3997 if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
4002 e = generate_fname(fep, FT_DEV, &f, &id, &v1);
4006 (void)fent_to_name(&f, fep);
4007 printf("%d/%lld: mknod - no filename from %s\n",
4008 procid, opno, f.path);
4013 e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
4016 add_to_flist(FT_DEV, id, parid, 0);
4018 printf("%d/%lld: mknod %s %d\n", procid, opno, f.path, e);
4019 printf("%d/%lld: mknod add id=%d,parent=%d\n", procid, opno, id, parid);
4024 #ifdef HAVE_SYS_MMAN_H
4025 struct print_flags mmap_flags[] = {
4026 { MAP_SHARED, "SHARED"},
4027 { MAP_PRIVATE, "PRIVATE"},
4031 #define translate_mmap_flags(flags) \
4032 ({translate_flags(flags, "|", mmap_flags);})
4036 do_mmap(opnum_t opno, long r, int prot)
4038 #ifdef HAVE_SYS_MMAN_H
4050 sigjmp_buf sigbus_jmpbuf;
4053 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
4055 printf("%d/%lld: do_mmap - no filename\n", procid, opno);
4059 fd = open_path(&f, O_RDWR);
4060 e = fd < 0 ? errno : 0;
4064 printf("%d/%lld: do_mmap - open %s failed %d\n",
4065 procid, opno, f.path, e);
4069 if (fstat64(fd, &stb) < 0) {
4071 printf("%d/%lld: do_mmap - fstat64 %s failed %d\n",
4072 procid, opno, f.path, errno);
4077 inode_info(st, sizeof(st), &stb, v);
4078 if (stb.st_size == 0) {
4080 printf("%d/%lld: do_mmap - %s%s zero size\n", procid, opno,
4087 lr = ((int64_t)random() << 32) + random();
4088 off = (off64_t)(lr % stb.st_size);
4089 off = rounddown_64(off, sysconf(_SC_PAGE_SIZE));
4090 len = (size_t)(random() % MIN(stb.st_size - off, FILELEN_MAX)) + 1;
4092 flags = (random() % 2) ? MAP_SHARED : MAP_PRIVATE;
4093 addr = mmap(NULL, len, prot, flags, fd, off);
4094 e = (addr == MAP_FAILED) ? errno : 0;
4097 printf("%d/%lld: do_mmap - mmap failed %s%s [%lld,%d,%s] %d\n",
4098 procid, opno, f.path, st, (long long)off,
4099 (int)len, translate_mmap_flags(flags), e);
4105 if (prot & PROT_WRITE) {
4106 if ((e = sigsetjmp(sigbus_jmpbuf, 1)) == 0) {
4107 sigbus_jmp = &sigbus_jmpbuf;
4108 memset(addr, nameseq & 0xff, len);
4112 if ((buf = malloc(len)) != NULL) {
4113 memcpy(buf, addr, len);
4118 /* set NULL to stop other functions from doing siglongjmp */
4122 printf("%d/%lld: %s %s%s [%lld,%d,%s] %s\n",
4123 procid, opno, (prot & PROT_WRITE) ? "mwrite" : "mread",
4124 f.path, st, (long long)off, (int)len,
4125 translate_mmap_flags(flags),
4126 (e == 0) ? "0" : "Bus error");
4134 mread_f(opnum_t opno, long r)
4136 #ifdef HAVE_SYS_MMAN_H
4137 do_mmap(opno, r, PROT_READ);
4142 mwrite_f(opnum_t opno, long r)
4144 #ifdef HAVE_SYS_MMAN_H
4145 do_mmap(opno, r, PROT_WRITE);
4150 punch_f(opnum_t opno, long r)
4152 #ifdef HAVE_LINUX_FALLOC_H
4153 do_fallocate(opno, r, FALLOC_FL_PUNCH_HOLE);
4158 zero_f(opnum_t opno, long r)
4160 #ifdef HAVE_LINUX_FALLOC_H
4161 do_fallocate(opno, r, FALLOC_FL_ZERO_RANGE);
4166 collapse_f(opnum_t opno, long r)
4168 #ifdef HAVE_LINUX_FALLOC_H
4169 do_fallocate(opno, r, FALLOC_FL_COLLAPSE_RANGE);
4174 insert_f(opnum_t opno, long r)
4176 #ifdef HAVE_LINUX_FALLOC_H
4177 do_fallocate(opno, r, FALLOC_FL_INSERT_RANGE);
4182 read_f(opnum_t opno, long r)
4196 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
4198 printf("%d/%lld: read - no filename\n", procid, opno);
4202 fd = open_path(&f, O_RDONLY);
4203 e = fd < 0 ? errno : 0;
4207 printf("%d/%lld: read - open %s failed %d\n",
4208 procid, opno, f.path, e);
4212 if (fstat64(fd, &stb) < 0) {
4214 printf("%d/%lld: read - fstat64 %s failed %d\n",
4215 procid, opno, f.path, errno);
4220 inode_info(st, sizeof(st), &stb, v);
4221 if (stb.st_size == 0) {
4223 printf("%d/%lld: read - %s%s zero size\n", procid, opno,
4229 lr = ((int64_t)random() << 32) + random();
4230 off = (off64_t)(lr % stb.st_size);
4231 lseek64(fd, off, SEEK_SET);
4232 len = (random() % FILELEN_MAX) + 1;
4234 e = read(fd, buf, len) < 0 ? errno : 0;
4237 printf("%d/%lld: read %s%s [%lld,%d] %d\n",
4238 procid, opno, f.path, st, (long long)off, (int)len, e);
4244 readlink_f(opnum_t opno, long r)
4252 if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
4254 printf("%d/%lld: readlink - no filename\n", procid, opno);
4258 e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
4261 printf("%d/%lld: readlink %s %d\n", procid, opno, f.path, e);
4266 readv_f(opnum_t opno, long r)
4278 struct iovec *iov = NULL;
4285 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
4287 printf("%d/%lld: readv - no filename\n", procid, opno);
4291 fd = open_path(&f, O_RDONLY);
4292 e = fd < 0 ? errno : 0;
4296 printf("%d/%lld: readv - open %s failed %d\n",
4297 procid, opno, f.path, e);
4301 if (fstat64(fd, &stb) < 0) {
4303 printf("%d/%lld: readv - fstat64 %s failed %d\n",
4304 procid, opno, f.path, errno);
4309 inode_info(st, sizeof(st), &stb, v);
4310 if (stb.st_size == 0) {
4312 printf("%d/%lld: readv - %s%s zero size\n", procid, opno,
4318 lr = ((int64_t)random() << 32) + random();
4319 off = (off64_t)(lr % stb.st_size);
4320 lseek64(fd, off, SEEK_SET);
4321 len = (random() % FILELEN_MAX) + 1;
4324 iovcnt = (random() % MIN(len, IOV_MAX)) + 1;
4325 iov = calloc(iovcnt, sizeof(struct iovec));
4326 iovl = len / iovcnt;
4328 for (i=0; i<iovcnt; i++) {
4329 (iov + i)->iov_base = (buf + iovb);
4330 (iov + i)->iov_len = iovl;
4334 e = readv(fd, iov, iovcnt) < 0 ? errno : 0;
4337 printf("%d/%lld: readv %s%s [%lld,%d,%d] %d\n",
4338 procid, opno, f.path, st, (long long)off, (int)iovl,
4345 removefattr_f(opnum_t opno, long r)
4351 char name[XATTR_NAME_BUF_SIZE];
4355 if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
4357 printf("%d/%lld: removefattr - no filename\n", procid, opno);
4363 * If the file/dir has xattrs, pick one randomly, otherwise attempt to
4364 * remove a xattr that doesn't exist (fremovexattr should fail with
4365 * errno set to ENOATTR (61) in this case).
4367 if (fep->xattr_counter > 0)
4368 xattr_num = (random() % fep->xattr_counter) + 1;
4372 e = generate_xattr_name(xattr_num, name, sizeof(name));
4374 printf("%d/%lld: removefattr - file %s failed to generate xattr name: %d\n",
4375 procid, opno, f.path, e);
4379 e = removexattr(f.path, name) < 0 ? errno : 0;
4381 printf("%d/%lld: removefattr file %s name %s %d\n",
4382 procid, opno, f.path, name, e);
4387 struct print_flags renameat2_flags [] = {
4388 { RENAME_NOREPLACE, "NOREPLACE"},
4389 { RENAME_EXCHANGE, "EXCHANGE"},
4390 { RENAME_WHITEOUT, "WHITEOUT"},
4394 #define translate_renameat2_flags(mode) \
4395 ({translate_flags(mode, "|", renameat2_flags);})
4398 do_renameat2(opnum_t opno, long r, int mode)
4414 /* get an existing path for the source of the rename */
4416 which = (mode == RENAME_WHITEOUT) ? FT_DEVm : FT_ANYm;
4417 if (!get_fname(which, r, &f, &flp, &fep, &v1)) {
4419 printf("%d/%lld: rename - no source filename\n",
4426 * Both pathnames must exist for the RENAME_EXCHANGE, and in
4427 * order to maintain filelist/filename integrity, we should
4428 * restrict exchange operation to files of the same type.
4430 if (mode == RENAME_EXCHANGE) {
4431 which = 1 << (flp - flist);
4432 init_pathname(&newf);
4433 if (!get_fname(which, random(), &newf, NULL, &dfep, &v)) {
4435 printf("%d/%lld: rename - no target filename\n",
4437 free_pathname(&newf);
4441 if (which == FT_DIRm && (fents_ancestor_check(fep, dfep) ||
4442 fents_ancestor_check(dfep, fep))) {
4444 printf("%d/%lld: rename(REXCHANGE) %s and %s "
4445 "have ancestor-descendant relationship\n",
4446 procid, opno, f.path, newf.path);
4447 free_pathname(&newf);
4453 parid = dfep->parent;
4456 * Get an existing directory for the destination parent
4459 if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
4466 * Generate a new path using an existing parent directory
4469 init_pathname(&newf);
4470 e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
4474 (void)fent_to_name(&f, dfep);
4475 printf("%d/%lld: rename - no filename from %s\n",
4476 procid, opno, f.path);
4478 free_pathname(&newf);
4483 e = rename_path(&f, &newf, mode) < 0 ? errno : 0;
4486 int xattr_counter = fep->xattr_counter;
4487 bool swap = (mode == RENAME_EXCHANGE) ? true : false;
4488 int ft = flp - flist;
4491 oldparid = fep->parent;
4494 * Swap the parent ids for RENAME_EXCHANGE, and replace the
4495 * old parent id for the others.
4497 if (ft == FT_DIR || ft == FT_SUBVOL)
4498 fix_parent(oldid, id, swap);
4500 if (mode == RENAME_WHITEOUT) {
4501 fep->xattr_counter = 0;
4502 add_to_flist(flp - flist, id, parid, xattr_counter);
4503 } else if (mode == RENAME_EXCHANGE) {
4504 fep->xattr_counter = dfep->xattr_counter;
4505 dfep->xattr_counter = xattr_counter;
4507 del_from_flist(flp - flist, fep - flp->fents);
4508 add_to_flist(flp - flist, id, parid, xattr_counter);
4512 printf("%d/%lld: rename(%s) %s to %s %d\n", procid,
4513 opno, translate_renameat2_flags(mode), f.path,
4516 printf("%d/%lld: rename source entry: id=%d,parent=%d\n",
4517 procid, opno, oldid, oldparid);
4518 printf("%d/%lld: rename target entry: id=%d,parent=%d\n",
4519 procid, opno, id, parid);
4522 free_pathname(&newf);
4527 rename_f(opnum_t opno, long r)
4529 do_renameat2(opno, r, 0);
4533 rnoreplace_f(opnum_t opno, long r)
4535 do_renameat2(opno, r, RENAME_NOREPLACE);
4539 rexchange_f(opnum_t opno, long r)
4541 do_renameat2(opno, r, RENAME_EXCHANGE);
4545 rwhiteout_f(opnum_t opno, long r)
4547 do_renameat2(opno, r, RENAME_WHITEOUT);
4551 resvsp_f(opnum_t opno, long r)
4556 struct xfs_flock64 fl;
4564 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
4566 printf("%d/%lld: resvsp - no filename\n", procid, opno);
4570 fd = open_path(&f, O_RDWR);
4571 e = fd < 0 ? errno : 0;
4575 printf("%d/%lld: resvsp - open %s failed %d\n",
4576 procid, opno, f.path, e);
4580 if (fstat64(fd, &stb) < 0) {
4582 printf("%d/%lld: resvsp - fstat64 %s failed %d\n",
4583 procid, opno, f.path, errno);
4588 inode_info(st, sizeof(st), &stb, v);
4589 lr = ((int64_t)random() << 32) + random();
4590 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
4592 fl.l_whence = SEEK_SET;
4594 fl.l_len = (off64_t)(random() % (1024 * 1024));
4595 e = xfsctl(f.path, fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
4597 printf("%d/%lld: xfsctl(XFS_IOC_RESVSP64) %s%s %lld %lld %d\n",
4598 procid, opno, f.path, st,
4599 (long long)off, (long long)fl.l_len, e);
4605 rmdir_f(opnum_t opno, long r)
4615 if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
4617 printf("%d/%lld: rmdir - no directory\n", procid, opno);
4621 e = rmdir_path(&f) < 0 ? errno : 0;
4625 oldparid = fep->parent;
4626 del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
4629 printf("%d/%lld: rmdir %s %d\n", procid, opno, f.path, e);
4631 printf("%d/%lld: rmdir del entry: id=%d,parent=%d\n",
4632 procid, opno, oldid, oldparid);
4638 setattr_f(opnum_t opno, long r)
4647 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
4648 append_pathname(&f, ".");
4649 fd = open_path(&f, O_RDWR);
4650 e = fd < 0 ? errno : 0;
4653 fl = attr_mask & (uint)random();
4654 e = ioctl(fd, FS_IOC_SETFLAGS, &fl);
4656 printf("%d/%lld: setattr %s %x %d\n", procid, opno, f.path, fl, e);
4662 setfattr_f(opnum_t opno, long r)
4669 char name[XATTR_NAME_BUF_SIZE];
4675 if (!get_fname(FT_REGFILE | FT_ANYDIR, r, &f, NULL, &fep, &v)) {
4677 printf("%d/%lld: setfattr - no filename\n", procid, opno);
4682 if ((fep->xattr_counter > 0) && (random() % 2)) {
4684 * Use an existing xattr name for replacing its value or
4685 * create again a xattr that was previously deleted.
4687 xattr_num = (random() % fep->xattr_counter) + 1;
4689 flag = XATTR_REPLACE;
4691 /* Use a new xattr name. */
4692 xattr_num = fep->xattr_counter + 1;
4694 * Don't always use the create flag because even if our xattr
4695 * counter is 0, we may still have xattrs associated to this
4696 * file (this happens when xattrs are added to a file through
4697 * one of its other hard links), so we can end up updating an
4698 * existing xattr too.
4701 flag = XATTR_CREATE;
4705 * The maximum supported value size depends on the filesystem
4706 * implementation, but 100 bytes is a safe value for most filesystems
4709 value_len = random() % 101;
4710 value = gen_random_string(value_len);
4711 if (!value && value_len > 0) {
4713 printf("%d/%lld: setfattr - file %s failed to allocate value with %d bytes\n",
4714 procid, opno, f.path, value_len);
4717 e = generate_xattr_name(xattr_num, name, sizeof(name));
4719 printf("%d/%lld: setfattr - file %s failed to generate xattr name: %d\n",
4720 procid, opno, f.path, e);
4724 e = setxattr(f.path, name, value, value_len, flag) < 0 ? errno : 0;
4726 fep->xattr_counter++;
4728 printf("%d/%lld: setfattr file %s name %s flag %s value length %d: %d\n",
4729 procid, opno, f.path, name, xattr_flag_to_string(flag),
4737 snapshot_f(opnum_t opno, long r)
4739 #ifdef HAVE_BTRFSUTIL_H
4740 enum btrfs_util_error e;
4751 if (!get_fname(FT_SUBVOLm, r, &f, NULL, &fep, &v)) {
4753 printf("%d/%lld: snapshot - no subvolume\n", procid,
4758 init_pathname(&newf);
4760 err = generate_fname(fep, FT_SUBVOL, &newf, &id, &v1);
4764 (void)fent_to_name(&f, fep);
4765 printf("%d/%lld: snapshot - no filename from %s\n",
4766 procid, opno, f.path);
4771 e = btrfs_util_create_snapshot(f.path, newf.path, 0, NULL, NULL);
4772 if (e == BTRFS_UTIL_OK)
4773 add_to_flist(FT_SUBVOL, id, parid, 0);
4775 printf("%d/%lld: snapshot %s->%s %d(%s)\n", procid, opno,
4776 f.path, newf.path, e, btrfs_util_strerror(e));
4777 printf("%d/%lld: snapshot add id=%d,parent=%d\n", procid, opno,
4780 free_pathname(&newf);
4786 stat_f(opnum_t opno, long r)
4794 if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
4796 printf("%d/%lld: stat - no entries\n", procid, opno);
4800 e = lstat64_path(&f, &stb) < 0 ? errno : 0;
4803 printf("%d/%lld: stat %s %d\n", procid, opno, f.path, e);
4808 subvol_create_f(opnum_t opno, long r)
4810 #ifdef HAVE_BTRFSUTIL_H
4811 enum btrfs_util_error e;
4821 if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
4825 err = generate_fname(fep, FT_SUBVOL, &f, &id, &v1);
4829 (void)fent_to_name(&f, fep);
4830 printf("%d/%lld: subvol_create - no filename from %s\n",
4831 procid, opno, f.path);
4836 e = btrfs_util_create_subvolume(f.path, 0, NULL, NULL);
4837 if (e == BTRFS_UTIL_OK)
4838 add_to_flist(FT_SUBVOL, id, parid, 0);
4840 printf("%d/%lld: subvol_create %s %d(%s)\n", procid, opno,
4841 f.path, e, btrfs_util_strerror(e));
4842 printf("%d/%lld: subvol_create add id=%d,parent=%d\n", procid,
4850 subvol_delete_f(opnum_t opno, long r)
4852 #ifdef HAVE_BTRFSUTIL_H
4853 enum btrfs_util_error e;
4861 if (!get_fname(FT_SUBVOLm, r, &f, NULL, &fep, &v)) {
4863 printf("%d:%lld: subvol_delete - no subvolume\n", procid,
4868 e = btrfs_util_delete_subvolume(f.path, 0);
4870 if (e == BTRFS_UTIL_OK) {
4872 oldparid = fep->parent;
4873 delete_subvol_children(oldid);
4874 del_from_flist(FT_SUBVOL, fep - flist[FT_SUBVOL].fents);
4877 printf("%d/%lld: subvol_delete %s %d(%s)\n", procid, opno, f.path,
4878 e, btrfs_util_strerror(e));
4879 if (e == BTRFS_UTIL_OK)
4880 printf("%d/%lld: subvol_delete del entry: id=%d,parent=%d\n",
4881 procid, opno, oldid, oldparid);
4888 symlink_f(opnum_t opno, long r)
4901 if (!get_fname(FT_ANYDIR, r, NULL, NULL, &fep, &v))
4906 e = generate_fname(fep, FT_SYM, &f, &id, &v1);
4910 (void)fent_to_name(&f, fep);
4911 printf("%d/%lld: symlink - no filename from %s\n",
4912 procid, opno, f.path);
4917 len = (int)(random() % PATH_MAX);
4918 val = malloc(len + 1);
4920 memset(val, 'x', len);
4922 for (i = 10; i < len - 1; i += 10)
4924 e = symlink_path(val, &f) < 0 ? errno : 0;
4927 add_to_flist(FT_SYM, id, parid, 0);
4930 printf("%d/%lld: symlink %s %d\n", procid, opno, f.path, e);
4931 printf("%d/%lld: symlink add id=%d,parent=%d\n", procid, opno, id, parid);
4938 sync_f(opnum_t opno, long r)
4942 printf("%d/%lld: sync\n", procid, opno);
4946 truncate_f(opnum_t opno, long r)
4957 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
4959 printf("%d/%lld: truncate - no filename\n", procid, opno);
4963 e = stat64_path(&f, &stb) < 0 ? errno : 0;
4967 printf("%d/%lld: truncate - stat64 %s failed %d\n",
4968 procid, opno, f.path, e);
4972 inode_info(st, sizeof(st), &stb, v);
4973 lr = ((int64_t)random() << 32) + random();
4974 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
4976 e = truncate64_path(&f, off) < 0 ? errno : 0;
4979 printf("%d/%lld: truncate %s%s %lld %d\n", procid, opno, f.path,
4980 st, (long long)off, e);
4985 unlink_f(opnum_t opno, long r)
4996 if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
4998 printf("%d/%lld: unlink - no file\n", procid, opno);
5002 e = unlink_path(&f) < 0 ? errno : 0;
5006 oldparid = fep->parent;
5007 del_from_flist(flp - flist, fep - flp->fents);
5010 printf("%d/%lld: unlink %s %d\n", procid, opno, f.path, e);
5012 printf("%d/%lld: unlink del entry: id=%d,parent=%d\n",
5013 procid, opno, oldid, oldparid);
5019 unresvsp_f(opnum_t opno, long r)
5024 struct xfs_flock64 fl;
5032 if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
5034 printf("%d/%lld: unresvsp - no filename\n", procid, opno);
5038 fd = open_path(&f, O_RDWR);
5039 e = fd < 0 ? errno : 0;
5043 printf("%d/%lld: unresvsp - open %s failed %d\n",
5044 procid, opno, f.path, e);
5048 if (fstat64(fd, &stb) < 0) {
5050 printf("%d/%lld: unresvsp - fstat64 %s failed %d\n",
5051 procid, opno, f.path, errno);
5056 inode_info(st, sizeof(st), &stb, v);
5057 lr = ((int64_t)random() << 32) + random();
5058 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
5060 fl.l_whence = SEEK_SET;
5062 fl.l_len = (off64_t)(random() % (1 << 20));
5063 e = xfsctl(f.path, fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
5065 printf("%d/%lld: xfsctl(XFS_IOC_UNRESVSP64) %s%s %lld %lld %d\n",
5066 procid, opno, f.path, st,
5067 (long long)off, (long long)fl.l_len, e);
5073 uring_read_f(opnum_t opno, long r)
5076 do_uring_rw(opno, r, O_RDONLY);
5081 uring_write_f(opnum_t opno, long r)
5084 do_uring_rw(opno, r, O_WRONLY);
5089 write_f(opnum_t opno, long r)
5103 if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
5105 printf("%d/%lld: write - no filename\n", procid, opno);
5109 fd = open_path(&f, O_WRONLY);
5110 e = fd < 0 ? errno : 0;
5114 printf("%d/%lld: write - open %s failed %d\n",
5115 procid, opno, f.path, e);
5119 if (fstat64(fd, &stb) < 0) {
5121 printf("%d/%lld: write - fstat64 %s failed %d\n",
5122 procid, opno, f.path, errno);
5127 inode_info(st, sizeof(st), &stb, v);
5128 lr = ((int64_t)random() << 32) + random();
5129 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
5131 lseek64(fd, off, SEEK_SET);
5132 len = (random() % FILELEN_MAX) + 1;
5134 memset(buf, nameseq & 0xff, len);
5135 e = write(fd, buf, len) < 0 ? errno : 0;
5138 printf("%d/%lld: write %s%s [%lld,%d] %d\n",
5139 procid, opno, f.path, st, (long long)off, (int)len, e);
5145 writev_f(opnum_t opno, long r)
5157 struct iovec *iov = NULL;
5164 if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
5166 printf("%d/%lld: writev - no filename\n", procid, opno);
5170 fd = open_path(&f, O_WRONLY);
5171 e = fd < 0 ? errno : 0;
5175 printf("%d/%lld: writev - open %s failed %d\n",
5176 procid, opno, f.path, e);
5180 if (fstat64(fd, &stb) < 0) {
5182 printf("%d/%lld: writev - fstat64 %s failed %d\n",
5183 procid, opno, f.path, errno);
5188 inode_info(st, sizeof(st), &stb, v);
5189 lr = ((int64_t)random() << 32) + random();
5190 off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
5192 lseek64(fd, off, SEEK_SET);
5193 len = (random() % FILELEN_MAX) + 1;
5195 memset(buf, nameseq & 0xff, len);
5197 iovcnt = (random() % MIN(len, IOV_MAX)) + 1;
5198 iov = calloc(iovcnt, sizeof(struct iovec));
5199 iovl = len / iovcnt;
5201 for (i=0; i<iovcnt; i++) {
5202 (iov + i)->iov_base = (buf + iovb);
5203 (iov + i)->iov_len = iovl;
5207 e = writev(fd, iov, iovcnt) < 0 ? errno : 0;
5211 printf("%d/%lld: writev %s%s [%lld,%d,%d] %d\n",
5212 procid, opno, f.path, st, (long long)off, (int)iovl,
5219 xattr_flag_to_string(int flag)
5221 if (flag == XATTR_CREATE)
5223 if (flag == XATTR_REPLACE)