2 * Copyright (C) 1991, NeXT Computer, Inc. All Rights Reserverd.
5 * Author: Avadis Tevanian, Jr.
7 * File system exerciser.
9 * Rewritten 8/98 by Conrad Minshall.
11 * Small changes to work under Linux -- davej.
13 * Checks for mmap last-page zero fill.
42 #define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */
46 enum opflags { FL_NONE = 0, FL_SKIPPED = 1, FL_CLOSE_OPEN = 2, FL_KEEP_SIZE = 4 };
49 * A log entry is an operation and a bunch of arguments.
61 struct log_entry oplog[LOGSIZE]; /* the log */
62 int logptr = 0; /* current position in log */
63 int logcount = 0; /* total ops */
66 * The operation matrix is complex due to conditional execution of different
67 * features. Hence when we come to deciding what operation to run, we need to
68 * be careful in how we select the different operations. The active operations
69 * are mapped to numbers as follows:
71 * lite !lite integrity
80 * COLLAPSE RANGE: - 8 8
83 * When mapped read/writes are disabled, they are simply converted to normal
84 * reads and writes. When fallocate/fpunch calls are disabled, they are
87 * Because of the "lite" version, we also need to have different "maximum
88 * operation" defines to allow the ops to be selected correctly based on the
93 /* common operations */
100 /* !lite operations */
101 OP_TRUNCATE = OP_MAX_LITE,
110 /* integrity operations */
111 OP_FSYNC = OP_MAX_FULL,
116 #define PAGE_SIZE getpagesize()
118 #define PAGE_MASK (PAGE_SIZE - 1)
120 char *original_buf; /* a pointer to the original data */
121 char *good_buf; /* a pointer to the correct data */
122 char *temp_buf; /* a pointer to the current data */
123 char *fname; /* name of our test file */
124 char *bname; /* basename of our test file */
125 char *logdev; /* -i flag */
126 char *logid; /* -j flag */
127 char dname[1024]; /* -P flag */
128 char goodfile[PATH_MAX];
129 int dirpath = 0; /* -P flag */
130 int fd; /* fd for our test file */
132 blksize_t block_size = 0;
135 unsigned long testcalls = 0; /* calls to function "test" */
137 unsigned long simulatedopcount = 0; /* -b flag */
138 int closeprob = 0; /* -c flag */
139 int debug = 0; /* -d flag */
140 unsigned long debugstart = 0; /* -D flag */
141 char filldata = 0; /* -g flag */
142 int flush = 0; /* -f flag */
143 int do_fsync = 0; /* -y flag */
144 unsigned long maxfilelen = 256 * 1024; /* -l flag */
145 int sizechecks = 1; /* -n flag disables them */
146 int maxoplen = 64 * 1024; /* -o flag */
147 int quiet = 0; /* -q flag */
148 unsigned long progressinterval = 0; /* -p flag */
149 int readbdy = 1; /* -r flag */
150 int style = 0; /* -s flag */
151 int prealloc = 0; /* -x flag */
152 int truncbdy = 1; /* -t flag */
153 int writebdy = 1; /* -w flag */
154 long monitorstart = -1; /* -m flag */
155 long monitorend = -1; /* -m flag */
156 int lite = 0; /* -L flag */
157 long numops = -1; /* -N flag */
158 int randomoplen = 1; /* -O flag disables it */
159 int seed = 1; /* -S flag */
160 int mapped_writes = 1; /* -W flag disables */
161 int fallocate_calls = 1; /* -F flag disables */
162 int keep_size_calls = 1; /* -K flag disables */
163 int punch_hole_calls = 1; /* -H flag disables */
164 int zero_range_calls = 1; /* -z flag disables */
165 int collapse_range_calls = 1; /* -C flag disables */
166 int insert_range_calls = 1; /* -I flag disables */
167 int mapped_reads = 1; /* -R flag disables it */
168 int check_file = 0; /* -X flag enables */
169 int clone_range_calls = 1; /* -J flag disables */
170 int integrity = 0; /* -i flag */
172 int o_direct; /* -Z */
180 int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset);
183 #define fsxread(a,b,c,d) aio_rw(READ, a,b,c,d)
184 #define fsxwrite(a,b,c,d) aio_rw(WRITE, a,b,c,d)
186 #define fsxread(a,b,c,d) read(a,b,c)
187 #define fsxwrite(a,b,c,d) write(a,b,c)
190 const char *replayops = NULL;
191 const char *recordops = NULL;
192 FILE * fsxlogf = NULL;
193 FILE * replayopsf = NULL;
194 char opsfile[PATH_MAX];
198 static void *round_ptr_up(void *ptr, unsigned long align, unsigned long offset)
200 unsigned long ret = (unsigned long)ptr;
202 ret = ((ret + align - 1) & ~(align - 1));
208 vwarnc(int code, const char *fmt, va_list ap)
211 fprintf(stderr, "%s: ", logid);
212 fprintf(stderr, "fsx: ");
214 vfprintf(stderr, fmt, ap);
215 fprintf(stderr, ": ");
217 fprintf(stderr, "%s\n", strerror(code));
221 warn(const char * fmt, ...) {
224 vwarnc(errno, fmt, ap);
229 prt(const char *fmt, ...)
234 fprintf(stdout, "%s: ", logid);
236 vfprintf(stdout, fmt, args);
240 vfprintf(fsxlogf, fmt, args);
246 prterr(const char *prefix)
248 prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
252 static const char *op_names[] = {
254 [OP_WRITE] = "write",
255 [OP_MAPREAD] = "mapread",
256 [OP_MAPWRITE] = "mapwrite",
257 [OP_TRUNCATE] = "truncate",
258 [OP_FALLOCATE] = "fallocate",
259 [OP_PUNCH_HOLE] = "punch_hole",
260 [OP_ZERO_RANGE] = "zero_range",
261 [OP_COLLAPSE_RANGE] = "collapse_range",
262 [OP_INSERT_RANGE] = "insert_range",
263 [OP_CLONE_RANGE] = "clone_range",
264 [OP_FSYNC] = "fsync",
267 static const char *op_name(int operation)
269 if (operation >= 0 &&
270 operation < sizeof(op_names) / sizeof(op_names[0]))
271 return op_names[operation];
275 static int op_code(const char *name)
279 for (i = 0; i < sizeof(op_names) / sizeof(op_names[0]); i++)
280 if (op_names[i] && strcmp(name, op_names[i]) == 0)
286 log5(int operation, int arg0, int arg1, int arg2, enum opflags flags)
288 struct log_entry *le;
291 le->operation = operation;
293 flags |= FL_CLOSE_OPEN;
297 le->args[3] = file_size;
302 if (logptr >= LOGSIZE)
307 log4(int operation, int arg0, int arg1, enum opflags flags)
309 struct log_entry *le;
312 le->operation = operation;
314 flags |= FL_CLOSE_OPEN;
317 le->args[2] = file_size;
322 if (logptr >= LOGSIZE)
331 struct log_entry *lp;
333 prt("LOG DUMP (%d total operations):\n", logcount);
335 logopsf = fopen(opsfile, "w");
339 if (logcount < LOGSIZE) {
346 for ( ; count > 0; count--) {
347 bool overlap, overlap2;
350 opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
351 prt("%d(%3d mod 256): ", opnum, opnum%256);
354 overlap = badoff >= lp->args[0] &&
355 badoff < lp->args[0] + lp->args[1];
357 if (lp->flags & FL_SKIPPED) {
358 prt("SKIPPED (no operation)");
362 switch (lp->operation) {
364 prt("MAPREAD 0x%x thru 0x%x\t(0x%x bytes)",
365 lp->args[0], lp->args[0] + lp->args[1] - 1,
371 prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
372 lp->args[0], lp->args[0] + lp->args[1] - 1,
378 prt("READ 0x%x thru 0x%x\t(0x%x bytes)",
379 lp->args[0], lp->args[0] + lp->args[1] - 1,
385 prt("WRITE 0x%x thru 0x%x\t(0x%x bytes)",
386 lp->args[0], lp->args[0] + lp->args[1] - 1,
388 if (lp->args[0] > lp->args[2])
390 else if (lp->args[0] + lp->args[1] > lp->args[2])
392 overlap = (badoff >= lp->args[0] ||
393 badoff >=lp->args[2]) &&
394 badoff < lp->args[0] + lp->args[1];
399 down = lp->args[1] < lp->args[2];
400 prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
401 down ? "DOWN" : "UP", lp->args[2], lp->args[1]);
402 overlap = badoff >= lp->args[1 + !down] &&
403 badoff < lp->args[1 + !!down];
408 /* 0: offset 1: length 2: where alloced */
409 prt("FALLOC 0x%x thru 0x%x\t(0x%x bytes) ",
410 lp->args[0], lp->args[0] + lp->args[1],
412 if (lp->args[0] + lp->args[1] <= lp->args[2])
414 else if (lp->flags & FL_KEEP_SIZE)
422 prt("PUNCH 0x%x thru 0x%x\t(0x%x bytes)",
423 lp->args[0], lp->args[0] + lp->args[1] - 1,
429 prt("ZERO 0x%x thru 0x%x\t(0x%x bytes)",
430 lp->args[0], lp->args[0] + lp->args[1] - 1,
435 case OP_COLLAPSE_RANGE:
436 prt("COLLAPSE 0x%x thru 0x%x\t(0x%x bytes)",
437 lp->args[0], lp->args[0] + lp->args[1] - 1,
442 case OP_INSERT_RANGE:
443 prt("INSERT 0x%x thru 0x%x\t(0x%x bytes)",
444 lp->args[0], lp->args[0] + lp->args[1] - 1,
450 prt("CLONE 0x%x thru 0x%x\t(0x%x bytes) to 0x%x thru 0x%x",
451 lp->args[0], lp->args[0] + lp->args[1] - 1,
453 lp->args[2], lp->args[2] + lp->args[1] - 1);
454 overlap2 = badoff >= lp->args[2] &&
455 badoff < lp->args[2] + lp->args[1];
456 if (overlap && overlap2)
467 prt("BOGUS LOG ENTRY (operation code = %d)!",
473 if (lp->flags & FL_CLOSE_OPEN)
474 prt("\n\t\tCLOSE/OPEN");
483 if (lp->flags & FL_SKIPPED)
484 fprintf(logopsf, "skip ");
485 fprintf(logopsf, "%s", op_name(lp->operation));
486 for (j = 0; j < lp->nr_args; j++)
487 fprintf(logopsf, " 0x%x", lp->args[j]);
488 if (lp->flags & FL_KEEP_SIZE)
489 fprintf(logopsf, " keep_size");
490 if (lp->flags & FL_CLOSE_OPEN)
491 fprintf(logopsf, " close_open");
493 fprintf(logopsf, " *");
494 fprintf(logopsf, "\n");
499 if (fclose(logopsf) != 0)
502 prt("Log of operations saved to \"%s\"; "
503 "replay with --replay-ops\n",
510 save_buffer(char *buffer, off_t bufferlength, int fd)
513 ssize_t byteswritten;
515 if (fd <= 0 || bufferlength == 0)
518 if (bufferlength > SSIZE_MAX) {
519 prt("fsx flaw: overflow in save_buffer\n");
523 off_t size_by_seek = lseek(fd, (off_t)0, SEEK_END);
524 if (size_by_seek == (off_t)-1)
525 prterr("save_buffer: lseek eof");
526 else if (bufferlength > size_by_seek) {
527 warn("save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek,
528 (unsigned long long)bufferlength);
529 bufferlength = size_by_seek;
533 ret = lseek(fd, (off_t)0, SEEK_SET);
534 if (ret == (off_t)-1)
535 prterr("save_buffer: lseek 0");
537 byteswritten = write(fd, buffer, (size_t)bufferlength);
538 if (byteswritten != bufferlength) {
539 if (byteswritten == -1)
540 prterr("save_buffer write");
542 warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n",
543 (unsigned)byteswritten,
544 (unsigned long long)bufferlength);
550 report_failure(int status)
556 save_buffer(good_buf, file_size, fsxgoodfd);
557 prt("Correct content saved for comparison\n");
558 prt("(maybe hexdump \"%s\" vs \"%s\")\n",
567 #define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
568 *(((unsigned char *)(cp)) + 1)))
576 snprintf(command, 256, "dmsetup message %s 0 mark %s.mark%d", logdev,
578 ret = system(command);
580 prterr("dmsetup mark failed");
586 dump_fsync_buffer(void)
588 char fname_buffer[PATH_MAX];
594 snprintf(fname_buffer, sizeof(fname_buffer), "%s%s.mark%d", dname,
596 good_fd = open(fname_buffer, O_WRONLY|O_CREAT|O_TRUNC, 0666);
598 prterr(fname_buffer);
602 save_buffer(good_buf, file_size, good_fd);
604 prt("Dumped fsync buffer to %s\n", fname_buffer + dirpath);
608 check_buffers(char *buf, unsigned offset, unsigned size)
616 if (memcmp(good_buf + offset, buf, size) != 0) {
617 prt("READ BAD DATA: offset = 0x%x, size = 0x%x, fname = %s\n",
618 offset, size, fname);
619 prt("OFFSET\tGOOD\tBAD\tRANGE\n");
621 c = good_buf[offset];
625 bad = short_at(&buf[i]);
626 prt("0x%05x\t0x%04x\t0x%04x", offset,
627 short_at(&good_buf[offset]), bad);
628 op = buf[offset & 1 ? i+1 : i];
629 prt("\t0x%05x\n", n);
631 prt("operation# (mod 256) for "
632 "the bad data may be %u\n",
633 ((unsigned)op & 0xff));
635 prt("operation# (mod 256) for "
636 "the bad data unknown, check"
637 " HOLE and EXTEND ops\n");
657 if (fstat(fd, &statbuf)) {
658 prterr("check_size: fstat");
659 statbuf.st_size = -1;
661 size_by_seek = lseek(fd, (off_t)0, SEEK_END);
662 if (file_size != statbuf.st_size || file_size != size_by_seek) {
663 prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n",
664 (unsigned long long)file_size,
665 (unsigned long long)statbuf.st_size,
666 (unsigned long long)size_by_seek);
673 check_trunc_hack(void)
676 off_t offset = file_size + (off_t)100000;
678 if (ftruncate(fd, file_size))
680 if (ftruncate(fd, offset))
683 if (statbuf.st_size != offset) {
684 prt("no extend on truncate! not posix!\n");
687 if (ftruncate(fd, file_size)) {
689 prterr("check_trunc_hack: ftruncate");
695 doflush(unsigned offset, unsigned size)
701 if (o_direct == O_DIRECT)
704 pg_offset = offset & mmap_mask;
705 map_size = pg_offset + size;
707 if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
708 MAP_FILE | MAP_SHARED, fd,
709 (off_t)(offset - pg_offset))) == (char *)-1) {
710 prterr("doflush: mmap");
713 if (msync(p, map_size, MS_INVALIDATE) != 0) {
714 prterr("doflush: msync");
717 if (munmap(p, map_size) != 0) {
718 prterr("doflush: munmap");
724 doread(unsigned offset, unsigned size)
729 offset -= offset % readbdy;
731 size -= size % readbdy;
733 if (!quiet && testcalls > simulatedopcount && !o_direct)
734 prt("skipping zero size read\n");
735 log4(OP_READ, offset, size, FL_SKIPPED);
738 if (size + offset > file_size) {
739 if (!quiet && testcalls > simulatedopcount)
740 prt("skipping seek/read past end of file\n");
741 log4(OP_READ, offset, size, FL_SKIPPED);
745 log4(OP_READ, offset, size, FL_NONE);
747 if (testcalls <= simulatedopcount)
751 ((progressinterval && testcalls % progressinterval == 0) ||
753 (monitorstart == -1 ||
754 (offset + size > monitorstart &&
755 (monitorend == -1 || offset <= monitorend))))))
756 prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
757 offset, offset + size - 1, size);
758 ret = lseek(fd, (off_t)offset, SEEK_SET);
759 if (ret == (off_t)-1) {
760 prterr("doread: lseek");
763 iret = fsxread(fd, temp_buf, size, offset);
766 prterr("doread: read");
768 prt("short read: 0x%x bytes instead of 0x%x\n",
772 check_buffers(temp_buf, offset, size);
776 check_eofpage(char *s, unsigned offset, char *p, int size)
778 unsigned long last_page, should_be_zero;
780 if (offset + size <= (file_size & ~page_mask))
783 * we landed in the last page of the file
784 * test to make sure the VM system provided 0's
785 * beyond the true end of the file mapping
786 * (as required by mmap def in 1996 posix 1003.1)
788 last_page = ((unsigned long)p + (offset & page_mask) + size) & ~page_mask;
790 for (should_be_zero = last_page + (file_size & page_mask);
791 should_be_zero < last_page + page_size;
793 if (*(char *)should_be_zero) {
794 prt("Mapped %s: non-zero data past EOF (0x%llx) page offset 0x%x is 0x%04x\n",
795 s, file_size - 1, should_be_zero & page_mask,
796 short_at(should_be_zero));
804 static char *check_buf;
806 unsigned size = file_size;
814 check_buf = (char *) malloc(maxfilelen + writebdy);
815 assert(check_buf != NULL);
816 check_buf = round_ptr_up(check_buf, writebdy, 0);
817 memset(check_buf, '\0', maxfilelen);
821 size -= size % readbdy;
825 ret = lseek(fd, (off_t)offset, SEEK_SET);
826 if (ret == (off_t)-1) {
827 prterr("doread: lseek");
831 iret = fsxread(fd, check_buf, size, offset);
834 prterr("check_contents: read");
836 prt("short check read: 0x%x bytes instead of 0x%x\n",
840 check_buffers(check_buf, offset, size);
842 /* Map eof page, check it */
843 map_offset = size - (size & PAGE_MASK);
844 if (map_offset == size)
845 map_offset -= PAGE_SIZE;
846 map_size = size - map_offset;
848 p = mmap(0, map_size, PROT_READ, MAP_SHARED, fd, map_offset);
849 if (p == MAP_FAILED) {
850 prterr("check_contents: mmap");
853 check_eofpage("check_contents", map_offset, p, map_size);
855 if (munmap(p, map_size) != 0) {
856 prterr("check_contents: munmap");
862 domapread(unsigned offset, unsigned size)
868 offset -= offset % readbdy;
870 if (!quiet && testcalls > simulatedopcount)
871 prt("skipping zero size read\n");
872 log4(OP_MAPREAD, offset, size, FL_SKIPPED);
875 if (size + offset > file_size) {
876 if (!quiet && testcalls > simulatedopcount)
877 prt("skipping seek/read past end of file\n");
878 log4(OP_MAPREAD, offset, size, FL_SKIPPED);
882 log4(OP_MAPREAD, offset, size, FL_NONE);
884 if (testcalls <= simulatedopcount)
888 ((progressinterval && testcalls % progressinterval == 0) ||
890 (monitorstart == -1 ||
891 (offset + size > monitorstart &&
892 (monitorend == -1 || offset <= monitorend))))))
893 prt("%lu mapread\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
894 offset, offset + size - 1, size);
896 pg_offset = offset & PAGE_MASK;
897 map_size = pg_offset + size;
899 if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_SHARED, fd,
900 (off_t)(offset - pg_offset))) == (char *)-1) {
901 prterr("domapread: mmap");
904 memcpy(temp_buf, p + pg_offset, size);
906 check_eofpage("Read", offset, p, size);
908 if (munmap(p, map_size) != 0) {
909 prterr("domapread: munmap");
913 check_buffers(temp_buf, offset, size);
918 gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
922 good_buf[offset] = filldata;
924 good_buf[offset] = testcalls % 256;
926 good_buf[offset] += original_buf[offset];
934 dowrite(unsigned offset, unsigned size)
939 offset -= offset % writebdy;
941 size -= size % writebdy;
943 if (!quiet && testcalls > simulatedopcount && !o_direct)
944 prt("skipping zero size write\n");
945 log4(OP_WRITE, offset, size, FL_SKIPPED);
949 log4(OP_WRITE, offset, size, FL_NONE);
951 gendata(original_buf, good_buf, offset, size);
952 if (file_size < offset + size) {
953 if (file_size < offset)
954 memset(good_buf + file_size, '\0', offset - file_size);
955 file_size = offset + size;
957 warn("Lite file size bug in fsx!");
962 if (testcalls <= simulatedopcount)
966 ((progressinterval && testcalls % progressinterval == 0) ||
968 (monitorstart == -1 ||
969 (offset + size > monitorstart &&
970 (monitorend == -1 || offset <= monitorend))))))
971 prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
972 offset, offset + size - 1, size);
973 ret = lseek(fd, (off_t)offset, SEEK_SET);
974 if (ret == (off_t)-1) {
975 prterr("dowrite: lseek");
978 iret = fsxwrite(fd, good_buf + offset, size, offset);
981 prterr("dowrite: write");
983 prt("short write: 0x%x bytes instead of 0x%x\n",
989 prt("fsync() failed: %s\n", strerror(errno));
994 doflush(offset, size);
1000 domapwrite(unsigned offset, unsigned size)
1007 offset -= offset % writebdy;
1009 if (!quiet && testcalls > simulatedopcount)
1010 prt("skipping zero size write\n");
1011 log4(OP_MAPWRITE, offset, size, FL_SKIPPED);
1014 cur_filesize = file_size;
1016 log4(OP_MAPWRITE, offset, size, FL_NONE);
1018 gendata(original_buf, good_buf, offset, size);
1019 if (file_size < offset + size) {
1020 if (file_size < offset)
1021 memset(good_buf + file_size, '\0', offset - file_size);
1022 file_size = offset + size;
1024 warn("Lite file size bug in fsx!");
1025 report_failure(200);
1029 if (testcalls <= simulatedopcount)
1033 ((progressinterval && testcalls % progressinterval == 0) ||
1035 (monitorstart == -1 ||
1036 (offset + size > monitorstart &&
1037 (monitorend == -1 || offset <= monitorend))))))
1038 prt("%lu mapwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
1039 offset, offset + size - 1, size);
1041 if (file_size > cur_filesize) {
1042 if (ftruncate(fd, file_size) == -1) {
1043 prterr("domapwrite: ftruncate");
1047 pg_offset = offset & PAGE_MASK;
1048 map_size = pg_offset + size;
1050 if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
1051 MAP_FILE | MAP_SHARED, fd,
1052 (off_t)(offset - pg_offset))) == (char *)-1) {
1053 prterr("domapwrite: mmap");
1054 report_failure(202);
1056 memcpy(p + pg_offset, good_buf + offset, size);
1057 if (msync(p, map_size, MS_SYNC) != 0) {
1058 prterr("domapwrite: msync");
1059 report_failure(203);
1062 check_eofpage("Write", offset, p, size);
1064 if (munmap(p, map_size) != 0) {
1065 prterr("domapwrite: munmap");
1066 report_failure(204);
1072 dotruncate(unsigned size)
1074 int oldsize = file_size;
1076 size -= size % truncbdy;
1077 if (size > biggest) {
1079 if (!quiet && testcalls > simulatedopcount)
1080 prt("truncating to largest ever: 0x%x\n", size);
1083 log4(OP_TRUNCATE, 0, size, FL_NONE);
1085 if (size > file_size)
1086 memset(good_buf + file_size, '\0', size - file_size);
1089 if (testcalls <= simulatedopcount)
1092 if ((progressinterval && testcalls % progressinterval == 0) ||
1093 (debug && (monitorstart == -1 || monitorend == -1 ||
1094 size <= monitorend)))
1095 prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
1096 if (ftruncate(fd, (off_t)size) == -1) {
1097 prt("ftruncate1: %x\n", size);
1098 prterr("dotruncate: ftruncate");
1099 report_failure(160);
1103 #ifdef FALLOC_FL_PUNCH_HOLE
1105 do_punch_hole(unsigned offset, unsigned length)
1107 unsigned end_offset;
1110 int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
1113 if (!quiet && testcalls > simulatedopcount)
1114 prt("skipping zero length punch hole\n");
1115 log4(OP_PUNCH_HOLE, offset, length, FL_SKIPPED);
1119 if (file_size <= (loff_t)offset) {
1120 if (!quiet && testcalls > simulatedopcount)
1121 prt("skipping hole punch off the end of the file\n");
1122 log4(OP_PUNCH_HOLE, offset, length, FL_SKIPPED);
1126 end_offset = offset + length;
1128 log4(OP_PUNCH_HOLE, offset, length, FL_NONE);
1130 if (testcalls <= simulatedopcount)
1133 if ((progressinterval && testcalls % progressinterval == 0) ||
1134 (debug && (monitorstart == -1 || monitorend == -1 ||
1135 end_offset <= monitorend))) {
1136 prt("%lu punch\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls,
1137 offset, offset+length, length);
1139 if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
1140 prt("punch hole: 0x%x to 0x%x\n", offset, offset + length);
1141 prterr("do_punch_hole: fallocate");
1142 report_failure(161);
1146 max_offset = offset < file_size ? offset : file_size;
1147 max_len = max_offset + length <= file_size ? length :
1148 file_size - max_offset;
1149 memset(good_buf + max_offset, '\0', max_len);
1154 do_punch_hole(unsigned offset, unsigned length)
1160 #ifdef FALLOC_FL_ZERO_RANGE
1162 do_zero_range(unsigned offset, unsigned length, int keep_size)
1164 unsigned end_offset;
1165 int mode = FALLOC_FL_ZERO_RANGE;
1168 if (!quiet && testcalls > simulatedopcount)
1169 prt("skipping zero length zero range\n");
1170 log4(OP_ZERO_RANGE, offset, length, FL_SKIPPED |
1171 (keep_size ? FL_KEEP_SIZE : FL_NONE));
1175 end_offset = keep_size ? 0 : offset + length;
1177 if (end_offset > biggest) {
1178 biggest = end_offset;
1179 if (!quiet && testcalls > simulatedopcount)
1180 prt("zero_range to largest ever: 0x%x\n", end_offset);
1184 * last arg matches fallocate string array index in logdump:
1185 * 0: allocate past EOF
1186 * 1: extending prealloc
1187 * 2: interior prealloc
1189 log4(OP_ZERO_RANGE, offset, length,
1190 keep_size ? FL_KEEP_SIZE : FL_NONE);
1192 if (testcalls <= simulatedopcount)
1195 if ((progressinterval && testcalls % progressinterval == 0) ||
1196 (debug && (monitorstart == -1 || monitorend == -1 ||
1197 end_offset <= monitorend))) {
1198 prt("%lu zero\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls,
1199 offset, offset+length, length);
1201 if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
1202 prt("zero range: 0x%x to 0x%x\n", offset, offset + length);
1203 prterr("do_zero_range: fallocate");
1204 report_failure(161);
1207 memset(good_buf + offset, '\0', length);
1212 do_zero_range(unsigned offset, unsigned length, int keep_size)
1218 #ifdef FALLOC_FL_COLLAPSE_RANGE
1220 do_collapse_range(unsigned offset, unsigned length)
1222 unsigned end_offset;
1223 int mode = FALLOC_FL_COLLAPSE_RANGE;
1226 if (!quiet && testcalls > simulatedopcount)
1227 prt("skipping zero length collapse range\n");
1228 log4(OP_COLLAPSE_RANGE, offset, length, FL_SKIPPED);
1232 end_offset = offset + length;
1233 if ((loff_t)end_offset >= file_size) {
1234 if (!quiet && testcalls > simulatedopcount)
1235 prt("skipping collapse range behind EOF\n");
1236 log4(OP_COLLAPSE_RANGE, offset, length, FL_SKIPPED);
1240 log4(OP_COLLAPSE_RANGE, offset, length, FL_NONE);
1242 if (testcalls <= simulatedopcount)
1245 if ((progressinterval && testcalls % progressinterval == 0) ||
1246 (debug && (monitorstart == -1 || monitorend == -1 ||
1247 end_offset <= monitorend))) {
1248 prt("%lu collapse\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls,
1249 offset, offset+length, length);
1251 if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
1252 prt("collapse range: 0x%x to 0x%x\n", offset, offset + length);
1253 prterr("do_collapse_range: fallocate");
1254 report_failure(161);
1257 memmove(good_buf + offset, good_buf + end_offset,
1258 file_size - end_offset);
1259 file_size -= length;
1264 do_collapse_range(unsigned offset, unsigned length)
1270 #ifdef FALLOC_FL_INSERT_RANGE
1272 do_insert_range(unsigned offset, unsigned length)
1274 unsigned end_offset;
1275 int mode = FALLOC_FL_INSERT_RANGE;
1278 if (!quiet && testcalls > simulatedopcount)
1279 prt("skipping zero length insert range\n");
1280 log4(OP_INSERT_RANGE, offset, length, FL_SKIPPED);
1284 if ((loff_t)offset >= file_size) {
1285 if (!quiet && testcalls > simulatedopcount)
1286 prt("skipping insert range behind EOF\n");
1287 log4(OP_INSERT_RANGE, offset, length, FL_SKIPPED);
1291 log4(OP_INSERT_RANGE, offset, length, FL_NONE);
1293 if (testcalls <= simulatedopcount)
1296 end_offset = offset + length;
1297 if ((progressinterval && testcalls % progressinterval == 0) ||
1298 (debug && (monitorstart == -1 || monitorend == -1 ||
1299 end_offset <= monitorend))) {
1300 prt("%lu insert\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls,
1301 offset, offset+length, length);
1303 if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
1304 prt("insert range: 0x%x to 0x%x\n", offset, offset + length);
1305 prterr("do_insert_range: fallocate");
1306 report_failure(161);
1309 memmove(good_buf + end_offset, good_buf + offset,
1310 file_size - offset);
1311 memset(good_buf + offset, '\0', length);
1312 file_size += length;
1317 do_insert_range(unsigned offset, unsigned length)
1325 test_clone_range(void)
1327 struct file_clone_range fcr = {
1331 if (ioctl(fd, FICLONERANGE, &fcr) &&
1332 (errno = EOPNOTSUPP || errno == ENOTTY)) {
1335 "main: filesystem does not support "
1336 "clone range, disabling!\n");
1344 do_clone_range(unsigned offset, unsigned length, unsigned dest)
1346 struct file_clone_range fcr = {
1348 .src_offset = offset,
1349 .src_length = length,
1350 .dest_offset = dest,
1354 if (!quiet && testcalls > simulatedopcount)
1355 prt("skipping zero length clone range\n");
1356 log5(OP_CLONE_RANGE, offset, length, dest, FL_SKIPPED);
1360 if ((loff_t)offset >= file_size) {
1361 if (!quiet && testcalls > simulatedopcount)
1362 prt("skipping clone range behind EOF\n");
1363 log5(OP_CLONE_RANGE, offset, length, dest, FL_SKIPPED);
1367 if (dest + length > biggest) {
1368 biggest = dest + length;
1369 if (!quiet && testcalls > simulatedopcount)
1370 prt("cloning to largest ever: 0x%x\n", dest + length);
1373 log5(OP_CLONE_RANGE, offset, length, dest, FL_NONE);
1375 if (testcalls <= simulatedopcount)
1378 if ((progressinterval && testcalls % progressinterval == 0) ||
1379 (debug && (monitorstart == -1 || monitorend == -1 ||
1380 dest <= monitorstart || dest + length <= monitorend))) {
1381 prt("%lu clone\tfrom 0x%x to 0x%x, (0x%x bytes) at 0x%x\n",
1382 testcalls, offset, offset+length, length, dest);
1385 if (ioctl(fd, FICLONERANGE, &fcr) == -1) {
1386 prt("clone range: 0x%x to 0x%x at 0x%x\n", offset,
1387 offset + length, dest);
1388 prterr("do_clone_range: FICLONERANGE");
1389 report_failure(161);
1392 memcpy(good_buf + dest, good_buf + offset, length);
1393 if (dest > file_size)
1394 memset(good_buf + file_size, '\0', dest - file_size);
1395 if (dest + length > file_size)
1396 file_size = dest + length;
1401 test_clone_range(void)
1407 do_clone_range(unsigned offset, unsigned length, unsigned dest)
1413 #ifdef HAVE_LINUX_FALLOC_H
1414 /* fallocate is basically a no-op unless extending, then a lot like a truncate */
1416 do_preallocate(unsigned offset, unsigned length, int keep_size)
1418 unsigned end_offset;
1421 if (!quiet && testcalls > simulatedopcount)
1422 prt("skipping zero length fallocate\n");
1423 log4(OP_FALLOCATE, offset, length, FL_SKIPPED |
1424 (keep_size ? FL_KEEP_SIZE : FL_NONE));
1428 end_offset = keep_size ? 0 : offset + length;
1430 if (end_offset > biggest) {
1431 biggest = end_offset;
1432 if (!quiet && testcalls > simulatedopcount)
1433 prt("fallocating to largest ever: 0x%x\n", end_offset);
1437 * last arg matches fallocate string array index in logdump:
1438 * 0: allocate past EOF
1439 * 1: extending prealloc
1440 * 2: interior prealloc
1442 log4(OP_FALLOCATE, offset, length,
1443 keep_size ? FL_KEEP_SIZE : FL_NONE);
1445 if (end_offset > file_size) {
1446 memset(good_buf + file_size, '\0', end_offset - file_size);
1447 file_size = end_offset;
1450 if (testcalls <= simulatedopcount)
1453 if ((progressinterval && testcalls % progressinterval == 0) ||
1454 (debug && (monitorstart == -1 || monitorend == -1 ||
1455 end_offset <= monitorend)))
1456 prt("%lu falloc\tfrom 0x%x to 0x%x (0x%x bytes)\n", testcalls,
1457 offset, offset + length, length);
1458 if (fallocate(fd, keep_size ? FALLOC_FL_KEEP_SIZE : 0, (loff_t)offset, (loff_t)length) == -1) {
1459 prt("fallocate: 0x%x to 0x%x\n", offset, offset + length);
1460 prterr("do_preallocate: fallocate");
1461 report_failure(161);
1466 do_preallocate(unsigned offset, unsigned length, int keep_size)
1477 if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
1478 prterr("writefileimage: lseek");
1479 report_failure(171);
1481 iret = write(fd, good_buf, file_size);
1482 if ((off_t)iret != file_size) {
1484 prterr("writefileimage: write");
1486 prt("short write: 0x%x bytes instead of 0x%llx\n",
1487 iret, (unsigned long long)file_size);
1488 report_failure(172);
1490 if (lite ? 0 : ftruncate(fd, file_size) == -1) {
1491 prt("ftruncate2: %llx\n", (unsigned long long)file_size);
1492 prterr("writefileimage: ftruncate");
1493 report_failure(173);
1501 if (testcalls <= simulatedopcount)
1505 prt("%lu close/open\n", testcalls);
1507 prterr("docloseopen: close");
1508 report_failure(180);
1510 fd = open(fname, O_RDWR|o_direct, 0);
1512 prterr("docloseopen: open");
1513 report_failure(181);
1522 if (testcalls <= simulatedopcount)
1525 prt("%lu fsync\n", testcalls);
1526 log4(OP_FSYNC, 0, 0, 0);
1530 report_failure(210);
1533 dump_fsync_buffer();
1537 #define TRIM_OFF(off, size) \
1545 #define TRIM_LEN(off, len, size) \
1547 if ((off) + (len) > (size)) \
1548 (len) = (size) - (off); \
1551 #define TRIM_OFF_LEN(off, len, size) \
1553 TRIM_OFF(off, size); \
1554 TRIM_LEN(off, len, size); \
1561 prt("signal %d\n", sig);
1562 prt("testcalls = %lu\n", testcalls);
1567 op_args_count(int operation)
1569 switch (operation) {
1570 case OP_CLONE_RANGE:
1578 read_op(struct log_entry *log_entry)
1582 memset(log_entry, 0, sizeof(*log_entry));
1583 log_entry->operation = -1;
1585 while (log_entry->operation == -1) {
1590 if (!fgets(line, sizeof(line), replayopsf)) {
1591 if (feof(replayopsf)) {
1597 str = strtok(line, " \t\n");
1598 } while (!str || str[0] == '#');
1600 if (strcmp(str, "skip") == 0) {
1601 log_entry->flags |= FL_SKIPPED;
1602 str = strtok(NULL, " \t\n");
1606 log_entry->operation = op_code(str);
1607 if (log_entry->operation == -1)
1609 log_entry->nr_args = op_args_count(log_entry->operation);
1610 for (i = 0; i < log_entry->nr_args; i++) {
1613 str = strtok(NULL, " \t\n");
1616 log_entry->args[i] = strtoul(str, &end, 0);
1620 while ((str = strtok(NULL, " \t\n"))) {
1621 if (strcmp(str, "keep_size") == 0)
1622 log_entry->flags |= FL_KEEP_SIZE;
1623 else if (strcmp(str, "close_open") == 0)
1624 log_entry->flags |= FL_CLOSE_OPEN;
1625 else if (strcmp(str, "*") == 0)
1626 ; /* overlap marker; ignore */
1634 fprintf(stderr, "%s: parse error\n", replayops);
1637 cleanup(100); /* doesn't return */
1645 unsigned long offset, offset2;
1651 if (simulatedopcount > 0 && testcalls == simulatedopcount)
1656 if (debugstart > 0 && testcalls >= debugstart)
1659 if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
1660 prt("%lu...\n", testcalls);
1663 struct log_entry log_entry;
1665 while (read_op(&log_entry)) {
1666 if (log_entry.flags & FL_SKIPPED) {
1667 log4(log_entry.operation,
1668 log_entry.args[0], log_entry.args[1],
1673 op = log_entry.operation;
1674 offset = log_entry.args[0];
1675 size = log_entry.args[1];
1676 offset2 = log_entry.args[2];
1677 closeopen = !!(log_entry.flags & FL_CLOSE_OPEN);
1678 keep_size = !!(log_entry.flags & FL_KEEP_SIZE);
1686 closeopen = (rv >> 3) < (1 << 28) / closeprob;
1692 size = random() % (maxoplen + 1);
1694 /* calculate appropriate op to run */
1696 op = rv % OP_MAX_LITE;
1697 else if (!integrity)
1698 op = rv % OP_MAX_FULL;
1700 op = rv % OP_MAX_INTEGRITY;
1705 size = random() % maxfilelen;
1708 if (fallocate_calls && size && keep_size_calls)
1709 keep_size = random() % 2;
1712 if (zero_range_calls && size && keep_size_calls)
1713 keep_size = random() % 2;
1715 case OP_CLONE_RANGE:
1716 TRIM_OFF_LEN(offset, size, file_size);
1717 offset = offset & ~(block_size - 1);
1718 size = size & ~(block_size - 1);
1721 TRIM_OFF(offset2, maxfilelen);
1722 offset2 = offset2 & ~(block_size - 1);
1723 } while (llabs(offset2 - offset) < size ||
1724 offset2 + size > maxfilelen);
1740 if (!fallocate_calls) {
1741 log4(OP_FALLOCATE, offset, size, FL_SKIPPED);
1746 if (!punch_hole_calls) {
1747 log4(OP_PUNCH_HOLE, offset, size, FL_SKIPPED);
1752 if (!zero_range_calls) {
1753 log4(OP_ZERO_RANGE, offset, size, FL_SKIPPED);
1757 case OP_COLLAPSE_RANGE:
1758 if (!collapse_range_calls) {
1759 log4(OP_COLLAPSE_RANGE, offset, size, FL_SKIPPED);
1763 case OP_INSERT_RANGE:
1764 if (!insert_range_calls) {
1765 log4(OP_INSERT_RANGE, offset, size, FL_SKIPPED);
1769 case OP_CLONE_RANGE:
1770 if (!clone_range_calls) {
1771 log5(op, offset, size, offset2, FL_SKIPPED);
1779 TRIM_OFF_LEN(offset, size, file_size);
1780 doread(offset, size);
1784 TRIM_OFF_LEN(offset, size, maxfilelen);
1785 dowrite(offset, size);
1789 TRIM_OFF_LEN(offset, size, file_size);
1790 domapread(offset, size);
1794 TRIM_OFF_LEN(offset, size, maxfilelen);
1795 domapwrite(offset, size);
1803 TRIM_OFF_LEN(offset, size, maxfilelen);
1804 do_preallocate(offset, size, keep_size);
1808 TRIM_OFF_LEN(offset, size, file_size);
1809 do_punch_hole(offset, size);
1812 TRIM_OFF_LEN(offset, size, file_size);
1813 do_zero_range(offset, size, keep_size);
1815 case OP_COLLAPSE_RANGE:
1816 TRIM_OFF_LEN(offset, size, file_size - 1);
1817 offset = offset & ~(block_size - 1);
1818 size = size & ~(block_size - 1);
1820 log4(OP_COLLAPSE_RANGE, offset, size, FL_SKIPPED);
1823 do_collapse_range(offset, size);
1825 case OP_INSERT_RANGE:
1826 TRIM_OFF(offset, file_size);
1827 TRIM_LEN(file_size, size, maxfilelen);
1828 offset = offset & ~(block_size - 1);
1829 size = size & ~(block_size - 1);
1831 log4(OP_INSERT_RANGE, offset, size, FL_SKIPPED);
1834 if (file_size + size > maxfilelen) {
1835 log4(OP_INSERT_RANGE, offset, size, FL_SKIPPED);
1839 do_insert_range(offset, size);
1841 case OP_CLONE_RANGE:
1843 log5(OP_CLONE_RANGE, offset, size, offset2, FL_SKIPPED);
1846 if (offset2 + size > maxfilelen) {
1847 log5(OP_CLONE_RANGE, offset, size, offset2, FL_SKIPPED);
1851 do_clone_range(offset, size, offset2);
1857 prterr("test: unknown operation");
1862 if (check_file && testcalls > simulatedopcount)
1866 if (sizechecks && testcalls > simulatedopcount)
1877 fprintf(stdout, "usage: %s",
1878 "fsx [-dknqxAFJLOWZ] [-b opnum] [-c Prob] [-g filldata] [-i logdev] [-j logid] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\
1879 -b opnum: beginning operation number (default 1)\n\
1880 -c P: 1 in P chance of file close+open at each op (default infinity)\n\
1881 -d: debug output for all operations\n\
1882 -f flush and invalidate cache after I/O\n\
1883 -g X: write character X instead of random generated data\n\
1884 -i logdev: do integrity testing, logdev is the dm log writes device\n\
1885 -j logid: prefix debug log messsages with this id\n\
1886 -k: do not truncate existing file and use its size as upper bound on file size\n\
1887 -l flen: the upper bound on file size (default 262144)\n\
1888 -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
1889 -n: no verifications of file size\n\
1890 -o oplen: the upper bound on operation size (default 65536)\n\
1891 -p progressinterval: debug output at specified operation interval\n\
1892 -q: quieter operation\n\
1893 -r readbdy: 4096 would make reads page aligned (default 1)\n\
1894 -s style: 1 gives smaller truncates (default 0)\n\
1895 -t truncbdy: 4096 would make truncates page aligned (default 1)\n\
1896 -w writebdy: 4096 would make writes page aligned (default 1)\n\
1897 -x: preallocate file space before starting, XFS only (default 0)\n\
1898 -y synchronize changes to a file\n"
1901 " -A: Use the AIO system calls\n"
1903 " -D startingop: debug output starting at specified operation\n"
1904 #ifdef HAVE_LINUX_FALLOC_H
1905 " -F: Do not use fallocate (preallocation) calls\n"
1907 #ifdef FALLOC_FL_PUNCH_HOLE
1908 " -H: Do not use punch hole calls\n"
1910 #ifdef FALLOC_FL_ZERO_RANGE
1911 " -z: Do not use zero range calls\n"
1913 #ifdef FALLOC_FL_COLLAPSE_RANGE
1914 " -C: Do not use collapse range calls\n"
1916 #ifdef FALLOC_FL_INSERT_RANGE
1917 " -I: Do not use insert range calls\n"
1920 " -J: Do not use clone range calls\n"
1922 " -L: fsxLite - no file creations & no file size changes\n\
1923 -N numops: total # operations to do (default infinity)\n\
1924 -O: use oplen (see -o flag) for every op (default random)\n\
1925 -P: save .fsxlog .fsxops and .fsxgood files in dirpath (default ./)\n\
1926 -S seed: for random # generator (default 1) 0 gets timestamp\n\
1927 -W: mapped write operations DISabled\n\
1928 -X: Read file and compare to good buffer after every operation.\n\
1929 -R: read() system calls only (mapped reads disabled)\n\
1930 -Z: O_DIRECT (use -R, -W, -r and -w too)\n\
1931 --replay-ops opsfile: replay ops from recorded .fsxops file\n\
1932 --record-ops[=opsfile]: dump ops file also on success. optionally specify ops file name\n\
1933 fname: this filename is REQUIRED (no default)\n");
1939 getnum(char *s, char **e)
1944 ret = strtol(s, e, 0);
1974 io_context_t io_ctx;
1980 ret = io_queue_init(QSZ, &io_ctx);
1982 fprintf(stderr, "aio_setup: io_queue_init failed: %s\n",
1990 __aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
1992 struct io_event event;
1993 static struct timespec ts;
1994 struct iocb *iocbs[] = { &iocb };
1999 io_prep_pread(&iocb, fd, buf, len, offset);
2001 io_prep_pwrite(&iocb, fd, buf, len, offset);
2006 ret = io_submit(io_ctx, 1, iocbs);
2008 fprintf(stderr, "errcode=%d\n", ret);
2009 fprintf(stderr, "aio_rw: io_submit failed: %s\n",
2014 ret = io_getevents(io_ctx, 1, 1, &event, &ts);
2017 fprintf(stderr, "aio_rw: no events available\n");
2019 fprintf(stderr, "errcode=%d\n", -ret);
2020 fprintf(stderr, "aio_rw: io_getevents failed: %s\n",
2025 if (len != event.res) {
2027 * The b0rked libaio defines event.res as unsigned.
2028 * However the kernel strucuture has it signed,
2029 * and it's used to pass negated error value.
2030 * Till the library is fixed use the temp var.
2032 res = (long)event.res;
2034 fprintf(stderr, "bad io length: %lu instead of %u\n",
2037 fprintf(stderr, "errcode=%ld\n", -res);
2038 fprintf(stderr, "aio_rw: async io failed: %s\n",
2049 * The caller expects error return in traditional libc
2050 * convention, i.e. -1 and the errno set to error.
2056 int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
2061 ret = __aio_rw(rw, fd, buf, len, offset);
2064 ret = read(fd, buf, len);
2066 ret = write(fd, buf, len);
2073 #define test_fallocate(mode) __test_fallocate(mode, #mode)
2076 __test_fallocate(int mode, const char *mode_str)
2078 #ifdef HAVE_LINUX_FALLOC_H
2081 if (fallocate(fd, mode, file_size, 1) && errno == EOPNOTSUPP) {
2084 "main: filesystem does not support "
2085 "fallocate mode %s, disabling!\n",
2089 if (ftruncate(fd, file_size)) {
2090 warn("main: ftruncate");
2099 static struct option longopts[] = {
2100 {"replay-ops", required_argument, 0, 256},
2101 {"record-ops", optional_argument, 0, 255},
2106 main(int argc, char **argv)
2110 char logfile[PATH_MAX];
2111 struct stat statbuf;
2112 int o_flags = O_RDWR|O_CREAT|O_TRUNC;
2117 page_size = getpagesize();
2118 page_mask = page_size - 1;
2119 mmap_mask = page_mask;
2122 setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
2124 while ((ch = getopt_long(argc, argv,
2125 "b:c:dfg:i:j:kl:m:no:p:qr:s:t:w:xyAD:FJKHzCILN:OP:RS:WXZ",
2126 longopts, NULL)) != EOF)
2129 simulatedopcount = getnum(optarg, &endp);
2131 prt("Will begin at operation %ld\n", simulatedopcount);
2132 if (simulatedopcount == 0)
2134 simulatedopcount -= 1;
2137 closeprob = getnum(optarg, &endp);
2139 prt("Chance of close/open is 1 in %d\n", closeprob);
2154 logdev = strdup(optarg);
2161 logid = strdup(optarg);
2168 o_flags &= ~O_TRUNC;
2171 maxfilelen = getnum(optarg, &endp);
2172 if (maxfilelen <= 0)
2176 monitorstart = getnum(optarg, &endp);
2177 if (monitorstart < 0)
2179 if (!endp || *endp++ != ':')
2181 monitorend = getnum(endp, &endp);
2184 if (monitorend == 0)
2185 monitorend = -1; /* aka infinity */
2191 maxoplen = getnum(optarg, &endp);
2196 progressinterval = getnum(optarg, &endp);
2197 if (progressinterval == 0)
2204 readbdy = getnum(optarg, &endp);
2209 style = getnum(optarg, &endp);
2210 if (style < 0 || style > 1)
2214 truncbdy = getnum(optarg, &endp);
2219 writebdy = getnum(optarg, &endp);
2233 debugstart = getnum(optarg, &endp);
2238 fallocate_calls = 0;
2241 keep_size_calls = 0;
2244 punch_hole_calls = 0;
2247 zero_range_calls = 0;
2250 collapse_range_calls = 0;
2253 insert_range_calls = 0;
2256 clone_range_calls = 0;
2260 o_flags &= ~(O_CREAT|O_TRUNC);
2263 numops = getnum(optarg, &endp);
2271 strncpy(dname, optarg, sizeof(dname));
2273 dirpath = strlen(dname);
2279 seed = getnum(optarg, &endp);
2281 seed = time(0) % 10000;
2282 seed += (int)getpid();
2290 prt("mapped writes DISABLED\n");
2296 o_direct = O_DIRECT;
2297 o_flags |= O_DIRECT;
2299 case 255: /* --record-ops */
2301 strncpy(opsfile, optarg, sizeof(opsfile));
2302 recordops = opsfile;
2304 case 256: /* --replay-ops */
2316 if (integrity && !dirpath) {
2317 fprintf(stderr, "option -i <logdev> requires -P <dirpath>\n");
2322 tmp = strdup(fname);
2327 bname = basename(tmp);
2329 signal(SIGHUP, cleanup);
2330 signal(SIGINT, cleanup);
2331 signal(SIGPIPE, cleanup);
2332 signal(SIGALRM, cleanup);
2333 signal(SIGTERM, cleanup);
2334 signal(SIGXCPU, cleanup);
2335 signal(SIGXFSZ, cleanup);
2336 signal(SIGVTALRM, cleanup);
2337 signal(SIGUSR1, cleanup);
2338 signal(SIGUSR2, cleanup);
2341 prt("Seed set to %d\n", seed);
2343 fd = open(fname, o_flags, 0666);
2348 if (fstat(fd, &statbuf)) {
2349 prterr("check_size: fstat");
2352 block_size = statbuf.st_blksize;
2355 xfs_flock64_t resv = { 0 };
2356 #ifdef HAVE_XFS_PLATFORM_DEFS_H
2357 if (!platform_test_xfs_fd(fd)) {
2359 fprintf(stderr, "main: cannot prealloc, non XFS\n");
2363 resv.l_len = maxfilelen;
2364 if ((xfsctl(fname, fd, XFS_IOC_RESVSP, &resv)) < 0) {
2372 snprintf(goodfile, sizeof(goodfile), "%s%s.fsxgood", dname, bname);
2373 snprintf(logfile, sizeof(logfile), "%s%s.fsxlog", dname, bname);
2375 snprintf(opsfile, sizeof(opsfile), "%s%s.fsxops", dname, bname);
2377 snprintf(goodfile, sizeof(goodfile), "%s.fsxgood", fname);
2378 snprintf(logfile, sizeof(logfile), "%s.fsxlog", fname);
2380 snprintf(opsfile, sizeof(opsfile), "%s.fsxops", fname);
2382 fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
2383 if (fsxgoodfd < 0) {
2387 fsxlogf = fopen(logfile, "w");
2388 if (fsxlogf == NULL) {
2395 replayopsf = fopen(replayops, "r");
2407 if (!(o_flags & O_TRUNC)) {
2409 file_size = maxfilelen = biggest = lseek(fd, (off_t)0, SEEK_END);
2410 if (file_size == (off_t)-1) {
2412 warn("main: lseek eof");
2415 ret = lseek(fd, (off_t)0, SEEK_SET);
2416 if (ret == (off_t)-1) {
2418 warn("main: lseek 0");
2422 original_buf = (char *) malloc(maxfilelen);
2423 for (i = 0; i < maxfilelen; i++)
2424 original_buf[i] = random() % 256;
2425 good_buf = (char *) malloc(maxfilelen + writebdy);
2426 good_buf = round_ptr_up(good_buf, writebdy, 0);
2427 memset(good_buf, '\0', maxfilelen);
2428 temp_buf = (char *) malloc(maxoplen + readbdy);
2429 temp_buf = round_ptr_up(temp_buf, readbdy, 0);
2430 memset(temp_buf, '\0', maxoplen);
2431 if (lite) { /* zero entire existing file */
2434 written = write(fd, good_buf, (size_t)maxfilelen);
2435 if (written != maxfilelen) {
2436 if (written == -1) {
2438 warn("main: error on write");
2440 warn("main: short write, 0x%x bytes instead "
2447 ssize_t ret, len = file_size;
2451 ret = read(fd, good_buf + off, len);
2454 warn("main: error on read");
2464 if (fallocate_calls)
2465 fallocate_calls = test_fallocate(0);
2466 if (keep_size_calls)
2467 keep_size_calls = test_fallocate(FALLOC_FL_KEEP_SIZE);
2468 if (punch_hole_calls)
2469 punch_hole_calls = test_fallocate(FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE);
2470 if (zero_range_calls)
2471 zero_range_calls = test_fallocate(FALLOC_FL_ZERO_RANGE);
2472 if (collapse_range_calls)
2473 collapse_range_calls = test_fallocate(FALLOC_FL_COLLAPSE_RANGE);
2474 if (insert_range_calls)
2475 insert_range_calls = test_fallocate(FALLOC_FL_INSERT_RANGE);
2476 if (clone_range_calls)
2477 clone_range_calls = test_clone_range();
2479 while (numops == -1 || numops--)
2488 prt("All %lu operations completed A-OK!\n", testcalls);