17 * Just creates a random file, overwriting the file in a random number of loops
18 * and fsyncing between each loop.
20 static int test_one(int *max_blocks)
22 int loops = (random() % 20) + 5;
24 lseek(test_fd, 0, SEEK_SET);
26 int character = (random() % 126) + 33; /* printable character */
27 int blocks = (random() % 100) + 1;
29 if (blocks > *max_blocks)
31 lseek(test_fd, 0, SEEK_SET);
32 memset(buf, character, 4096);
34 fprintf(stderr, "Fsync failed, test results will be "
35 "invalid: %d\n", errno);
40 if (write(test_fd, buf, 4096) < 4096) {
41 fprintf(stderr, "Short write %d\n", errno);
51 * Preallocate a randomly sized file and then overwrite the entire thing and
54 static int test_two(int *max_blocks)
56 int blocks = (random() % 1024) + 1;
57 int character = (random() % 126) + 33;
61 if (fallocate(test_fd, 0, 0, blocks * 4096)) {
62 fprintf(stderr, "Error fallocating %d (%s)\n", errno,
67 lseek(test_fd, 0, SEEK_SET);
68 memset(buf, character, 4096);
70 if (write(test_fd, buf, 4096) < 4096) {
71 fprintf(stderr, "Short write %d\n", errno);
79 static void drop_all_caches()
84 if ((fd = open("/proc/sys/vm/drop_caches", O_WRONLY)) < 0) {
85 fprintf(stderr, "Error opening drop caches: %d\n", errno);
89 write(fd, value, sizeof(value)-1);
94 * Randomly write inside of a file, either creating a sparse file or prealloc
95 * the file and randomly write within it, depending on the prealloc flag
97 static int test_three(int *max_blocks, int prealloc, int rand_fsync,
98 int do_sync, int drop_caches)
100 int size = (random() % 2048) + 4;
101 int blocks = size / 2;
102 int sync_block = blocks / 2;
103 int rand_sync_interval = (random() % blocks) + 1;
104 int character = (random() % 126) + 33;
106 if (prealloc && fallocate(test_fd, 0, 0, size * 4096)) {
107 fprintf(stderr, "Error fallocating %d (%s)\n", errno,
115 memset(buf, character, 4096);
117 int block = (random() % size);
119 if ((block + 1) > *max_blocks)
120 *max_blocks = block + 1;
122 if (rand_fsync && !(blocks % rand_sync_interval)) {
123 if (fsync(test_fd)) {
124 fprintf(stderr, "Fsync failed, test results "
125 "will be invalid: %d\n", errno);
130 /* Force a transaction commit in between just for fun */
131 if (blocks == sync_block && (do_sync || drop_caches)) {
135 sync_file_range(test_fd, 0, 0,
136 SYNC_FILE_RANGE_WRITE|
137 SYNC_FILE_RANGE_WAIT_AFTER);
142 test_fd = open(fname, O_RDWR);
145 fprintf(stderr, "Error re-opening file: %d\n",
152 if (pwrite(test_fd, buf, 4096, block * 4096) < 4096) {
153 fprintf(stderr, "Short write %d\n", errno);
161 static void timeval_subtract(struct timeval *result,struct timeval *x,
164 if (x->tv_usec < y->tv_usec) {
165 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
166 y->tv_usec -= 1000000 * nsec;
170 if (x->tv_usec - y->tv_usec > 1000000) {
171 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
172 y->tv_usec += 1000000 * nsec;
176 result->tv_sec = x->tv_sec - y->tv_sec;
177 result->tv_usec = x->tv_usec - y->tv_usec;
180 static int test_four(int *max_blocks)
182 size_t size = 2621440; /* 10 gigabytes */
183 size_t blocks = size / 2;
184 size_t sync_block = blocks / 8; /* fsync 8 times */
185 int character = (random() % 126) + 33;
186 struct timeval start, end, diff;
188 memset(buf, character, 4096);
190 off_t block = (random() % size);
192 if ((block + 1) > *max_blocks)
193 *max_blocks = block + 1;
195 if ((blocks % sync_block) == 0) {
196 if (gettimeofday(&start, NULL)) {
197 fprintf(stderr, "Error getting time: %d\n",
201 if (fsync(test_fd)) {
202 fprintf(stderr, "Fsync failed, test results "
203 "will be invalid: %d\n", errno);
206 if (gettimeofday(&end, NULL)) {
207 fprintf(stderr, "Error getting time: %d\n",
211 timeval_subtract(&diff, &end, &start);
212 printf("Fsync time was %ds and %dus\n",
213 (int)diff.tv_sec, (int)diff.tv_usec);
216 if (pwrite(test_fd, buf, 4096, block * 4096) < 4096) {
217 fprintf(stderr, "Short write %d\n", errno);
225 static int test_five()
227 int character = (random() % 126) + 33;
228 int runs = (random() % 100) + 1;
231 memset(buf, character, 3072);
232 for (i = 0; i < runs; i++) {
233 ssize_t write_size = (random() % 3072) + 1;
235 if (pwrite(test_fd, buf, write_size, 0) < write_size) {
236 fprintf(stderr, "Short write %d\n", errno);
241 if (fsync(test_fd)) {
242 fprintf(stderr, "Fsync failed, test results "
243 "will be invalid: %d\n", errno);
253 * Reproducer for something like this
255 * [data][prealloc][data]
257 * and then in the [prealloc] section we have
259 * [ pre ][pre][ pre ]
260 * [d][pp][dd][ppp][d][ppp][d]
262 * where each letter represents on block of either data or prealloc.
264 * This explains all the weirdly specific numbers.
266 static int test_six()
268 int character = (random() % 126) + 33;
271 memset(buf, character, 4096);
273 /* Write on either side of the file, leaving a hole in the middle */
274 for (i = 0; i < 10; i++) {
275 if (pwrite(test_fd, buf, 4096, i * 4096) < 4096) {
276 fprintf(stderr, "Short write %d\n", errno);
281 if (fsync(test_fd)) {
282 fprintf(stderr, "Fsync failed %d\n", errno);
287 * The test fs I had the prealloc extent was 13 4k blocks long so I'm
288 * just using that to give myself the best chances of reproducing.
290 for (i = 23; i < 33; i++) {
291 if (pwrite(test_fd, buf, 4096, i * 4096) < 4096) {
292 fprintf(stderr, "Short write %d\n", errno);
297 if (fsync(test_fd)) {
298 fprintf(stderr, "Fsync failed %d\n", errno);
302 if (fallocate(test_fd, 0, 10 * 4096, 4 * 4096)) {
303 fprintf(stderr, "Error fallocating %d\n", errno);
307 if (fallocate(test_fd, 0, 14 * 4096, 5 * 4096)) {
308 fprintf(stderr, "Error fallocating %d\n", errno);
312 if (fallocate(test_fd, 0, 19 * 4096, 4 * 4096)) {
313 fprintf(stderr, "Error fallocating %d\n", errno);
317 if (pwrite(test_fd, buf, 4096, 10 * 4096) < 4096) {
318 fprintf(stderr, "Short write %d\n", errno);
322 if (fsync(test_fd)) {
323 fprintf(stderr, "Fsync failed %d\n", errno);
327 for (i = 13; i < 15; i++) {
328 if (pwrite(test_fd, buf, 4096, i * 4096) < 4096) {
329 fprintf(stderr, "Short write %d\n", errno);
334 if (fsync(test_fd)) {
335 fprintf(stderr, "Fsync failed %d\n", errno);
339 if (pwrite(test_fd, buf, 4096, 18 * 4096) < 4096) {
340 fprintf(stderr, "Short write %d\n", errno);
344 if (fsync(test_fd)) {
345 fprintf(stderr, "Fsync failed %d\n", errno);
349 if (pwrite(test_fd, buf, 4096, 22 * 4096) < 4096) {
350 fprintf(stderr, "Short write %d\n", errno);
354 if (fsync(test_fd)) {
355 fprintf(stderr, "Fsync failed %d\n", errno);
364 printf("Usage fsync-tester [-s <seed>] [-r] [-d] -t <test-num> <filename>\n");
365 printf(" -s seed : seed for teh random map generator (defaults to reading /dev/urandom)\n");
366 printf(" -r : don't reboot the box immediately\n");
367 printf(" -d : use O_DIRECT\n");
368 printf(" -t test : test nr to run, required\n");
372 int main(int argc, char **argv)
378 unsigned int seed = 123;
384 int flags = O_RDWR|O_CREAT|O_TRUNC;
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);
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, flags, 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");