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,
109 /* integrity operations */
110 OP_FSYNC = OP_MAX_FULL,
115 #define PAGE_SIZE getpagesize()
117 #define PAGE_MASK (PAGE_SIZE - 1)
119 char *original_buf; /* a pointer to the original data */
120 char *good_buf; /* a pointer to the correct data */
121 char *temp_buf; /* a pointer to the current data */
122 char *fname; /* name of our test file */
123 char *bname; /* basename of our test file */
124 char *logdev; /* -i flag */
125 char *logid; /* -j flag */
126 char dname[1024]; /* -P flag */
127 char goodfile[PATH_MAX];
128 int dirpath = 0; /* -P flag */
129 int fd; /* fd for our test file */
131 blksize_t block_size = 0;
134 unsigned long testcalls = 0; /* calls to function "test" */
136 unsigned long simulatedopcount = 0; /* -b flag */
137 int closeprob = 0; /* -c flag */
138 int debug = 0; /* -d flag */
139 unsigned long debugstart = 0; /* -D flag */
140 char filldata = 0; /* -g flag */
141 int flush = 0; /* -f flag */
142 int do_fsync = 0; /* -y flag */
143 unsigned long maxfilelen = 256 * 1024; /* -l flag */
144 int sizechecks = 1; /* -n flag disables them */
145 int maxoplen = 64 * 1024; /* -o flag */
146 int quiet = 0; /* -q flag */
147 unsigned long progressinterval = 0; /* -p flag */
148 int readbdy = 1; /* -r flag */
149 int style = 0; /* -s flag */
150 int prealloc = 0; /* -x flag */
151 int truncbdy = 1; /* -t flag */
152 int writebdy = 1; /* -w flag */
153 long monitorstart = -1; /* -m flag */
154 long monitorend = -1; /* -m flag */
155 int lite = 0; /* -L flag */
156 long numops = -1; /* -N flag */
157 int randomoplen = 1; /* -O flag disables it */
158 int seed = 1; /* -S flag */
159 int mapped_writes = 1; /* -W flag disables */
160 int fallocate_calls = 1; /* -F flag disables */
161 int keep_size_calls = 1; /* -K flag disables */
162 int punch_hole_calls = 1; /* -H flag disables */
163 int zero_range_calls = 1; /* -z flag disables */
164 int collapse_range_calls = 1; /* -C flag disables */
165 int insert_range_calls = 1; /* -I flag disables */
166 int mapped_reads = 1; /* -R flag disables it */
167 int check_file = 0; /* -X flag enables */
168 int integrity = 0; /* -i flag */
170 int o_direct; /* -Z */
178 int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset);
181 #define fsxread(a,b,c,d) aio_rw(READ, a,b,c,d)
182 #define fsxwrite(a,b,c,d) aio_rw(WRITE, a,b,c,d)
184 #define fsxread(a,b,c,d) read(a,b,c)
185 #define fsxwrite(a,b,c,d) write(a,b,c)
188 const char *replayops = NULL;
189 const char *recordops = NULL;
190 FILE * fsxlogf = NULL;
191 FILE * replayopsf = NULL;
192 char opsfile[PATH_MAX];
196 static void *round_ptr_up(void *ptr, unsigned long align, unsigned long offset)
198 unsigned long ret = (unsigned long)ptr;
200 ret = ((ret + align - 1) & ~(align - 1));
206 vwarnc(int code, const char *fmt, va_list ap)
209 fprintf(stderr, "%s: ", logid);
210 fprintf(stderr, "fsx: ");
212 vfprintf(stderr, fmt, ap);
213 fprintf(stderr, ": ");
215 fprintf(stderr, "%s\n", strerror(code));
219 warn(const char * fmt, ...) {
222 vwarnc(errno, fmt, ap);
227 prt(const char *fmt, ...)
232 fprintf(stdout, "%s: ", logid);
234 vfprintf(stdout, fmt, args);
238 vfprintf(fsxlogf, fmt, args);
244 prterr(const char *prefix)
246 prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
250 static const char *op_names[] = {
252 [OP_WRITE] = "write",
253 [OP_MAPREAD] = "mapread",
254 [OP_MAPWRITE] = "mapwrite",
255 [OP_TRUNCATE] = "truncate",
256 [OP_FALLOCATE] = "fallocate",
257 [OP_PUNCH_HOLE] = "punch_hole",
258 [OP_ZERO_RANGE] = "zero_range",
259 [OP_COLLAPSE_RANGE] = "collapse_range",
260 [OP_INSERT_RANGE] = "insert_range",
261 [OP_FSYNC] = "fsync",
264 static const char *op_name(int operation)
266 if (operation >= 0 &&
267 operation < sizeof(op_names) / sizeof(op_names[0]))
268 return op_names[operation];
272 static int op_code(const char *name)
276 for (i = 0; i < sizeof(op_names) / sizeof(op_names[0]); i++)
277 if (op_names[i] && strcmp(name, op_names[i]) == 0)
283 log5(int operation, int arg0, int arg1, int arg2, enum opflags flags)
285 struct log_entry *le;
288 le->operation = operation;
290 flags |= FL_CLOSE_OPEN;
294 le->args[3] = file_size;
299 if (logptr >= LOGSIZE)
304 log4(int operation, int arg0, int arg1, enum opflags flags)
306 struct log_entry *le;
309 le->operation = operation;
311 flags |= FL_CLOSE_OPEN;
314 le->args[2] = file_size;
319 if (logptr >= LOGSIZE)
329 struct log_entry *lp;
331 prt("LOG DUMP (%d total operations):\n", logcount);
333 logopsf = fopen(opsfile, "w");
337 if (logcount < LOGSIZE) {
344 for ( ; count > 0; count--) {
348 opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
349 prt("%d(%3d mod 256): ", opnum, opnum%256);
352 overlap = badoff >= lp->args[0] &&
353 badoff < lp->args[0] + lp->args[1];
355 if (lp->flags & FL_SKIPPED) {
356 prt("SKIPPED (no operation)");
360 switch (lp->operation) {
362 prt("MAPREAD 0x%x thru 0x%x\t(0x%x bytes)",
363 lp->args[0], lp->args[0] + lp->args[1] - 1,
369 prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
370 lp->args[0], lp->args[0] + lp->args[1] - 1,
376 prt("READ 0x%x thru 0x%x\t(0x%x bytes)",
377 lp->args[0], lp->args[0] + lp->args[1] - 1,
383 prt("WRITE 0x%x thru 0x%x\t(0x%x bytes)",
384 lp->args[0], lp->args[0] + lp->args[1] - 1,
386 if (lp->args[0] > lp->args[2])
388 else if (lp->args[0] + lp->args[1] > lp->args[2])
390 overlap = (badoff >= lp->args[0] ||
391 badoff >=lp->args[2]) &&
392 badoff < lp->args[0] + lp->args[1];
397 down = lp->args[1] < lp->args[2];
398 prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
399 down ? "DOWN" : "UP", lp->args[2], lp->args[1]);
400 overlap = badoff >= lp->args[1 + !down] &&
401 badoff < lp->args[1 + !!down];
406 /* 0: offset 1: length 2: where alloced */
407 prt("FALLOC 0x%x thru 0x%x\t(0x%x bytes) ",
408 lp->args[0], lp->args[0] + lp->args[1],
410 if (lp->args[0] + lp->args[1] <= lp->args[2])
412 else if (lp->flags & FL_KEEP_SIZE)
420 prt("PUNCH 0x%x thru 0x%x\t(0x%x bytes)",
421 lp->args[0], lp->args[0] + lp->args[1] - 1,
427 prt("ZERO 0x%x thru 0x%x\t(0x%x bytes)",
428 lp->args[0], lp->args[0] + lp->args[1] - 1,
433 case OP_COLLAPSE_RANGE:
434 prt("COLLAPSE 0x%x thru 0x%x\t(0x%x bytes)",
435 lp->args[0], lp->args[0] + lp->args[1] - 1,
440 case OP_INSERT_RANGE:
441 prt("INSERT 0x%x thru 0x%x\t(0x%x bytes)",
442 lp->args[0], lp->args[0] + lp->args[1] - 1,
451 prt("BOGUS LOG ENTRY (operation code = %d)!",
457 if (lp->flags & FL_CLOSE_OPEN)
458 prt("\n\t\tCLOSE/OPEN");
467 if (lp->flags & FL_SKIPPED)
468 fprintf(logopsf, "skip ");
469 fprintf(logopsf, "%s", op_name(lp->operation));
470 for (j = 0; j < lp->nr_args; j++)
471 fprintf(logopsf, " 0x%x", lp->args[j]);
472 if (lp->flags & FL_KEEP_SIZE)
473 fprintf(logopsf, " keep_size");
474 if (lp->flags & FL_CLOSE_OPEN)
475 fprintf(logopsf, " close_open");
477 fprintf(logopsf, " *");
478 fprintf(logopsf, "\n");
483 if (fclose(logopsf) != 0)
486 prt("Log of operations saved to \"%s\"; "
487 "replay with --replay-ops\n",
494 save_buffer(char *buffer, off_t bufferlength, int fd)
497 ssize_t byteswritten;
499 if (fd <= 0 || bufferlength == 0)
502 if (bufferlength > SSIZE_MAX) {
503 prt("fsx flaw: overflow in save_buffer\n");
507 off_t size_by_seek = lseek(fd, (off_t)0, SEEK_END);
508 if (size_by_seek == (off_t)-1)
509 prterr("save_buffer: lseek eof");
510 else if (bufferlength > size_by_seek) {
511 warn("save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek,
512 (unsigned long long)bufferlength);
513 bufferlength = size_by_seek;
517 ret = lseek(fd, (off_t)0, SEEK_SET);
518 if (ret == (off_t)-1)
519 prterr("save_buffer: lseek 0");
521 byteswritten = write(fd, buffer, (size_t)bufferlength);
522 if (byteswritten != bufferlength) {
523 if (byteswritten == -1)
524 prterr("save_buffer write");
526 warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n",
527 (unsigned)byteswritten,
528 (unsigned long long)bufferlength);
534 report_failure(int status)
540 save_buffer(good_buf, file_size, fsxgoodfd);
541 prt("Correct content saved for comparison\n");
542 prt("(maybe hexdump \"%s\" vs \"%s\")\n",
551 #define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
552 *(((unsigned char *)(cp)) + 1)))
560 snprintf(command, 256, "dmsetup message %s 0 mark %s.mark%d", logdev,
562 ret = system(command);
564 prterr("dmsetup mark failed");
570 dump_fsync_buffer(void)
572 char fname_buffer[PATH_MAX];
578 snprintf(fname_buffer, sizeof(fname_buffer), "%s%s.mark%d", dname,
580 good_fd = open(fname_buffer, O_WRONLY|O_CREAT|O_TRUNC, 0666);
582 prterr(fname_buffer);
586 save_buffer(good_buf, file_size, good_fd);
588 prt("Dumped fsync buffer to %s\n", fname_buffer + dirpath);
592 check_buffers(char *buf, unsigned offset, unsigned size)
600 if (memcmp(good_buf + offset, buf, size) != 0) {
601 prt("READ BAD DATA: offset = 0x%x, size = 0x%x, fname = %s\n",
602 offset, size, fname);
603 prt("OFFSET\tGOOD\tBAD\tRANGE\n");
605 c = good_buf[offset];
609 bad = short_at(&buf[i]);
610 prt("0x%05x\t0x%04x\t0x%04x", offset,
611 short_at(&good_buf[offset]), bad);
612 op = buf[offset & 1 ? i+1 : i];
613 prt("\t0x%05x\n", n);
615 prt("operation# (mod 256) for "
616 "the bad data may be %u\n",
617 ((unsigned)op & 0xff));
619 prt("operation# (mod 256) for "
620 "the bad data unknown, check"
621 " HOLE and EXTEND ops\n");
641 if (fstat(fd, &statbuf)) {
642 prterr("check_size: fstat");
643 statbuf.st_size = -1;
645 size_by_seek = lseek(fd, (off_t)0, SEEK_END);
646 if (file_size != statbuf.st_size || file_size != size_by_seek) {
647 prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n",
648 (unsigned long long)file_size,
649 (unsigned long long)statbuf.st_size,
650 (unsigned long long)size_by_seek);
657 check_trunc_hack(void)
660 off_t offset = file_size + (off_t)100000;
662 if (ftruncate(fd, file_size))
664 if (ftruncate(fd, offset))
667 if (statbuf.st_size != offset) {
668 prt("no extend on truncate! not posix!\n");
671 if (ftruncate(fd, file_size)) {
673 prterr("check_trunc_hack: ftruncate");
679 doflush(unsigned offset, unsigned size)
685 if (o_direct == O_DIRECT)
688 pg_offset = offset & mmap_mask;
689 map_size = pg_offset + size;
691 if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
692 MAP_FILE | MAP_SHARED, fd,
693 (off_t)(offset - pg_offset))) == (char *)-1) {
694 prterr("doflush: mmap");
697 if (msync(p, map_size, MS_INVALIDATE) != 0) {
698 prterr("doflush: msync");
701 if (munmap(p, map_size) != 0) {
702 prterr("doflush: munmap");
708 doread(unsigned offset, unsigned size)
713 offset -= offset % readbdy;
715 size -= size % readbdy;
717 if (!quiet && testcalls > simulatedopcount && !o_direct)
718 prt("skipping zero size read\n");
719 log4(OP_READ, offset, size, FL_SKIPPED);
722 if (size + offset > file_size) {
723 if (!quiet && testcalls > simulatedopcount)
724 prt("skipping seek/read past end of file\n");
725 log4(OP_READ, offset, size, FL_SKIPPED);
729 log4(OP_READ, offset, size, FL_NONE);
731 if (testcalls <= simulatedopcount)
735 ((progressinterval && testcalls % progressinterval == 0) ||
737 (monitorstart == -1 ||
738 (offset + size > monitorstart &&
739 (monitorend == -1 || offset <= monitorend))))))
740 prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
741 offset, offset + size - 1, size);
742 ret = lseek(fd, (off_t)offset, SEEK_SET);
743 if (ret == (off_t)-1) {
744 prterr("doread: lseek");
747 iret = fsxread(fd, temp_buf, size, offset);
750 prterr("doread: read");
752 prt("short read: 0x%x bytes instead of 0x%x\n",
756 check_buffers(temp_buf, offset, size);
760 check_eofpage(char *s, unsigned offset, char *p, int size)
762 unsigned long last_page, should_be_zero;
764 if (offset + size <= (file_size & ~page_mask))
767 * we landed in the last page of the file
768 * test to make sure the VM system provided 0's
769 * beyond the true end of the file mapping
770 * (as required by mmap def in 1996 posix 1003.1)
772 last_page = ((unsigned long)p + (offset & page_mask) + size) & ~page_mask;
774 for (should_be_zero = last_page + (file_size & page_mask);
775 should_be_zero < last_page + page_size;
777 if (*(char *)should_be_zero) {
778 prt("Mapped %s: non-zero data past EOF (0x%llx) page offset 0x%x is 0x%04x\n",
779 s, file_size - 1, should_be_zero & page_mask,
780 short_at(should_be_zero));
788 static char *check_buf;
790 unsigned size = file_size;
798 check_buf = (char *) malloc(maxfilelen + writebdy);
799 assert(check_buf != NULL);
800 check_buf = round_ptr_up(check_buf, writebdy, 0);
801 memset(check_buf, '\0', maxfilelen);
805 size -= size % readbdy;
809 ret = lseek(fd, (off_t)offset, SEEK_SET);
810 if (ret == (off_t)-1) {
811 prterr("doread: lseek");
815 iret = fsxread(fd, check_buf, size, offset);
818 prterr("check_contents: read");
820 prt("short check read: 0x%x bytes instead of 0x%x\n",
824 check_buffers(check_buf, offset, size);
826 /* Map eof page, check it */
827 map_offset = size - (size & PAGE_MASK);
828 if (map_offset == size)
829 map_offset -= PAGE_SIZE;
830 map_size = size - map_offset;
832 p = mmap(0, map_size, PROT_READ, MAP_SHARED, fd, map_offset);
833 if (p == MAP_FAILED) {
834 prterr("check_contents: mmap");
837 check_eofpage("check_contents", map_offset, p, map_size);
839 if (munmap(p, map_size) != 0) {
840 prterr("check_contents: munmap");
846 domapread(unsigned offset, unsigned size)
852 offset -= offset % readbdy;
854 if (!quiet && testcalls > simulatedopcount)
855 prt("skipping zero size read\n");
856 log4(OP_MAPREAD, offset, size, FL_SKIPPED);
859 if (size + offset > file_size) {
860 if (!quiet && testcalls > simulatedopcount)
861 prt("skipping seek/read past end of file\n");
862 log4(OP_MAPREAD, offset, size, FL_SKIPPED);
866 log4(OP_MAPREAD, offset, size, FL_NONE);
868 if (testcalls <= simulatedopcount)
872 ((progressinterval && testcalls % progressinterval == 0) ||
874 (monitorstart == -1 ||
875 (offset + size > monitorstart &&
876 (monitorend == -1 || offset <= monitorend))))))
877 prt("%lu mapread\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
878 offset, offset + size - 1, size);
880 pg_offset = offset & PAGE_MASK;
881 map_size = pg_offset + size;
883 if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_SHARED, fd,
884 (off_t)(offset - pg_offset))) == (char *)-1) {
885 prterr("domapread: mmap");
888 memcpy(temp_buf, p + pg_offset, size);
890 check_eofpage("Read", offset, p, size);
892 if (munmap(p, map_size) != 0) {
893 prterr("domapread: munmap");
897 check_buffers(temp_buf, offset, size);
902 gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
906 good_buf[offset] = filldata;
908 good_buf[offset] = testcalls % 256;
910 good_buf[offset] += original_buf[offset];
918 dowrite(unsigned offset, unsigned size)
923 offset -= offset % writebdy;
925 size -= size % writebdy;
927 if (!quiet && testcalls > simulatedopcount && !o_direct)
928 prt("skipping zero size write\n");
929 log4(OP_WRITE, offset, size, FL_SKIPPED);
933 log4(OP_WRITE, offset, size, FL_NONE);
935 gendata(original_buf, good_buf, offset, size);
936 if (file_size < offset + size) {
937 if (file_size < offset)
938 memset(good_buf + file_size, '\0', offset - file_size);
939 file_size = offset + size;
941 warn("Lite file size bug in fsx!");
946 if (testcalls <= simulatedopcount)
950 ((progressinterval && testcalls % progressinterval == 0) ||
952 (monitorstart == -1 ||
953 (offset + size > monitorstart &&
954 (monitorend == -1 || offset <= monitorend))))))
955 prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
956 offset, offset + size - 1, size);
957 ret = lseek(fd, (off_t)offset, SEEK_SET);
958 if (ret == (off_t)-1) {
959 prterr("dowrite: lseek");
962 iret = fsxwrite(fd, good_buf + offset, size, offset);
965 prterr("dowrite: write");
967 prt("short write: 0x%x bytes instead of 0x%x\n",
973 prt("fsync() failed: %s\n", strerror(errno));
978 doflush(offset, size);
984 domapwrite(unsigned offset, unsigned size)
991 offset -= offset % writebdy;
993 if (!quiet && testcalls > simulatedopcount)
994 prt("skipping zero size write\n");
995 log4(OP_MAPWRITE, offset, size, FL_SKIPPED);
998 cur_filesize = file_size;
1000 log4(OP_MAPWRITE, offset, size, FL_NONE);
1002 gendata(original_buf, good_buf, offset, size);
1003 if (file_size < offset + size) {
1004 if (file_size < offset)
1005 memset(good_buf + file_size, '\0', offset - file_size);
1006 file_size = offset + size;
1008 warn("Lite file size bug in fsx!");
1009 report_failure(200);
1013 if (testcalls <= simulatedopcount)
1017 ((progressinterval && testcalls % progressinterval == 0) ||
1019 (monitorstart == -1 ||
1020 (offset + size > monitorstart &&
1021 (monitorend == -1 || offset <= monitorend))))))
1022 prt("%lu mapwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
1023 offset, offset + size - 1, size);
1025 if (file_size > cur_filesize) {
1026 if (ftruncate(fd, file_size) == -1) {
1027 prterr("domapwrite: ftruncate");
1031 pg_offset = offset & PAGE_MASK;
1032 map_size = pg_offset + size;
1034 if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
1035 MAP_FILE | MAP_SHARED, fd,
1036 (off_t)(offset - pg_offset))) == (char *)-1) {
1037 prterr("domapwrite: mmap");
1038 report_failure(202);
1040 memcpy(p + pg_offset, good_buf + offset, size);
1041 if (msync(p, map_size, MS_SYNC) != 0) {
1042 prterr("domapwrite: msync");
1043 report_failure(203);
1046 check_eofpage("Write", offset, p, size);
1048 if (munmap(p, map_size) != 0) {
1049 prterr("domapwrite: munmap");
1050 report_failure(204);
1056 dotruncate(unsigned size)
1058 int oldsize = file_size;
1060 size -= size % truncbdy;
1061 if (size > biggest) {
1063 if (!quiet && testcalls > simulatedopcount)
1064 prt("truncating to largest ever: 0x%x\n", size);
1067 log4(OP_TRUNCATE, 0, size, FL_NONE);
1069 if (size > file_size)
1070 memset(good_buf + file_size, '\0', size - file_size);
1073 if (testcalls <= simulatedopcount)
1076 if ((progressinterval && testcalls % progressinterval == 0) ||
1077 (debug && (monitorstart == -1 || monitorend == -1 ||
1078 size <= monitorend)))
1079 prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
1080 if (ftruncate(fd, (off_t)size) == -1) {
1081 prt("ftruncate1: %x\n", size);
1082 prterr("dotruncate: ftruncate");
1083 report_failure(160);
1087 #ifdef FALLOC_FL_PUNCH_HOLE
1089 do_punch_hole(unsigned offset, unsigned length)
1091 unsigned end_offset;
1094 int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
1097 if (!quiet && testcalls > simulatedopcount)
1098 prt("skipping zero length punch hole\n");
1099 log4(OP_PUNCH_HOLE, offset, length, FL_SKIPPED);
1103 if (file_size <= (loff_t)offset) {
1104 if (!quiet && testcalls > simulatedopcount)
1105 prt("skipping hole punch off the end of the file\n");
1106 log4(OP_PUNCH_HOLE, offset, length, FL_SKIPPED);
1110 end_offset = offset + length;
1112 log4(OP_PUNCH_HOLE, offset, length, FL_NONE);
1114 if (testcalls <= simulatedopcount)
1117 if ((progressinterval && testcalls % progressinterval == 0) ||
1118 (debug && (monitorstart == -1 || monitorend == -1 ||
1119 end_offset <= monitorend))) {
1120 prt("%lu punch\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls,
1121 offset, offset+length, length);
1123 if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
1124 prt("punch hole: 0x%x to 0x%x\n", offset, offset + length);
1125 prterr("do_punch_hole: fallocate");
1126 report_failure(161);
1130 max_offset = offset < file_size ? offset : file_size;
1131 max_len = max_offset + length <= file_size ? length :
1132 file_size - max_offset;
1133 memset(good_buf + max_offset, '\0', max_len);
1138 do_punch_hole(unsigned offset, unsigned length)
1144 #ifdef FALLOC_FL_ZERO_RANGE
1146 do_zero_range(unsigned offset, unsigned length, int keep_size)
1148 unsigned end_offset;
1149 int mode = FALLOC_FL_ZERO_RANGE;
1152 if (!quiet && testcalls > simulatedopcount)
1153 prt("skipping zero length zero range\n");
1154 log4(OP_ZERO_RANGE, offset, length, FL_SKIPPED |
1155 (keep_size ? FL_KEEP_SIZE : FL_NONE));
1159 end_offset = keep_size ? 0 : offset + length;
1161 if (end_offset > biggest) {
1162 biggest = end_offset;
1163 if (!quiet && testcalls > simulatedopcount)
1164 prt("zero_range to largest ever: 0x%x\n", end_offset);
1168 * last arg matches fallocate string array index in logdump:
1169 * 0: allocate past EOF
1170 * 1: extending prealloc
1171 * 2: interior prealloc
1173 log4(OP_ZERO_RANGE, offset, length,
1174 keep_size ? FL_KEEP_SIZE : FL_NONE);
1176 if (testcalls <= simulatedopcount)
1179 if ((progressinterval && testcalls % progressinterval == 0) ||
1180 (debug && (monitorstart == -1 || monitorend == -1 ||
1181 end_offset <= monitorend))) {
1182 prt("%lu zero\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls,
1183 offset, offset+length, length);
1185 if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
1186 prt("zero range: 0x%x to 0x%x\n", offset, offset + length);
1187 prterr("do_zero_range: fallocate");
1188 report_failure(161);
1191 memset(good_buf + offset, '\0', length);
1196 do_zero_range(unsigned offset, unsigned length, int keep_size)
1202 #ifdef FALLOC_FL_COLLAPSE_RANGE
1204 do_collapse_range(unsigned offset, unsigned length)
1206 unsigned end_offset;
1207 int mode = FALLOC_FL_COLLAPSE_RANGE;
1210 if (!quiet && testcalls > simulatedopcount)
1211 prt("skipping zero length collapse range\n");
1212 log4(OP_COLLAPSE_RANGE, offset, length, FL_SKIPPED);
1216 end_offset = offset + length;
1217 if ((loff_t)end_offset >= file_size) {
1218 if (!quiet && testcalls > simulatedopcount)
1219 prt("skipping collapse range behind EOF\n");
1220 log4(OP_COLLAPSE_RANGE, offset, length, FL_SKIPPED);
1224 log4(OP_COLLAPSE_RANGE, offset, length, FL_NONE);
1226 if (testcalls <= simulatedopcount)
1229 if ((progressinterval && testcalls % progressinterval == 0) ||
1230 (debug && (monitorstart == -1 || monitorend == -1 ||
1231 end_offset <= monitorend))) {
1232 prt("%lu collapse\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls,
1233 offset, offset+length, length);
1235 if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
1236 prt("collapse range: 0x%x to 0x%x\n", offset, offset + length);
1237 prterr("do_collapse_range: fallocate");
1238 report_failure(161);
1241 memmove(good_buf + offset, good_buf + end_offset,
1242 file_size - end_offset);
1243 file_size -= length;
1248 do_collapse_range(unsigned offset, unsigned length)
1254 #ifdef FALLOC_FL_INSERT_RANGE
1256 do_insert_range(unsigned offset, unsigned length)
1258 unsigned end_offset;
1259 int mode = FALLOC_FL_INSERT_RANGE;
1262 if (!quiet && testcalls > simulatedopcount)
1263 prt("skipping zero length insert range\n");
1264 log4(OP_INSERT_RANGE, offset, length, FL_SKIPPED);
1268 if ((loff_t)offset >= file_size) {
1269 if (!quiet && testcalls > simulatedopcount)
1270 prt("skipping insert range behind EOF\n");
1271 log4(OP_INSERT_RANGE, offset, length, FL_SKIPPED);
1275 log4(OP_INSERT_RANGE, offset, length, FL_NONE);
1277 if (testcalls <= simulatedopcount)
1280 end_offset = offset + length;
1281 if ((progressinterval && testcalls % progressinterval == 0) ||
1282 (debug && (monitorstart == -1 || monitorend == -1 ||
1283 end_offset <= monitorend))) {
1284 prt("%lu insert\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls,
1285 offset, offset+length, length);
1287 if (fallocate(fd, mode, (loff_t)offset, (loff_t)length) == -1) {
1288 prt("insert range: 0x%x to 0x%x\n", offset, offset + length);
1289 prterr("do_insert_range: fallocate");
1290 report_failure(161);
1293 memmove(good_buf + end_offset, good_buf + offset,
1294 file_size - offset);
1295 memset(good_buf + offset, '\0', length);
1296 file_size += length;
1301 do_insert_range(unsigned offset, unsigned length)
1307 #ifdef HAVE_LINUX_FALLOC_H
1308 /* fallocate is basically a no-op unless extending, then a lot like a truncate */
1310 do_preallocate(unsigned offset, unsigned length, int keep_size)
1312 unsigned end_offset;
1315 if (!quiet && testcalls > simulatedopcount)
1316 prt("skipping zero length fallocate\n");
1317 log4(OP_FALLOCATE, offset, length, FL_SKIPPED |
1318 (keep_size ? FL_KEEP_SIZE : FL_NONE));
1322 end_offset = keep_size ? 0 : offset + length;
1324 if (end_offset > biggest) {
1325 biggest = end_offset;
1326 if (!quiet && testcalls > simulatedopcount)
1327 prt("fallocating to largest ever: 0x%x\n", end_offset);
1331 * last arg matches fallocate string array index in logdump:
1332 * 0: allocate past EOF
1333 * 1: extending prealloc
1334 * 2: interior prealloc
1336 log4(OP_FALLOCATE, offset, length,
1337 keep_size ? FL_KEEP_SIZE : FL_NONE);
1339 if (end_offset > file_size) {
1340 memset(good_buf + file_size, '\0', end_offset - file_size);
1341 file_size = end_offset;
1344 if (testcalls <= simulatedopcount)
1347 if ((progressinterval && testcalls % progressinterval == 0) ||
1348 (debug && (monitorstart == -1 || monitorend == -1 ||
1349 end_offset <= monitorend)))
1350 prt("%lu falloc\tfrom 0x%x to 0x%x (0x%x bytes)\n", testcalls,
1351 offset, offset + length, length);
1352 if (fallocate(fd, keep_size ? FALLOC_FL_KEEP_SIZE : 0, (loff_t)offset, (loff_t)length) == -1) {
1353 prt("fallocate: 0x%x to 0x%x\n", offset, offset + length);
1354 prterr("do_preallocate: fallocate");
1355 report_failure(161);
1360 do_preallocate(unsigned offset, unsigned length, int keep_size)
1371 if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
1372 prterr("writefileimage: lseek");
1373 report_failure(171);
1375 iret = write(fd, good_buf, file_size);
1376 if ((off_t)iret != file_size) {
1378 prterr("writefileimage: write");
1380 prt("short write: 0x%x bytes instead of 0x%llx\n",
1381 iret, (unsigned long long)file_size);
1382 report_failure(172);
1384 if (lite ? 0 : ftruncate(fd, file_size) == -1) {
1385 prt("ftruncate2: %llx\n", (unsigned long long)file_size);
1386 prterr("writefileimage: ftruncate");
1387 report_failure(173);
1395 if (testcalls <= simulatedopcount)
1399 prt("%lu close/open\n", testcalls);
1401 prterr("docloseopen: close");
1402 report_failure(180);
1404 fd = open(fname, O_RDWR|o_direct, 0);
1406 prterr("docloseopen: open");
1407 report_failure(181);
1416 if (testcalls <= simulatedopcount)
1419 prt("%lu fsync\n", testcalls);
1420 log4(OP_FSYNC, 0, 0, 0);
1424 report_failure(210);
1427 dump_fsync_buffer();
1431 #define TRIM_OFF(off, size) \
1439 #define TRIM_LEN(off, len, size) \
1441 if ((off) + (len) > (size)) \
1442 (len) = (size) - (off); \
1445 #define TRIM_OFF_LEN(off, len, size) \
1447 TRIM_OFF(off, size); \
1448 TRIM_LEN(off, len, size); \
1455 prt("signal %d\n", sig);
1456 prt("testcalls = %lu\n", testcalls);
1461 op_args_count(int operation)
1463 switch (operation) {
1470 read_op(struct log_entry *log_entry)
1474 memset(log_entry, 0, sizeof(*log_entry));
1475 log_entry->operation = -1;
1477 while (log_entry->operation == -1) {
1482 if (!fgets(line, sizeof(line), replayopsf)) {
1483 if (feof(replayopsf)) {
1489 str = strtok(line, " \t\n");
1490 } while (!str || str[0] == '#');
1492 if (strcmp(str, "skip") == 0) {
1493 log_entry->flags |= FL_SKIPPED;
1494 str = strtok(NULL, " \t\n");
1498 log_entry->operation = op_code(str);
1499 if (log_entry->operation == -1)
1501 log_entry->nr_args = op_args_count(log_entry->operation);
1502 for (i = 0; i < log_entry->nr_args; i++) {
1505 str = strtok(NULL, " \t\n");
1508 log_entry->args[i] = strtoul(str, &end, 0);
1512 while ((str = strtok(NULL, " \t\n"))) {
1513 if (strcmp(str, "keep_size") == 0)
1514 log_entry->flags |= FL_KEEP_SIZE;
1515 else if (strcmp(str, "close_open") == 0)
1516 log_entry->flags |= FL_CLOSE_OPEN;
1517 else if (strcmp(str, "*") == 0)
1518 ; /* overlap marker; ignore */
1526 fprintf(stderr, "%s: parse error\n", replayops);
1529 cleanup(100); /* doesn't return */
1537 unsigned long offset;
1543 if (simulatedopcount > 0 && testcalls == simulatedopcount)
1548 if (debugstart > 0 && testcalls >= debugstart)
1551 if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
1552 prt("%lu...\n", testcalls);
1555 struct log_entry log_entry;
1557 while (read_op(&log_entry)) {
1558 if (log_entry.flags & FL_SKIPPED) {
1559 log4(log_entry.operation,
1560 log_entry.args[0], log_entry.args[1],
1565 op = log_entry.operation;
1566 offset = log_entry.args[0];
1567 size = log_entry.args[1];
1568 closeopen = !!(log_entry.flags & FL_CLOSE_OPEN);
1569 keep_size = !!(log_entry.flags & FL_KEEP_SIZE);
1577 closeopen = (rv >> 3) < (1 << 28) / closeprob;
1582 size = random() % (maxoplen + 1);
1584 /* calculate appropriate op to run */
1586 op = rv % OP_MAX_LITE;
1587 else if (!integrity)
1588 op = rv % OP_MAX_FULL;
1590 op = rv % OP_MAX_INTEGRITY;
1595 size = random() % maxfilelen;
1598 if (fallocate_calls && size && keep_size_calls)
1599 keep_size = random() % 2;
1602 if (zero_range_calls && size && keep_size_calls)
1603 keep_size = random() % 2;
1619 if (!fallocate_calls) {
1620 log4(OP_FALLOCATE, offset, size, FL_SKIPPED);
1625 if (!punch_hole_calls) {
1626 log4(OP_PUNCH_HOLE, offset, size, FL_SKIPPED);
1631 if (!zero_range_calls) {
1632 log4(OP_ZERO_RANGE, offset, size, FL_SKIPPED);
1636 case OP_COLLAPSE_RANGE:
1637 if (!collapse_range_calls) {
1638 log4(OP_COLLAPSE_RANGE, offset, size, FL_SKIPPED);
1642 case OP_INSERT_RANGE:
1643 if (!insert_range_calls) {
1644 log4(OP_INSERT_RANGE, offset, size, FL_SKIPPED);
1652 TRIM_OFF_LEN(offset, size, file_size);
1653 doread(offset, size);
1657 TRIM_OFF_LEN(offset, size, maxfilelen);
1658 dowrite(offset, size);
1662 TRIM_OFF_LEN(offset, size, file_size);
1663 domapread(offset, size);
1667 TRIM_OFF_LEN(offset, size, maxfilelen);
1668 domapwrite(offset, size);
1676 TRIM_OFF_LEN(offset, size, maxfilelen);
1677 do_preallocate(offset, size, keep_size);
1681 TRIM_OFF_LEN(offset, size, file_size);
1682 do_punch_hole(offset, size);
1685 TRIM_OFF_LEN(offset, size, file_size);
1686 do_zero_range(offset, size, keep_size);
1688 case OP_COLLAPSE_RANGE:
1689 TRIM_OFF_LEN(offset, size, file_size - 1);
1690 offset = offset & ~(block_size - 1);
1691 size = size & ~(block_size - 1);
1693 log4(OP_COLLAPSE_RANGE, offset, size, FL_SKIPPED);
1696 do_collapse_range(offset, size);
1698 case OP_INSERT_RANGE:
1699 TRIM_OFF(offset, file_size);
1700 TRIM_LEN(file_size, size, maxfilelen);
1701 offset = offset & ~(block_size - 1);
1702 size = size & ~(block_size - 1);
1704 log4(OP_INSERT_RANGE, offset, size, FL_SKIPPED);
1707 if (file_size + size > maxfilelen) {
1708 log4(OP_INSERT_RANGE, offset, size, FL_SKIPPED);
1712 do_insert_range(offset, size);
1718 prterr("test: unknown operation");
1723 if (check_file && testcalls > simulatedopcount)
1727 if (sizechecks && testcalls > simulatedopcount)
1738 fprintf(stdout, "usage: %s",
1739 "fsx [-dknqxAFLOWZ] [-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\
1740 -b opnum: beginning operation number (default 1)\n\
1741 -c P: 1 in P chance of file close+open at each op (default infinity)\n\
1742 -d: debug output for all operations\n\
1743 -f flush and invalidate cache after I/O\n\
1744 -g X: write character X instead of random generated data\n\
1745 -i logdev: do integrity testing, logdev is the dm log writes device\n\
1746 -j logid: prefix debug log messsages with this id\n\
1747 -k: do not truncate existing file and use its size as upper bound on file size\n\
1748 -l flen: the upper bound on file size (default 262144)\n\
1749 -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
1750 -n: no verifications of file size\n\
1751 -o oplen: the upper bound on operation size (default 65536)\n\
1752 -p progressinterval: debug output at specified operation interval\n\
1753 -q: quieter operation\n\
1754 -r readbdy: 4096 would make reads page aligned (default 1)\n\
1755 -s style: 1 gives smaller truncates (default 0)\n\
1756 -t truncbdy: 4096 would make truncates page aligned (default 1)\n\
1757 -w writebdy: 4096 would make writes page aligned (default 1)\n\
1758 -x: preallocate file space before starting, XFS only (default 0)\n\
1759 -y synchronize changes to a file\n"
1762 " -A: Use the AIO system calls\n"
1764 " -D startingop: debug output starting at specified operation\n"
1765 #ifdef HAVE_LINUX_FALLOC_H
1766 " -F: Do not use fallocate (preallocation) calls\n"
1768 #ifdef FALLOC_FL_PUNCH_HOLE
1769 " -H: Do not use punch hole calls\n"
1771 #ifdef FALLOC_FL_ZERO_RANGE
1772 " -z: Do not use zero range calls\n"
1774 #ifdef FALLOC_FL_COLLAPSE_RANGE
1775 " -C: Do not use collapse range calls\n"
1777 #ifdef FALLOC_FL_INSERT_RANGE
1778 " -I: Do not use insert range calls\n"
1780 " -L: fsxLite - no file creations & no file size changes\n\
1781 -N numops: total # operations to do (default infinity)\n\
1782 -O: use oplen (see -o flag) for every op (default random)\n\
1783 -P: save .fsxlog .fsxops and .fsxgood files in dirpath (default ./)\n\
1784 -S seed: for random # generator (default 1) 0 gets timestamp\n\
1785 -W: mapped write operations DISabled\n\
1786 -X: Read file and compare to good buffer after every operation.\n\
1787 -R: read() system calls only (mapped reads disabled)\n\
1788 -Z: O_DIRECT (use -R, -W, -r and -w too)\n\
1789 --replay-ops opsfile: replay ops from recorded .fsxops file\n\
1790 --record-ops[=opsfile]: dump ops file also on success. optionally specify ops file name\n\
1791 fname: this filename is REQUIRED (no default)\n");
1797 getnum(char *s, char **e)
1802 ret = strtol(s, e, 0);
1832 io_context_t io_ctx;
1838 ret = io_queue_init(QSZ, &io_ctx);
1840 fprintf(stderr, "aio_setup: io_queue_init failed: %s\n",
1848 __aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
1850 struct io_event event;
1851 static struct timespec ts;
1852 struct iocb *iocbs[] = { &iocb };
1857 io_prep_pread(&iocb, fd, buf, len, offset);
1859 io_prep_pwrite(&iocb, fd, buf, len, offset);
1864 ret = io_submit(io_ctx, 1, iocbs);
1866 fprintf(stderr, "errcode=%d\n", ret);
1867 fprintf(stderr, "aio_rw: io_submit failed: %s\n",
1872 ret = io_getevents(io_ctx, 1, 1, &event, &ts);
1875 fprintf(stderr, "aio_rw: no events available\n");
1877 fprintf(stderr, "errcode=%d\n", -ret);
1878 fprintf(stderr, "aio_rw: io_getevents failed: %s\n",
1883 if (len != event.res) {
1885 * The b0rked libaio defines event.res as unsigned.
1886 * However the kernel strucuture has it signed,
1887 * and it's used to pass negated error value.
1888 * Till the library is fixed use the temp var.
1890 res = (long)event.res;
1892 fprintf(stderr, "bad io length: %lu instead of %u\n",
1895 fprintf(stderr, "errcode=%ld\n", -res);
1896 fprintf(stderr, "aio_rw: async io failed: %s\n",
1907 * The caller expects error return in traditional libc
1908 * convention, i.e. -1 and the errno set to error.
1914 int aio_rw(int rw, int fd, char *buf, unsigned len, unsigned offset)
1919 ret = __aio_rw(rw, fd, buf, len, offset);
1922 ret = read(fd, buf, len);
1924 ret = write(fd, buf, len);
1931 #define test_fallocate(mode) __test_fallocate(mode, #mode)
1934 __test_fallocate(int mode, const char *mode_str)
1936 #ifdef HAVE_LINUX_FALLOC_H
1939 if (fallocate(fd, mode, file_size, 1) && errno == EOPNOTSUPP) {
1942 "main: filesystem does not support "
1943 "fallocate mode %s, disabling!\n",
1947 if (ftruncate(fd, file_size)) {
1948 warn("main: ftruncate");
1957 static struct option longopts[] = {
1958 {"replay-ops", required_argument, 0, 256},
1959 {"record-ops", optional_argument, 0, 255},
1964 main(int argc, char **argv)
1968 char logfile[PATH_MAX];
1969 struct stat statbuf;
1970 int o_flags = O_RDWR|O_CREAT|O_TRUNC;
1975 page_size = getpagesize();
1976 page_mask = page_size - 1;
1977 mmap_mask = page_mask;
1980 setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
1982 while ((ch = getopt_long(argc, argv,
1983 "b:c:dfg:i:j:kl:m:no:p:qr:s:t:w:xyAD:FKHzCILN:OP:RS:WXZ",
1984 longopts, NULL)) != EOF)
1987 simulatedopcount = getnum(optarg, &endp);
1989 prt("Will begin at operation %ld\n", simulatedopcount);
1990 if (simulatedopcount == 0)
1992 simulatedopcount -= 1;
1995 closeprob = getnum(optarg, &endp);
1997 prt("Chance of close/open is 1 in %d\n", closeprob);
2012 logdev = strdup(optarg);
2019 logid = strdup(optarg);
2026 o_flags &= ~O_TRUNC;
2029 maxfilelen = getnum(optarg, &endp);
2030 if (maxfilelen <= 0)
2034 monitorstart = getnum(optarg, &endp);
2035 if (monitorstart < 0)
2037 if (!endp || *endp++ != ':')
2039 monitorend = getnum(endp, &endp);
2042 if (monitorend == 0)
2043 monitorend = -1; /* aka infinity */
2049 maxoplen = getnum(optarg, &endp);
2054 progressinterval = getnum(optarg, &endp);
2055 if (progressinterval == 0)
2062 readbdy = getnum(optarg, &endp);
2067 style = getnum(optarg, &endp);
2068 if (style < 0 || style > 1)
2072 truncbdy = getnum(optarg, &endp);
2077 writebdy = getnum(optarg, &endp);
2091 debugstart = getnum(optarg, &endp);
2096 fallocate_calls = 0;
2099 keep_size_calls = 0;
2102 punch_hole_calls = 0;
2105 zero_range_calls = 0;
2108 collapse_range_calls = 0;
2111 insert_range_calls = 0;
2115 o_flags &= ~(O_CREAT|O_TRUNC);
2118 numops = getnum(optarg, &endp);
2126 strncpy(dname, optarg, sizeof(dname));
2128 dirpath = strlen(dname);
2134 seed = getnum(optarg, &endp);
2136 seed = time(0) % 10000;
2137 seed += (int)getpid();
2145 prt("mapped writes DISABLED\n");
2151 o_direct = O_DIRECT;
2152 o_flags |= O_DIRECT;
2154 case 255: /* --record-ops */
2156 strncpy(opsfile, optarg, sizeof(opsfile));
2157 recordops = opsfile;
2159 case 256: /* --replay-ops */
2171 if (integrity && !dirpath) {
2172 fprintf(stderr, "option -i <logdev> requires -P <dirpath>\n");
2177 tmp = strdup(fname);
2182 bname = basename(tmp);
2184 signal(SIGHUP, cleanup);
2185 signal(SIGINT, cleanup);
2186 signal(SIGPIPE, cleanup);
2187 signal(SIGALRM, cleanup);
2188 signal(SIGTERM, cleanup);
2189 signal(SIGXCPU, cleanup);
2190 signal(SIGXFSZ, cleanup);
2191 signal(SIGVTALRM, cleanup);
2192 signal(SIGUSR1, cleanup);
2193 signal(SIGUSR2, cleanup);
2196 prt("Seed set to %d\n", seed);
2198 fd = open(fname, o_flags, 0666);
2203 if (fstat(fd, &statbuf)) {
2204 prterr("check_size: fstat");
2207 block_size = statbuf.st_blksize;
2210 xfs_flock64_t resv = { 0 };
2211 #ifdef HAVE_XFS_PLATFORM_DEFS_H
2212 if (!platform_test_xfs_fd(fd)) {
2214 fprintf(stderr, "main: cannot prealloc, non XFS\n");
2218 resv.l_len = maxfilelen;
2219 if ((xfsctl(fname, fd, XFS_IOC_RESVSP, &resv)) < 0) {
2227 snprintf(goodfile, sizeof(goodfile), "%s%s.fsxgood", dname, bname);
2228 snprintf(logfile, sizeof(logfile), "%s%s.fsxlog", dname, bname);
2230 snprintf(opsfile, sizeof(opsfile), "%s%s.fsxops", dname, bname);
2232 snprintf(goodfile, sizeof(goodfile), "%s.fsxgood", fname);
2233 snprintf(logfile, sizeof(logfile), "%s.fsxlog", fname);
2235 snprintf(opsfile, sizeof(opsfile), "%s.fsxops", fname);
2237 fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
2238 if (fsxgoodfd < 0) {
2242 fsxlogf = fopen(logfile, "w");
2243 if (fsxlogf == NULL) {
2250 replayopsf = fopen(replayops, "r");
2262 if (!(o_flags & O_TRUNC)) {
2264 file_size = maxfilelen = biggest = lseek(fd, (off_t)0, SEEK_END);
2265 if (file_size == (off_t)-1) {
2267 warn("main: lseek eof");
2270 ret = lseek(fd, (off_t)0, SEEK_SET);
2271 if (ret == (off_t)-1) {
2273 warn("main: lseek 0");
2277 original_buf = (char *) malloc(maxfilelen);
2278 for (i = 0; i < maxfilelen; i++)
2279 original_buf[i] = random() % 256;
2280 good_buf = (char *) malloc(maxfilelen + writebdy);
2281 good_buf = round_ptr_up(good_buf, writebdy, 0);
2282 memset(good_buf, '\0', maxfilelen);
2283 temp_buf = (char *) malloc(maxoplen + readbdy);
2284 temp_buf = round_ptr_up(temp_buf, readbdy, 0);
2285 memset(temp_buf, '\0', maxoplen);
2286 if (lite) { /* zero entire existing file */
2289 written = write(fd, good_buf, (size_t)maxfilelen);
2290 if (written != maxfilelen) {
2291 if (written == -1) {
2293 warn("main: error on write");
2295 warn("main: short write, 0x%x bytes instead "
2302 ssize_t ret, len = file_size;
2306 ret = read(fd, good_buf + off, len);
2309 warn("main: error on read");
2319 if (fallocate_calls)
2320 fallocate_calls = test_fallocate(0);
2321 if (keep_size_calls)
2322 keep_size_calls = test_fallocate(FALLOC_FL_KEEP_SIZE);
2323 if (punch_hole_calls)
2324 punch_hole_calls = test_fallocate(FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE);
2325 if (zero_range_calls)
2326 zero_range_calls = test_fallocate(FALLOC_FL_ZERO_RANGE);
2327 if (collapse_range_calls)
2328 collapse_range_calls = test_fallocate(FALLOC_FL_COLLAPSE_RANGE);
2329 if (insert_range_calls)
2330 insert_range_calls = test_fallocate(FALLOC_FL_INSERT_RANGE);
2332 while (numops == -1 || numops--)
2341 prt("All %lu operations completed A-OK!\n", testcalls);