2 * Copyright (c) 2010-2011 IBM
5 * Chunqiang Tang <ctang@us.ibm.com>
7 * This work is licensed under the terms of the GNU GPL, version 2.
8 * See the COPYING file in the top-level directory.
11 /*=============================================================================
12 * A short description: this module implements a fully automated testing tool
13 * for block device drivers. It works with block/sim.c.
14 *=============================================================================
17 #include "qemu/osdep.h"
20 #include "qemu/timer.h"
21 #include "block/block_int.h"
22 #include "block/fvd-ext.h"
23 #include "block/blksim.h"
25 #define die(format,...) \
27 fprintf (stderr, "%s:%d --- ", __FILE__, __LINE__); \
28 fprintf (stderr, format, ##__VA_ARGS__); \
32 typedef enum { OP_NULL
= 0, OP_READ
, OP_WRITE
, OP_FLUSH
} op_type_t
;
33 const char *op_type_str
[] = { "NULL ", "READ ", "WRITE", "FLUSH" };
35 typedef struct CompareFullCB
{
44 typedef struct RandomIO
{
54 BlockDriverAIOCB
*acb
;
57 static char *progname
;
58 static BlockDriverState
*bs
;
60 static int64_t total_sectors
;
61 static int64_t io_size
= 262144;
62 static int verify_write
= TRUE
;
63 static int parallel
= 1;
64 static int max_iov
= 10;
65 static int64_t round
= 10;
66 static int64_t finished_round
= 0;
67 static RandomIO
*testers
= NULL
;
68 static double fail_prob
= 0;
69 static double cancel_prob
= 0;
70 static double flush_prob
= 0;
71 static int64_t rand_time
= 1000;
72 static int64_t test_uuid
= 0;
73 static int instant_qemubh
= FALSE
;
75 static void rand_io_cb (void *opaque
, int ret
);
76 static void perform_next_io (RandomIO
* r
);
78 int64_t qemu_get_clock (QEMUClock
* clock
)
80 return sim_get_time ();
83 void timer_mod(QEMUTimer
*ts
, int64_t expire_time
)
85 sim_mod_timer (ts
, expire_time
);
88 QEMUTimer
*qemu_new_timer (QEMUClock
* clock
, QEMUTimerCB
* cb
, void *opaque
)
90 return sim_new_timer (cb
, opaque
);
93 void timer_free(QEMUTimer
*ts
)
98 void timer_del(QEMUTimer
*ts
)
103 QEMUBH
*qemu_bh_new (QEMUBHFunc
* cb
, void *opaque
)
105 return sim_new_timer (cb
, opaque
);
108 int qemu_bh_poll (void)
113 void qemu_bh_schedule (QEMUBH
* bh
)
115 if (instant_qemubh
) {
116 sim_mod_timer (bh
, -1); /* Run this bh next. */
118 sim_mod_timer (bh
, sim_get_time ());
122 void qemu_bh_cancel (QEMUBH
* bh
)
127 void qemu_bh_delete (QEMUBH
* bh
)
132 static void usage (void)
134 printf ("%s [--help]\n"
135 "\t--truth=<truth_img>\n"
136 "\t--test=<img_to_test>\n"
137 "\t[--format=<test_img_fmt>]\n"
139 "\t[--instant_qemubh=<true|false>]\n"
140 "\t[--fail_prob=<#f>]\n"
141 "\t[--cancel_prob=<#f>]\n"
142 "\t[--flush_prob=<#f>]\n"
143 "\t[--io_size=<#d>]\n"
144 "\t[--verify_write=[true|false]]\n"
145 "\t[--parallel=[#d]\n"
146 "\t[--max_iov=[#d]\n"
147 "\t[--compare_before=[true|false]]\n"
148 "\t[--compare_after=[true|false]]\n" "\n", progname
);
152 static int truth_io (void *buf
, int64_t sector_num
, int nb_sectors
, int do_read
)
154 off_t offset
= sector_num
* 512;
155 size_t size
= nb_sectors
* 512;
160 r
= pread (fd
, buf
, size
, offset
);
162 r
= pwrite (fd
, buf
, size
, offset
);
167 buf
= (void *) (((char *) buf
) + r
);
168 } else if (errno
!= EINTR
) {
170 die ("I/O error on the truth file.\n");
178 static int verify (uint8_t * truth_buf
, uint8_t * test_buf
,
179 int64_t sector_num
, int nb_sectors
)
182 for (i
= 0; i
< nb_sectors
; i
++) {
183 int64_t offset
= i
* 512;
184 if (memcmp (&truth_buf
[offset
], &test_buf
[offset
], 512) != 0) {
186 printf ("Sector %" PRId64
" differs\n", sector_num
+ i
);
187 QDEBUG ("Sector %" PRId64
" differs\n", sector_num
+ i
);
188 for (j
= 0; j
< 512; j
++) {
189 if (truth_buf
[offset
+ j
] == test_buf
[offset
+ j
]) {
190 QDEBUG ("%02d: %02X %02X\n", j
, truth_buf
[offset
+ j
],
191 test_buf
[offset
+ j
]);
193 QDEBUG ("%02d: %02X %02X ***\n", j
,
194 truth_buf
[offset
+ j
], test_buf
[offset
+ j
]);
198 fprintf (stderr
, "Pause process %d for debugging...\n", getpid ());
208 static void compare_full_images_cb (void *opaque
, int ret
)
210 CompareFullCB
*cf
= opaque
;
213 /* Failed. Retry the operation. */
214 bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
, cf
->nb_sectors
,
215 compare_full_images_cb
, cf
);
219 truth_io (cf
->truth_buf
, cf
->sector_num
, cf
->nb_sectors
, TRUE
);
220 verify (cf
->truth_buf
, cf
->iov
.iov_base
, cf
->sector_num
, cf
->nb_sectors
);
222 cf
->sector_num
+= cf
->nb_sectors
;
223 if (cf
->sector_num
>= total_sectors
) {
225 free (cf
->truth_buf
);
226 qemu_vfree (cf
->iov
.iov_base
);
231 /* Read more data to compare. */
232 if (cf
->sector_num
+ cf
->max_nb_sectors
> total_sectors
) {
233 cf
->nb_sectors
= total_sectors
- cf
->sector_num
;
235 cf
->nb_sectors
= cf
->max_nb_sectors
;
237 cf
->iov
.iov_len
= cf
->nb_sectors
* 512;
238 qemu_iovec_init_external (&cf
->qiov
, &cf
->iov
, 1);
239 if (!bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
,
240 cf
->nb_sectors
, compare_full_images_cb
, cf
)) {
241 die ("bdrv_aio_readv\n");
245 static int compare_full_images (void)
248 int old_copy_on_read
= FALSE
;
250 printf ("Performing a full comparison of the truth image and "
251 "the test image...\n");
253 if (!strncmp (bs
->drv
->format_name
, "fvd", 3)) {
254 /* Disable copy-on-read when scanning through the entire image. */
255 old_copy_on_read
= fvd_get_copy_on_read (bs
);
256 fvd_set_copy_on_read (bs
, FALSE
);
259 cf
= g_malloc(sizeof(CompareFullCB
));
260 cf
->max_nb_sectors
= 1048576L / 512;
261 cf
->nb_sectors
= MIN (cf
->max_nb_sectors
, total_sectors
);
262 if (posix_memalign ((void **) &cf
->truth_buf
, 512,
263 cf
->max_nb_sectors
* 512) != 0) {
264 die ("posix_memalign");
266 cf
->iov
.iov_base
= qemu_blockalign (bs
, cf
->max_nb_sectors
* 512);
267 cf
->iov
.iov_len
= cf
->nb_sectors
* 512;
269 qemu_iovec_init_external (&cf
->qiov
, &cf
->iov
, 1);
270 if (!bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
,
271 cf
->nb_sectors
, compare_full_images_cb
, cf
)) {
272 die ("bdrv_aio_readv\n");
277 if (!strncmp (bs
->drv
->format_name
, "fvd", 3)) {
278 fvd_set_copy_on_read (bs
, old_copy_on_read
);
284 static inline int64_t rand64 (void)
286 int64_t f1
= random ();
287 int64_t f2
= random ();
288 int64_t f3
= (f1
<< 32) | f2
;
289 return f3
>= 0 ? f3
: -f3
;
292 static int check_conflict (RandomIO
* r
)
296 for (i
= 0; i
< parallel
; i
++) {
297 RandomIO
*s
= &testers
[i
];
298 if (s
== r
|| s
->type
== OP_FLUSH
||
299 (r
->type
== OP_READ
&& s
->type
== OP_READ
)) {
303 if ((r
->sector_num
<= s
->sector_num
&&
304 s
->sector_num
< r
->sector_num
+ r
->nb_sectors
) ||
305 (s
->sector_num
<= r
->sector_num
&&
306 r
->sector_num
< s
->sector_num
+ s
->nb_sectors
)) {
307 return 1; /* Conflict. */
311 return 0; /* No confict. */
314 /* Return FALSE if the submitted request is cancelled. */
315 static int submit_rand_io (RandomIO
* r
)
317 BlockDriverAIOCB
*acb
= NULL
;
319 QDEBUG ("TESTER %03d: %s test%" PRIX64
" sector_num=%" PRId64
320 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
321 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
322 printf ("TESTER %03d: %s sector_num=%" PRId64
" nb_sectors=%d niov=%d\n",
323 r
->tester
, op_type_str
[r
->type
], r
->sector_num
, r
->nb_sectors
,
327 if (fail_prob
<= 0) {
329 } else if (random () / (double) RAND_MAX
<= fail_prob
) {
335 /* This affects whether this request will fail or not. */
336 sim_set_disk_io_return_code (ret
);
340 if (!(acb
= bdrv_aio_readv (bs
, r
->sector_num
, &r
->qiov
, r
->nb_sectors
,
342 die ("bdrv_aio_readv\n");
346 if (!(acb
= bdrv_aio_writev (bs
, r
->sector_num
, &r
->qiov
, r
->nb_sectors
,
348 die ("bdrv_aio_writev\n");
352 if (!(acb
= bdrv_aio_flush (bs
, rand_io_cb
, r
))) {
353 die ("bdrv_aio_flush\n");
361 sim_set_disk_io_return_code (0); /* Reset to no failure state. */
363 if (r
->allow_cancel
&& cancel_prob
> 0 &&
364 random () / (double) RAND_MAX
<= cancel_prob
) {
365 QDEBUG ("TESTER %03d: cancel %s test%" PRIX64
" sector_num=%" PRId64
366 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
367 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
368 printf ("TESTER %03d: cancel %s sector_num=%" PRId64
369 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
370 r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
371 bdrv_aio_cancel (acb
);
378 static void prepare_read_write (RandomIO
* r
)
380 /* Do a READ or WRITE? */
387 /* Find the next region to perform io. */
389 if (parallel
<= 1 || (random () % 2 == 0)) {
390 /* Perform a random I/O. */
391 r
->sector_num
= rand64 () % total_sectors
;
393 /* Perform an I/O next to a currently ongoing I/O. */
396 id
= random () % parallel
;
397 } while (id
== r
->tester
);
399 RandomIO
*p
= &testers
[id
];
401 p
->sector_num
+ 2 * io_size
- rand64 () % (4 * io_size
);
402 if (r
->sector_num
< 0) {
404 } else if (r
->sector_num
>= total_sectors
) {
405 r
->sector_num
= total_sectors
- 1;
409 r
->nb_sectors
= 1 + rand64 () % io_size
;
410 if (r
->sector_num
+ r
->nb_sectors
> total_sectors
) {
411 r
->nb_sectors
= total_sectors
- r
->sector_num
;
413 } while (check_conflict (r
));
415 if (r
->type
== OP_WRITE
) {
416 /* Fill test_buf with random data. */
418 for (i
= 0; i
< r
->nb_sectors
; i
++) {
419 const uint64_t TEST_MAGIC
= 0x0123456789ABCDEFULL
;
420 /* This first 8 bytes of the sector stores the current testing
421 * round. The next 8 bytes store a magic number. This info helps
423 uint64_t *p
= (uint64_t *) & r
->test_buf
[i
* 512];
430 /* The rest of the sector are filled with random data. */
431 uint32_t *q
= (uint32_t *) (p
+ 1);
432 int n
= (512 - 2 * sizeof (uint64_t)) / sizeof (uint32_t);
433 for (j
= 0; j
< n
; j
++) {
439 /* Determine the number of iov. */
441 uint8_t *p
= r
->test_buf
;
442 int left
= r
->nb_sectors
;
444 if (niov
== max_iov
- 1) {
445 r
->qiov
.iov
[niov
].iov_len
= left
* 512;
446 r
->qiov
.iov
[niov
].iov_base
= p
;
451 int nb
= 1 + random () % left
;
452 r
->qiov
.iov
[niov
].iov_len
= nb
* 512;
453 r
->qiov
.iov
[niov
].iov_base
= p
;
454 p
+= r
->qiov
.iov
[niov
].iov_len
;
459 qemu_iovec_init_external (&r
->qiov
, r
->qiov
.iov
, niov
);
462 static void perform_next_io (RandomIO
* r
)
464 if (finished_round
>= round
) {
469 r
->allow_cancel
= TRUE
;
472 r
->uuid
= test_uuid
++;
474 if (flush_prob
> 0 && random () / (double) RAND_MAX
< flush_prob
) {
477 prepare_read_write (r
);
479 } while (!submit_rand_io (r
));
482 static void rand_io_cb (void *opaque
, int ret
)
484 RandomIO
*r
= opaque
;
487 if (fail_prob
<= 0) {
488 fprintf (stderr
, "Request %s sector_num=%" PRId64
489 " nb_sectors=%d failed while fail_prob=0. "
490 "Pause for debugging...\n",
491 op_type_str
[r
->type
], r
->sector_num
, r
->nb_sectors
);
494 /* Failed. Retry the operation. */
495 QDEBUG ("TESTER %03d: retry %s test%" PRIX64
" sector_num=%"
496 PRId64
" nb_sectors=%d niov=%d\n",
497 r
->tester
, op_type_str
[r
->type
], r
->uuid
,
498 r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
499 if (!submit_rand_io (r
)) {
505 QDEBUG ("TESTER %03d: finished %s test%" PRIX64
" sector_num=%"PRId64
506 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
507 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
516 truth_io (r
->truth_buf
, r
->sector_num
, r
->nb_sectors
, TRUE
);
517 verify (r
->truth_buf
, r
->test_buf
, r
->sector_num
, r
->nb_sectors
);
522 truth_io (r
->test_buf
, r
->sector_num
, r
->nb_sectors
, FALSE
);
524 /* Perform a read for the same data. */
527 /* To verify the write, this read cannot be cancelled. */
528 r
->allow_cancel
= FALSE
;
530 r
->qiov
.iov
[0].iov_len
= r
->qiov
.size
;
531 memset (r
->test_buf
, 0xA5, r
->qiov
.size
); /* Fill in garbage. */
544 static int read_bool (const char *arg
)
547 if (strcmp (optarg
, "true") == 0) {
549 } else if (strcmp (optarg
, "false") == 0) {
552 printf ("%s is neither 'true' nor 'false'\n", arg
);
560 static void perform_test(const char *truth_file
, const char *test_file
,
561 const char *format
, int compare_before
,
566 bs
= bdrv_new ("hda");
568 die ("bdrv_new failed\n");
571 BlockDriver
*drv
= NULL
;
573 drv
= bdrv_find_format (format
);
575 die ("Found no driver for format '%s'.\n", format
);
579 flags
= BDRV_O_RDWR
| BDRV_O_CACHE_WB
;
581 if (bdrv_open (bs
, test_file
, flags
, drv
) < 0) {
582 die ("Failed to open '%s'\n", test_file
);
585 fd
= open (truth_file
, O_RDWR
| O_LARGEFILE
, 0);
588 die ("Failed to open '%s'\n", truth_file
);
591 int64_t l0
= lseek (fd
, 0, SEEK_END
);
592 int64_t l1
= bdrv_getlength (bs
);
593 if (l0
< 0 || l1
< 0 || l0
< l1
) {
594 die ("Mismatch: truth image %s length %" PRId64
", test image %s "
595 "length %" PRId64
"\n", truth_file
, l0
, test_file
, l1
);
598 total_sectors
= l1
/ 512;
599 if (total_sectors
<= 1) {
600 die ("Total sectors: %" PRId64
"\n", total_sectors
);
606 } else if (io_size
> total_sectors
/ 2) {
607 io_size
= total_sectors
/ 2;
610 if (compare_before
) {
611 if (compare_full_images ()) {
612 die ("The original two files do not match.\n");
617 /* Create testers. */
618 testers
= g_malloc(sizeof(RandomIO
) * parallel
);
619 for (i
= 0; i
< parallel
; i
++) {
620 RandomIO
*r
= &testers
[i
];
621 r
->test_buf
= qemu_blockalign (bs
, io_size
* 512);
622 if (posix_memalign ((void **) &r
->truth_buf
, 512, io_size
* 512)) {
623 die ("posix_memalign");
625 r
->qiov
.iov
= g_malloc(sizeof(struct iovec
) * max_iov
);
631 for (i
= 0; i
< parallel
; i
++) {
632 perform_next_io (&testers
[i
]);
636 sim_all_tasks (); /* Run tests. */
639 /* Create testers. */
641 if (compare_full_images ()) {
642 die ("The two files do not match after I/O operations.\n");
646 for (i
= 0; i
< parallel
; i
++) {
647 RandomIO
*r
= &testers
[i
];
648 qemu_vfree (r
->test_buf
);
655 printf ("Test process %d finished successfully\n", getpid ());
657 int fvd
= (strncmp (bs
->drv
->format_name
, "fvd", 3) == 0);
660 fvd_check_memory_usage ();
665 int main (int argc
, char **argv
)
668 const char *truth_file
= NULL
;
669 const char *test_file
= NULL
;
670 const char *format
= NULL
;
671 int compare_before
= FALSE
;
672 int compare_after
= TRUE
;
675 const struct option lopt
[] = {
678 {"truth", 1, 0, 'b'},
680 {"format", 1, 0, 'f'},
681 {"rand_time", 1, 0, 'n'},
682 {"fail_prob", 1, 0, 'u'},
683 {"cancel_prob", 1, 0, 'c'},
684 {"flush_prob", 1, 0, 'w'},
685 {"round", 1, 0, 'r'},
686 {"parallel", 1, 0, 'p'},
687 {"compare_before", 1, 0, 'm'},
688 {"verify_write", 1, 0, 'v'},
689 {"compare_after", 1, 0, 'a'},
690 {"max_iov", 1, 0, 'i'},
691 {"io_size", 1, 0, 's'},
692 {"instant_qemubh", 1, 0, 'q'},
696 progname
= basename (argv
[0]);
698 while ((c
= getopt_long (argc
, argv
, "hc:u:p:q:i:f:d:b:t:r:m:v:a:s:",
699 lopt
, NULL
)) != -1) {
706 instant_qemubh
= read_bool (optarg
);
710 flush_prob
= atof (optarg
);
714 cancel_prob
= atof (optarg
);
718 fail_prob
= atof (optarg
);
722 rand_time
= atoll (optarg
);
726 max_iov
= atoi (optarg
);
730 parallel
= atoi (optarg
);
734 verify_write
= read_bool (optarg
);
738 compare_before
= read_bool (optarg
);
742 compare_after
= read_bool (optarg
);
746 seed
= atoll (optarg
);
762 io_size
= atoll (optarg
);
766 round
= atoll (optarg
);
775 if (!truth_file
|| !test_file
) {
784 /* Convince FVD this is not in a qemu-tool. */
785 in_qemu_tool
= false;
786 enable_block_sim (FALSE
/*no print */ , rand_time
);
787 fvd_enable_host_crash_test ();
789 perform_test (truth_file
, test_file
, format
, compare_before
, compare_after
);