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 *=============================================================================
18 #include <sys/types.h>
21 #include "qemu-common.h"
22 #include "qemu/timer.h"
23 #include "block/block_int.h"
24 #include "block/fvd-ext.h"
25 #include "block/blksim.h"
27 #define die(format,...) \
29 fprintf (stderr, "%s:%d --- ", __FILE__, __LINE__); \
30 fprintf (stderr, format, ##__VA_ARGS__); \
34 typedef enum { OP_NULL
= 0, OP_READ
, OP_WRITE
, OP_FLUSH
} op_type_t
;
35 const char *op_type_str
[] = { "NULL ", "READ ", "WRITE", "FLUSH" };
37 typedef struct CompareFullCB
{
46 typedef struct RandomIO
{
56 BlockDriverAIOCB
*acb
;
59 static char *progname
;
60 static BlockDriverState
*bs
;
62 static int64_t total_sectors
;
63 static int64_t io_size
= 262144;
64 static int verify_write
= TRUE
;
65 static int parallel
= 1;
66 static int max_iov
= 10;
67 static int64_t round
= 10;
68 static int64_t finished_round
= 0;
69 static RandomIO
*testers
= NULL
;
70 static double fail_prob
= 0;
71 static double cancel_prob
= 0;
72 static double flush_prob
= 0;
73 static int64_t rand_time
= 1000;
74 static int64_t test_uuid
= 0;
75 static int instant_qemubh
= FALSE
;
77 static void rand_io_cb (void *opaque
, int ret
);
78 static void perform_next_io (RandomIO
* r
);
80 int64_t qemu_get_clock (QEMUClock
* clock
)
82 return sim_get_time ();
85 void timer_mod(QEMUTimer
*ts
, int64_t expire_time
)
87 sim_mod_timer (ts
, expire_time
);
90 QEMUTimer
*qemu_new_timer (QEMUClock
* clock
, QEMUTimerCB
* cb
, void *opaque
)
92 return sim_new_timer (cb
, opaque
);
95 void timer_free(QEMUTimer
*ts
)
100 void timer_del(QEMUTimer
*ts
)
105 QEMUBH
*qemu_bh_new (QEMUBHFunc
* cb
, void *opaque
)
107 return sim_new_timer (cb
, opaque
);
110 int qemu_bh_poll (void)
115 void qemu_bh_schedule (QEMUBH
* bh
)
117 if (instant_qemubh
) {
118 sim_mod_timer (bh
, -1); /* Run this bh next. */
120 sim_mod_timer (bh
, sim_get_time ());
124 void qemu_bh_cancel (QEMUBH
* bh
)
129 void qemu_bh_delete (QEMUBH
* bh
)
134 static void usage (void)
136 printf ("%s [--help]\n"
137 "\t--truth=<truth_img>\n"
138 "\t--test=<img_to_test>\n"
139 "\t[--format=<test_img_fmt>]\n"
141 "\t[--instant_qemubh=<true|false>]\n"
142 "\t[--fail_prob=<#f>]\n"
143 "\t[--cancel_prob=<#f>]\n"
144 "\t[--flush_prob=<#f>]\n"
145 "\t[--io_size=<#d>]\n"
146 "\t[--verify_write=[true|false]]\n"
147 "\t[--parallel=[#d]\n"
148 "\t[--max_iov=[#d]\n"
149 "\t[--compare_before=[true|false]]\n"
150 "\t[--compare_after=[true|false]]\n" "\n", progname
);
154 static int truth_io (void *buf
, int64_t sector_num
, int nb_sectors
, int do_read
)
156 off_t offset
= sector_num
* 512;
157 size_t size
= nb_sectors
* 512;
162 r
= pread (fd
, buf
, size
, offset
);
164 r
= pwrite (fd
, buf
, size
, offset
);
169 buf
= (void *) (((char *) buf
) + r
);
170 } else if (errno
!= EINTR
) {
172 die ("I/O error on the truth file.\n");
180 static int verify (uint8_t * truth_buf
, uint8_t * test_buf
,
181 int64_t sector_num
, int nb_sectors
)
184 for (i
= 0; i
< nb_sectors
; i
++) {
185 int64_t offset
= i
* 512;
186 if (memcmp (&truth_buf
[offset
], &test_buf
[offset
], 512) != 0) {
188 printf ("Sector %" PRId64
" differs\n", sector_num
+ i
);
189 QDEBUG ("Sector %" PRId64
" differs\n", sector_num
+ i
);
190 for (j
= 0; j
< 512; j
++) {
191 if (truth_buf
[offset
+ j
] == test_buf
[offset
+ j
]) {
192 QDEBUG ("%02d: %02X %02X\n", j
, truth_buf
[offset
+ j
],
193 test_buf
[offset
+ j
]);
195 QDEBUG ("%02d: %02X %02X ***\n", j
,
196 truth_buf
[offset
+ j
], test_buf
[offset
+ j
]);
200 fprintf (stderr
, "Pause process %d for debugging...\n", getpid ());
210 static void compare_full_images_cb (void *opaque
, int ret
)
212 CompareFullCB
*cf
= opaque
;
215 /* Failed. Retry the operation. */
216 bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
, cf
->nb_sectors
,
217 compare_full_images_cb
, cf
);
221 truth_io (cf
->truth_buf
, cf
->sector_num
, cf
->nb_sectors
, TRUE
);
222 verify (cf
->truth_buf
, cf
->iov
.iov_base
, cf
->sector_num
, cf
->nb_sectors
);
224 cf
->sector_num
+= cf
->nb_sectors
;
225 if (cf
->sector_num
>= total_sectors
) {
227 free (cf
->truth_buf
);
228 qemu_vfree (cf
->iov
.iov_base
);
233 /* Read more data to compare. */
234 if (cf
->sector_num
+ cf
->max_nb_sectors
> total_sectors
) {
235 cf
->nb_sectors
= total_sectors
- cf
->sector_num
;
237 cf
->nb_sectors
= cf
->max_nb_sectors
;
239 cf
->iov
.iov_len
= cf
->nb_sectors
* 512;
240 qemu_iovec_init_external (&cf
->qiov
, &cf
->iov
, 1);
241 if (!bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
,
242 cf
->nb_sectors
, compare_full_images_cb
, cf
)) {
243 die ("bdrv_aio_readv\n");
247 static int compare_full_images (void)
250 int old_copy_on_read
= FALSE
;
252 printf ("Performing a full comparison of the truth image and "
253 "the test image...\n");
255 if (!strncmp (bs
->drv
->format_name
, "fvd", 3)) {
256 /* Disable copy-on-read when scanning through the entire image. */
257 old_copy_on_read
= fvd_get_copy_on_read (bs
);
258 fvd_set_copy_on_read (bs
, FALSE
);
261 cf
= g_malloc(sizeof(CompareFullCB
));
262 cf
->max_nb_sectors
= 1048576L / 512;
263 cf
->nb_sectors
= MIN (cf
->max_nb_sectors
, total_sectors
);
264 if (posix_memalign ((void **) &cf
->truth_buf
, 512,
265 cf
->max_nb_sectors
* 512) != 0) {
266 die ("posix_memalign");
268 cf
->iov
.iov_base
= qemu_blockalign (bs
, cf
->max_nb_sectors
* 512);
269 cf
->iov
.iov_len
= cf
->nb_sectors
* 512;
271 qemu_iovec_init_external (&cf
->qiov
, &cf
->iov
, 1);
272 if (!bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
,
273 cf
->nb_sectors
, compare_full_images_cb
, cf
)) {
274 die ("bdrv_aio_readv\n");
279 if (!strncmp (bs
->drv
->format_name
, "fvd", 3)) {
280 fvd_set_copy_on_read (bs
, old_copy_on_read
);
286 static inline int64_t rand64 (void)
288 int64_t f1
= random ();
289 int64_t f2
= random ();
290 int64_t f3
= (f1
<< 32) | f2
;
291 return f3
>= 0 ? f3
: -f3
;
294 static int check_conflict (RandomIO
* r
)
298 for (i
= 0; i
< parallel
; i
++) {
299 RandomIO
*s
= &testers
[i
];
300 if (s
== r
|| s
->type
== OP_FLUSH
||
301 (r
->type
== OP_READ
&& s
->type
== OP_READ
)) {
305 if ((r
->sector_num
<= s
->sector_num
&&
306 s
->sector_num
< r
->sector_num
+ r
->nb_sectors
) ||
307 (s
->sector_num
<= r
->sector_num
&&
308 r
->sector_num
< s
->sector_num
+ s
->nb_sectors
)) {
309 return 1; /* Conflict. */
313 return 0; /* No confict. */
316 /* Return FALSE if the submitted request is cancelled. */
317 static int submit_rand_io (RandomIO
* r
)
319 BlockDriverAIOCB
*acb
= NULL
;
321 QDEBUG ("TESTER %03d: %s test%" PRIX64
" sector_num=%" PRId64
322 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
323 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
324 printf ("TESTER %03d: %s sector_num=%" PRId64
" nb_sectors=%d niov=%d\n",
325 r
->tester
, op_type_str
[r
->type
], r
->sector_num
, r
->nb_sectors
,
329 if (fail_prob
<= 0) {
331 } else if (random () / (double) RAND_MAX
<= fail_prob
) {
337 /* This affects whether this request will fail or not. */
338 sim_set_disk_io_return_code (ret
);
342 if (!(acb
= bdrv_aio_readv (bs
, r
->sector_num
, &r
->qiov
, r
->nb_sectors
,
344 die ("bdrv_aio_readv\n");
348 if (!(acb
= bdrv_aio_writev (bs
, r
->sector_num
, &r
->qiov
, r
->nb_sectors
,
350 die ("bdrv_aio_writev\n");
354 if (!(acb
= bdrv_aio_flush (bs
, rand_io_cb
, r
))) {
355 die ("bdrv_aio_flush\n");
363 sim_set_disk_io_return_code (0); /* Reset to no failure state. */
365 if (r
->allow_cancel
&& cancel_prob
> 0 &&
366 random () / (double) RAND_MAX
<= cancel_prob
) {
367 QDEBUG ("TESTER %03d: cancel %s test%" PRIX64
" sector_num=%" PRId64
368 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
369 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
370 printf ("TESTER %03d: cancel %s sector_num=%" PRId64
371 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
372 r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
373 bdrv_aio_cancel (acb
);
380 static void prepare_read_write (RandomIO
* r
)
382 /* Do a READ or WRITE? */
389 /* Find the next region to perform io. */
391 if (parallel
<= 1 || (random () % 2 == 0)) {
392 /* Perform a random I/O. */
393 r
->sector_num
= rand64 () % total_sectors
;
395 /* Perform an I/O next to a currently ongoing I/O. */
398 id
= random () % parallel
;
399 } while (id
== r
->tester
);
401 RandomIO
*p
= &testers
[id
];
403 p
->sector_num
+ 2 * io_size
- rand64 () % (4 * io_size
);
404 if (r
->sector_num
< 0) {
406 } else if (r
->sector_num
>= total_sectors
) {
407 r
->sector_num
= total_sectors
- 1;
411 r
->nb_sectors
= 1 + rand64 () % io_size
;
412 if (r
->sector_num
+ r
->nb_sectors
> total_sectors
) {
413 r
->nb_sectors
= total_sectors
- r
->sector_num
;
415 } while (check_conflict (r
));
417 if (r
->type
== OP_WRITE
) {
418 /* Fill test_buf with random data. */
420 for (i
= 0; i
< r
->nb_sectors
; i
++) {
421 const uint64_t TEST_MAGIC
= 0x0123456789ABCDEFULL
;
422 /* This first 8 bytes of the sector stores the current testing
423 * round. The next 8 bytes store a magic number. This info helps
425 uint64_t *p
= (uint64_t *) & r
->test_buf
[i
* 512];
432 /* The rest of the sector are filled with random data. */
433 uint32_t *q
= (uint32_t *) (p
+ 1);
434 int n
= (512 - 2 * sizeof (uint64_t)) / sizeof (uint32_t);
435 for (j
= 0; j
< n
; j
++) {
441 /* Determine the number of iov. */
443 uint8_t *p
= r
->test_buf
;
444 int left
= r
->nb_sectors
;
446 if (niov
== max_iov
- 1) {
447 r
->qiov
.iov
[niov
].iov_len
= left
* 512;
448 r
->qiov
.iov
[niov
].iov_base
= p
;
453 int nb
= 1 + random () % left
;
454 r
->qiov
.iov
[niov
].iov_len
= nb
* 512;
455 r
->qiov
.iov
[niov
].iov_base
= p
;
456 p
+= r
->qiov
.iov
[niov
].iov_len
;
461 qemu_iovec_init_external (&r
->qiov
, r
->qiov
.iov
, niov
);
464 static void perform_next_io (RandomIO
* r
)
466 if (finished_round
>= round
) {
471 r
->allow_cancel
= TRUE
;
474 r
->uuid
= test_uuid
++;
476 if (flush_prob
> 0 && random () / (double) RAND_MAX
< flush_prob
) {
479 prepare_read_write (r
);
481 } while (!submit_rand_io (r
));
484 static void rand_io_cb (void *opaque
, int ret
)
486 RandomIO
*r
= opaque
;
489 if (fail_prob
<= 0) {
490 fprintf (stderr
, "Request %s sector_num=%" PRId64
491 " nb_sectors=%d failed while fail_prob=0. "
492 "Pause for debugging...\n",
493 op_type_str
[r
->type
], r
->sector_num
, r
->nb_sectors
);
496 /* Failed. Retry the operation. */
497 QDEBUG ("TESTER %03d: retry %s test%" PRIX64
" sector_num=%"
498 PRId64
" nb_sectors=%d niov=%d\n",
499 r
->tester
, op_type_str
[r
->type
], r
->uuid
,
500 r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
501 if (!submit_rand_io (r
)) {
507 QDEBUG ("TESTER %03d: finished %s test%" PRIX64
" sector_num=%"PRId64
508 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
509 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
518 truth_io (r
->truth_buf
, r
->sector_num
, r
->nb_sectors
, TRUE
);
519 verify (r
->truth_buf
, r
->test_buf
, r
->sector_num
, r
->nb_sectors
);
524 truth_io (r
->test_buf
, r
->sector_num
, r
->nb_sectors
, FALSE
);
526 /* Perform a read for the same data. */
529 /* To verify the write, this read cannot be cancelled. */
530 r
->allow_cancel
= FALSE
;
532 r
->qiov
.iov
[0].iov_len
= r
->qiov
.size
;
533 memset (r
->test_buf
, 0xA5, r
->qiov
.size
); /* Fill in garbage. */
546 static int read_bool (const char *arg
)
549 if (strcmp (optarg
, "true") == 0) {
551 } else if (strcmp (optarg
, "false") == 0) {
554 printf ("%s is neither 'true' nor 'false'\n", arg
);
562 static void perform_test(const char *truth_file
, const char *test_file
,
563 const char *format
, int compare_before
,
568 bs
= bdrv_new ("hda");
570 die ("bdrv_new failed\n");
573 BlockDriver
*drv
= NULL
;
575 drv
= bdrv_find_format (format
);
577 die ("Found no driver for format '%s'.\n", format
);
581 flags
= BDRV_O_RDWR
| BDRV_O_CACHE_WB
;
583 if (bdrv_open (bs
, test_file
, flags
, drv
) < 0) {
584 die ("Failed to open '%s'\n", test_file
);
587 fd
= open (truth_file
, O_RDWR
| O_LARGEFILE
, 0);
590 die ("Failed to open '%s'\n", truth_file
);
593 int64_t l0
= lseek (fd
, 0, SEEK_END
);
594 int64_t l1
= bdrv_getlength (bs
);
595 if (l0
< 0 || l1
< 0 || l0
< l1
) {
596 die ("Mismatch: truth image %s length %" PRId64
", test image %s "
597 "length %" PRId64
"\n", truth_file
, l0
, test_file
, l1
);
600 total_sectors
= l1
/ 512;
601 if (total_sectors
<= 1) {
602 die ("Total sectors: %" PRId64
"\n", total_sectors
);
608 } else if (io_size
> total_sectors
/ 2) {
609 io_size
= total_sectors
/ 2;
612 if (compare_before
) {
613 if (compare_full_images ()) {
614 die ("The original two files do not match.\n");
619 /* Create testers. */
620 testers
= g_malloc(sizeof(RandomIO
) * parallel
);
621 for (i
= 0; i
< parallel
; i
++) {
622 RandomIO
*r
= &testers
[i
];
623 r
->test_buf
= qemu_blockalign (bs
, io_size
* 512);
624 if (posix_memalign ((void **) &r
->truth_buf
, 512, io_size
* 512)) {
625 die ("posix_memalign");
627 r
->qiov
.iov
= g_malloc(sizeof(struct iovec
) * max_iov
);
633 for (i
= 0; i
< parallel
; i
++) {
634 perform_next_io (&testers
[i
]);
638 sim_all_tasks (); /* Run tests. */
641 /* Create testers. */
643 if (compare_full_images ()) {
644 die ("The two files do not match after I/O operations.\n");
648 for (i
= 0; i
< parallel
; i
++) {
649 RandomIO
*r
= &testers
[i
];
650 qemu_vfree (r
->test_buf
);
657 printf ("Test process %d finished successfully\n", getpid ());
659 int fvd
= (strncmp (bs
->drv
->format_name
, "fvd", 3) == 0);
662 fvd_check_memory_usage ();
667 int main (int argc
, char **argv
)
670 const char *truth_file
= NULL
;
671 const char *test_file
= NULL
;
672 const char *format
= NULL
;
673 int compare_before
= FALSE
;
674 int compare_after
= TRUE
;
677 const struct option lopt
[] = {
680 {"truth", 1, 0, 'b'},
682 {"format", 1, 0, 'f'},
683 {"rand_time", 1, 0, 'n'},
684 {"fail_prob", 1, 0, 'u'},
685 {"cancel_prob", 1, 0, 'c'},
686 {"flush_prob", 1, 0, 'w'},
687 {"round", 1, 0, 'r'},
688 {"parallel", 1, 0, 'p'},
689 {"compare_before", 1, 0, 'm'},
690 {"verify_write", 1, 0, 'v'},
691 {"compare_after", 1, 0, 'a'},
692 {"max_iov", 1, 0, 'i'},
693 {"io_size", 1, 0, 's'},
694 {"instant_qemubh", 1, 0, 'q'},
698 progname
= basename (argv
[0]);
700 while ((c
= getopt_long (argc
, argv
, "hc:u:p:q:i:f:d:b:t:r:m:v:a:s:",
701 lopt
, NULL
)) != -1) {
708 instant_qemubh
= read_bool (optarg
);
712 flush_prob
= atof (optarg
);
716 cancel_prob
= atof (optarg
);
720 fail_prob
= atof (optarg
);
724 rand_time
= atoll (optarg
);
728 max_iov
= atoi (optarg
);
732 parallel
= atoi (optarg
);
736 verify_write
= read_bool (optarg
);
740 compare_before
= read_bool (optarg
);
744 compare_after
= read_bool (optarg
);
748 seed
= atoll (optarg
);
764 io_size
= atoll (optarg
);
768 round
= atoll (optarg
);
777 if (!truth_file
|| !test_file
) {
786 /* Convince FVD this is not in a qemu-tool. */
787 in_qemu_tool
= false;
788 enable_block_sim (FALSE
/*no print */ , rand_time
);
789 fvd_enable_host_crash_test ();
791 perform_test (truth_file
, test_file
, format
, compare_before
, compare_after
);