15 static int openflags = O_RDWR;
18 * Just creates a random file, overwriting the file in a random number of loops
19 * and fsyncing between each loop.
21 static int test_one(int *max_blocks)
23 int loops = (random() % 20) + 5;
25 lseek(test_fd, 0, SEEK_SET);
27 int character = (random() % 126) + 33; /* printable character */
28 int blocks = (random() % 100) + 1;
30 if (blocks > *max_blocks)
32 lseek(test_fd, 0, SEEK_SET);
33 memset(buf, character, 4096);
35 fprintf(stderr, "Fsync failed, test results will be "
36 "invalid: %d\n", errno);
41 if (write(test_fd, buf, 4096) < 4096) {
42 fprintf(stderr, "Short write %d\n", errno);
52 * Preallocate a randomly sized file and then overwrite the entire thing and
55 static int test_two(int *max_blocks)
57 int blocks = (random() % 1024) + 1;
58 int character = (random() % 126) + 33;
62 if (fallocate(test_fd, 0, 0, blocks * 4096)) {
63 fprintf(stderr, "Error fallocating %d (%s)\n", errno,
68 lseek(test_fd, 0, SEEK_SET);
69 memset(buf, character, 4096);
71 if (write(test_fd, buf, 4096) < 4096) {
72 fprintf(stderr, "Short write %d\n", errno);
80 static void drop_all_caches()
85 if ((fd = open("/proc/sys/vm/drop_caches", O_WRONLY)) < 0) {
86 fprintf(stderr, "Error opening drop caches: %d\n", errno);
90 write(fd, value, sizeof(value)-1);
95 * Randomly write inside of a file, either creating a sparse file or prealloc
96 * the file and randomly write within it, depending on the prealloc flag
98 static int test_three(int *max_blocks, int prealloc, int rand_fsync,
99 int do_sync, int drop_caches)
101 int size = (random() % 2048) + 4;
102 int blocks = size / 2;
103 int sync_block = blocks / 2;
104 int rand_sync_interval = (random() % blocks) + 1;
105 int character = (random() % 126) + 33;
107 if (prealloc && fallocate(test_fd, 0, 0, size * 4096)) {
108 fprintf(stderr, "Error fallocating %d (%s)\n", errno,
116 memset(buf, character, 4096);
118 int block = (random() % size);
120 if ((block + 1) > *max_blocks)
121 *max_blocks = block + 1;
123 if (rand_fsync && !(blocks % rand_sync_interval)) {
124 if (fsync(test_fd)) {
125 fprintf(stderr, "Fsync failed, test results "
126 "will be invalid: %d\n", errno);
131 /* Force a transaction commit in between just for fun */
132 if (blocks == sync_block && (do_sync || drop_caches)) {
136 sync_file_range(test_fd, 0, 0,
137 SYNC_FILE_RANGE_WRITE|
138 SYNC_FILE_RANGE_WAIT_AFTER);
143 test_fd = open(fname, openflags);
146 fprintf(stderr, "Error re-opening file: %d\n",
153 if (pwrite(test_fd, buf, 4096, block * 4096) < 4096) {
154 fprintf(stderr, "Short write %d\n", errno);
162 static void timeval_subtract(struct timeval *result,struct timeval *x,
165 if (x->tv_usec < y->tv_usec) {
166 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
167 y->tv_usec -= 1000000 * nsec;
171 if (x->tv_usec - y->tv_usec > 1000000) {
172 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
173 y->tv_usec += 1000000 * nsec;
177 result->tv_sec = x->tv_sec - y->tv_sec;
178 result->tv_usec = x->tv_usec - y->tv_usec;
181 static int test_four(int *max_blocks)
183 size_t size = 2621440; /* 10 gigabytes */
184 size_t blocks = size / 2;
185 size_t sync_block = blocks / 8; /* fsync 8 times */
186 int character = (random() % 126) + 33;
187 struct timeval start, end, diff;
189 memset(buf, character, 4096);
191 off_t block = (random() % size);
193 if ((block + 1) > *max_blocks)
194 *max_blocks = block + 1;
196 if ((blocks % sync_block) == 0) {
197 if (gettimeofday(&start, NULL)) {
198 fprintf(stderr, "Error getting time: %d\n",
202 if (fsync(test_fd)) {
203 fprintf(stderr, "Fsync failed, test results "
204 "will be invalid: %d\n", errno);
207 if (gettimeofday(&end, NULL)) {
208 fprintf(stderr, "Error getting time: %d\n",
212 timeval_subtract(&diff, &end, &start);
213 printf("Fsync time was %ds and %dus\n",
214 (int)diff.tv_sec, (int)diff.tv_usec);
217 if (pwrite(test_fd, buf, 4096, block * 4096) < 4096) {
218 fprintf(stderr, "Short write %d\n", errno);
226 static int test_five()
228 int character = (random() % 126) + 33;
229 int runs = (random() % 100) + 1;
232 memset(buf, character, 3072);
233 for (i = 0; i < runs; i++) {
234 ssize_t write_size = (random() % 3072) + 1;
236 if (pwrite(test_fd, buf, write_size, 0) < write_size) {
237 fprintf(stderr, "Short write %d\n", errno);
242 if (fsync(test_fd)) {
243 fprintf(stderr, "Fsync failed, test results "
244 "will be invalid: %d\n", errno);
254 * Reproducer for something like this
256 * [data][prealloc][data]
258 * and then in the [prealloc] section we have
260 * [ pre ][pre][ pre ]
261 * [d][pp][dd][ppp][d][ppp][d]
263 * where each letter represents on block of either data or prealloc.
265 * This explains all the weirdly specific numbers.
267 static int test_six()
269 int character = (random() % 126) + 33;
272 memset(buf, character, 4096);
274 /* Write on either side of the file, leaving a hole in the middle */
275 for (i = 0; i < 10; i++) {
276 if (pwrite(test_fd, buf, 4096, i * 4096) < 4096) {
277 fprintf(stderr, "Short write %d\n", errno);
282 if (fsync(test_fd)) {
283 fprintf(stderr, "Fsync failed %d\n", errno);
288 * The test fs I had the prealloc extent was 13 4k blocks long so I'm
289 * just using that to give myself the best chances of reproducing.
291 for (i = 23; i < 33; i++) {
292 if (pwrite(test_fd, buf, 4096, i * 4096) < 4096) {
293 fprintf(stderr, "Short write %d\n", errno);
298 if (fsync(test_fd)) {
299 fprintf(stderr, "Fsync failed %d\n", errno);
303 if (fallocate(test_fd, 0, 10 * 4096, 4 * 4096)) {
304 fprintf(stderr, "Error fallocating %d\n", errno);
308 if (fallocate(test_fd, 0, 14 * 4096, 5 * 4096)) {
309 fprintf(stderr, "Error fallocating %d\n", errno);
313 if (fallocate(test_fd, 0, 19 * 4096, 4 * 4096)) {
314 fprintf(stderr, "Error fallocating %d\n", errno);
318 if (pwrite(test_fd, buf, 4096, 10 * 4096) < 4096) {
319 fprintf(stderr, "Short write %d\n", errno);
323 if (fsync(test_fd)) {
324 fprintf(stderr, "Fsync failed %d\n", errno);
328 for (i = 13; i < 15; i++) {
329 if (pwrite(test_fd, buf, 4096, i * 4096) < 4096) {
330 fprintf(stderr, "Short write %d\n", errno);
335 if (fsync(test_fd)) {
336 fprintf(stderr, "Fsync failed %d\n", errno);
340 if (pwrite(test_fd, buf, 4096, 18 * 4096) < 4096) {
341 fprintf(stderr, "Short write %d\n", errno);
345 if (fsync(test_fd)) {
346 fprintf(stderr, "Fsync failed %d\n", errno);
350 if (pwrite(test_fd, buf, 4096, 22 * 4096) < 4096) {
351 fprintf(stderr, "Short write %d\n", errno);
355 if (fsync(test_fd)) {
356 fprintf(stderr, "Fsync failed %d\n", errno);
365 printf("Usage fsync-tester [-s <seed>] [-r] [-d] -t <test-num> <filename>\n");
366 printf(" -s seed : seed for teh random map generator (defaults to reading /dev/urandom)\n");
367 printf(" -r : don't reboot the box immediately\n");
368 printf(" -d : use O_DIRECT\n");
369 printf(" -t test : test nr to run, required\n");
373 int main(int argc, char **argv)
379 unsigned int seed = 123;
389 fd = open("/dev/urandom", O_RDONLY);
391 read(fd, &seed, sizeof(seed));
395 while ((opt = getopt(argc, argv, "s:rdt:")) != -1) {
398 tmp = strtol(optarg, &endptr, 10);
399 if (tmp == LONG_MAX || endptr == optarg)
410 test = strtol(optarg, &endptr, 10);
411 if (test == LONG_MAX || endptr == optarg)
423 * test 19 is for smaller than blocksize writes to test btrfs's inline
424 * extent fsyncing, so direct_io doesn't make sense and in fact doesn't
425 * work for other file systems, so just disable direct io for this test.
430 fname = argv[optind];
434 printf("Random seed is %u\n", seed);
438 openflags |= O_DIRECT;
439 ret = posix_memalign((void **)&buf, getpagesize(), 4096);
441 fprintf(stderr, "Error allocating buf: %d\n", ret);
447 fprintf(stderr, "Error allocating buf: %d\n", errno);
452 test_fd = open(fname, openflags | O_CREAT | O_TRUNC, 0644);
454 fprintf(stderr, "Error opening file %d (%s)\n", errno,
461 ret = test_one(&max_blocks);
464 ret = test_two(&max_blocks);
467 ret = test_three(&max_blocks, 0, 0, 0, 0);
470 ret = test_three(&max_blocks, 1, 0, 0, 0);
473 ret = test_three(&max_blocks, 0, 1, 0, 0);
476 ret = test_three(&max_blocks, 1, 1, 0, 0);
479 ret = test_three(&max_blocks, 0, 0, 1, 0);
482 ret = test_three(&max_blocks, 1, 0, 1, 0);
485 ret = test_three(&max_blocks, 0, 1, 1, 0);
488 ret = test_three(&max_blocks, 1, 1, 1, 0);
491 ret = test_three(&max_blocks, 0, 0, 0, 1);
494 ret = test_three(&max_blocks, 0, 1, 0, 1);
497 ret = test_three(&max_blocks, 0, 0, 1, 1);
500 ret = test_three(&max_blocks, 0, 1, 1, 1);
503 ret = test_three(&max_blocks, 1, 0, 0, 1);
506 ret = test_three(&max_blocks, 1, 1, 0, 1);
509 ret = test_three(&max_blocks, 1, 0, 1, 1);
512 ret = test_three(&max_blocks, 1, 1, 1, 1);
522 * This is just a perf test, keep moving it down so it's always
523 * the last test option.
526 ret = test_four(&max_blocks);
535 if (fsync(test_fd)) {
536 fprintf(stderr, "Fsync failed, test results will be invalid: "
541 system("reboot -fn");