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-common.h"
21 #include "qemu/timer.h"
22 #include "block/block_int.h"
23 #include "block/fvd-ext.h"
24 #include "block/blksim.h"
26 #define die(format,...) \
28 fprintf (stderr, "%s:%d --- ", __FILE__, __LINE__); \
29 fprintf (stderr, format, ##__VA_ARGS__); \
33 typedef enum { OP_NULL
= 0, OP_READ
, OP_WRITE
, OP_FLUSH
} op_type_t
;
34 const char *op_type_str
[] = { "NULL ", "READ ", "WRITE", "FLUSH" };
36 typedef struct CompareFullCB
{
45 typedef struct RandomIO
{
55 BlockDriverAIOCB
*acb
;
58 static char *progname
;
59 static BlockDriverState
*bs
;
61 static int64_t total_sectors
;
62 static int64_t io_size
= 262144;
63 static int verify_write
= TRUE
;
64 static int parallel
= 1;
65 static int max_iov
= 10;
66 static int64_t round
= 10;
67 static int64_t finished_round
= 0;
68 static RandomIO
*testers
= NULL
;
69 static double fail_prob
= 0;
70 static double cancel_prob
= 0;
71 static double flush_prob
= 0;
72 static int64_t rand_time
= 1000;
73 static int64_t test_uuid
= 0;
74 static int instant_qemubh
= FALSE
;
76 static void rand_io_cb (void *opaque
, int ret
);
77 static void perform_next_io (RandomIO
* r
);
79 int64_t qemu_get_clock (QEMUClock
* clock
)
81 return sim_get_time ();
84 void timer_mod(QEMUTimer
*ts
, int64_t expire_time
)
86 sim_mod_timer (ts
, expire_time
);
89 QEMUTimer
*qemu_new_timer (QEMUClock
* clock
, QEMUTimerCB
* cb
, void *opaque
)
91 return sim_new_timer (cb
, opaque
);
94 void timer_free(QEMUTimer
*ts
)
99 void timer_del(QEMUTimer
*ts
)
104 QEMUBH
*qemu_bh_new (QEMUBHFunc
* cb
, void *opaque
)
106 return sim_new_timer (cb
, opaque
);
109 int qemu_bh_poll (void)
114 void qemu_bh_schedule (QEMUBH
* bh
)
116 if (instant_qemubh
) {
117 sim_mod_timer (bh
, -1); /* Run this bh next. */
119 sim_mod_timer (bh
, sim_get_time ());
123 void qemu_bh_cancel (QEMUBH
* bh
)
128 void qemu_bh_delete (QEMUBH
* bh
)
133 static void usage (void)
135 printf ("%s [--help]\n"
136 "\t--truth=<truth_img>\n"
137 "\t--test=<img_to_test>\n"
138 "\t[--format=<test_img_fmt>]\n"
140 "\t[--instant_qemubh=<true|false>]\n"
141 "\t[--fail_prob=<#f>]\n"
142 "\t[--cancel_prob=<#f>]\n"
143 "\t[--flush_prob=<#f>]\n"
144 "\t[--io_size=<#d>]\n"
145 "\t[--verify_write=[true|false]]\n"
146 "\t[--parallel=[#d]\n"
147 "\t[--max_iov=[#d]\n"
148 "\t[--compare_before=[true|false]]\n"
149 "\t[--compare_after=[true|false]]\n" "\n", progname
);
153 static int truth_io (void *buf
, int64_t sector_num
, int nb_sectors
, int do_read
)
155 off_t offset
= sector_num
* 512;
156 size_t size
= nb_sectors
* 512;
161 r
= pread (fd
, buf
, size
, offset
);
163 r
= pwrite (fd
, buf
, size
, offset
);
168 buf
= (void *) (((char *) buf
) + r
);
169 } else if (errno
!= EINTR
) {
171 die ("I/O error on the truth file.\n");
179 static int verify (uint8_t * truth_buf
, uint8_t * test_buf
,
180 int64_t sector_num
, int nb_sectors
)
183 for (i
= 0; i
< nb_sectors
; i
++) {
184 int64_t offset
= i
* 512;
185 if (memcmp (&truth_buf
[offset
], &test_buf
[offset
], 512) != 0) {
187 printf ("Sector %" PRId64
" differs\n", sector_num
+ i
);
188 QDEBUG ("Sector %" PRId64
" differs\n", sector_num
+ i
);
189 for (j
= 0; j
< 512; j
++) {
190 if (truth_buf
[offset
+ j
] == test_buf
[offset
+ j
]) {
191 QDEBUG ("%02d: %02X %02X\n", j
, truth_buf
[offset
+ j
],
192 test_buf
[offset
+ j
]);
194 QDEBUG ("%02d: %02X %02X ***\n", j
,
195 truth_buf
[offset
+ j
], test_buf
[offset
+ j
]);
199 fprintf (stderr
, "Pause process %d for debugging...\n", getpid ());
209 static void compare_full_images_cb (void *opaque
, int ret
)
211 CompareFullCB
*cf
= opaque
;
214 /* Failed. Retry the operation. */
215 bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
, cf
->nb_sectors
,
216 compare_full_images_cb
, cf
);
220 truth_io (cf
->truth_buf
, cf
->sector_num
, cf
->nb_sectors
, TRUE
);
221 verify (cf
->truth_buf
, cf
->iov
.iov_base
, cf
->sector_num
, cf
->nb_sectors
);
223 cf
->sector_num
+= cf
->nb_sectors
;
224 if (cf
->sector_num
>= total_sectors
) {
226 free (cf
->truth_buf
);
227 qemu_vfree (cf
->iov
.iov_base
);
232 /* Read more data to compare. */
233 if (cf
->sector_num
+ cf
->max_nb_sectors
> total_sectors
) {
234 cf
->nb_sectors
= total_sectors
- cf
->sector_num
;
236 cf
->nb_sectors
= cf
->max_nb_sectors
;
238 cf
->iov
.iov_len
= cf
->nb_sectors
* 512;
239 qemu_iovec_init_external (&cf
->qiov
, &cf
->iov
, 1);
240 if (!bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
,
241 cf
->nb_sectors
, compare_full_images_cb
, cf
)) {
242 die ("bdrv_aio_readv\n");
246 static int compare_full_images (void)
249 int old_copy_on_read
= FALSE
;
251 printf ("Performing a full comparison of the truth image and "
252 "the test image...\n");
254 if (!strncmp (bs
->drv
->format_name
, "fvd", 3)) {
255 /* Disable copy-on-read when scanning through the entire image. */
256 old_copy_on_read
= fvd_get_copy_on_read (bs
);
257 fvd_set_copy_on_read (bs
, FALSE
);
260 cf
= g_malloc(sizeof(CompareFullCB
));
261 cf
->max_nb_sectors
= 1048576L / 512;
262 cf
->nb_sectors
= MIN (cf
->max_nb_sectors
, total_sectors
);
263 if (posix_memalign ((void **) &cf
->truth_buf
, 512,
264 cf
->max_nb_sectors
* 512) != 0) {
265 die ("posix_memalign");
267 cf
->iov
.iov_base
= qemu_blockalign (bs
, cf
->max_nb_sectors
* 512);
268 cf
->iov
.iov_len
= cf
->nb_sectors
* 512;
270 qemu_iovec_init_external (&cf
->qiov
, &cf
->iov
, 1);
271 if (!bdrv_aio_readv (bs
, cf
->sector_num
, &cf
->qiov
,
272 cf
->nb_sectors
, compare_full_images_cb
, cf
)) {
273 die ("bdrv_aio_readv\n");
278 if (!strncmp (bs
->drv
->format_name
, "fvd", 3)) {
279 fvd_set_copy_on_read (bs
, old_copy_on_read
);
285 static inline int64_t rand64 (void)
287 int64_t f1
= random ();
288 int64_t f2
= random ();
289 int64_t f3
= (f1
<< 32) | f2
;
290 return f3
>= 0 ? f3
: -f3
;
293 static int check_conflict (RandomIO
* r
)
297 for (i
= 0; i
< parallel
; i
++) {
298 RandomIO
*s
= &testers
[i
];
299 if (s
== r
|| s
->type
== OP_FLUSH
||
300 (r
->type
== OP_READ
&& s
->type
== OP_READ
)) {
304 if ((r
->sector_num
<= s
->sector_num
&&
305 s
->sector_num
< r
->sector_num
+ r
->nb_sectors
) ||
306 (s
->sector_num
<= r
->sector_num
&&
307 r
->sector_num
< s
->sector_num
+ s
->nb_sectors
)) {
308 return 1; /* Conflict. */
312 return 0; /* No confict. */
315 /* Return FALSE if the submitted request is cancelled. */
316 static int submit_rand_io (RandomIO
* r
)
318 BlockDriverAIOCB
*acb
= NULL
;
320 QDEBUG ("TESTER %03d: %s test%" PRIX64
" sector_num=%" PRId64
321 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
322 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
323 printf ("TESTER %03d: %s sector_num=%" PRId64
" nb_sectors=%d niov=%d\n",
324 r
->tester
, op_type_str
[r
->type
], r
->sector_num
, r
->nb_sectors
,
328 if (fail_prob
<= 0) {
330 } else if (random () / (double) RAND_MAX
<= fail_prob
) {
336 /* This affects whether this request will fail or not. */
337 sim_set_disk_io_return_code (ret
);
341 if (!(acb
= bdrv_aio_readv (bs
, r
->sector_num
, &r
->qiov
, r
->nb_sectors
,
343 die ("bdrv_aio_readv\n");
347 if (!(acb
= bdrv_aio_writev (bs
, r
->sector_num
, &r
->qiov
, r
->nb_sectors
,
349 die ("bdrv_aio_writev\n");
353 if (!(acb
= bdrv_aio_flush (bs
, rand_io_cb
, r
))) {
354 die ("bdrv_aio_flush\n");
362 sim_set_disk_io_return_code (0); /* Reset to no failure state. */
364 if (r
->allow_cancel
&& cancel_prob
> 0 &&
365 random () / (double) RAND_MAX
<= cancel_prob
) {
366 QDEBUG ("TESTER %03d: cancel %s test%" PRIX64
" sector_num=%" PRId64
367 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
368 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
369 printf ("TESTER %03d: cancel %s sector_num=%" PRId64
370 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
371 r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
372 bdrv_aio_cancel (acb
);
379 static void prepare_read_write (RandomIO
* r
)
381 /* Do a READ or WRITE? */
388 /* Find the next region to perform io. */
390 if (parallel
<= 1 || (random () % 2 == 0)) {
391 /* Perform a random I/O. */
392 r
->sector_num
= rand64 () % total_sectors
;
394 /* Perform an I/O next to a currently ongoing I/O. */
397 id
= random () % parallel
;
398 } while (id
== r
->tester
);
400 RandomIO
*p
= &testers
[id
];
402 p
->sector_num
+ 2 * io_size
- rand64 () % (4 * io_size
);
403 if (r
->sector_num
< 0) {
405 } else if (r
->sector_num
>= total_sectors
) {
406 r
->sector_num
= total_sectors
- 1;
410 r
->nb_sectors
= 1 + rand64 () % io_size
;
411 if (r
->sector_num
+ r
->nb_sectors
> total_sectors
) {
412 r
->nb_sectors
= total_sectors
- r
->sector_num
;
414 } while (check_conflict (r
));
416 if (r
->type
== OP_WRITE
) {
417 /* Fill test_buf with random data. */
419 for (i
= 0; i
< r
->nb_sectors
; i
++) {
420 const uint64_t TEST_MAGIC
= 0x0123456789ABCDEFULL
;
421 /* This first 8 bytes of the sector stores the current testing
422 * round. The next 8 bytes store a magic number. This info helps
424 uint64_t *p
= (uint64_t *) & r
->test_buf
[i
* 512];
431 /* The rest of the sector are filled with random data. */
432 uint32_t *q
= (uint32_t *) (p
+ 1);
433 int n
= (512 - 2 * sizeof (uint64_t)) / sizeof (uint32_t);
434 for (j
= 0; j
< n
; j
++) {
440 /* Determine the number of iov. */
442 uint8_t *p
= r
->test_buf
;
443 int left
= r
->nb_sectors
;
445 if (niov
== max_iov
- 1) {
446 r
->qiov
.iov
[niov
].iov_len
= left
* 512;
447 r
->qiov
.iov
[niov
].iov_base
= p
;
452 int nb
= 1 + random () % left
;
453 r
->qiov
.iov
[niov
].iov_len
= nb
* 512;
454 r
->qiov
.iov
[niov
].iov_base
= p
;
455 p
+= r
->qiov
.iov
[niov
].iov_len
;
460 qemu_iovec_init_external (&r
->qiov
, r
->qiov
.iov
, niov
);
463 static void perform_next_io (RandomIO
* r
)
465 if (finished_round
>= round
) {
470 r
->allow_cancel
= TRUE
;
473 r
->uuid
= test_uuid
++;
475 if (flush_prob
> 0 && random () / (double) RAND_MAX
< flush_prob
) {
478 prepare_read_write (r
);
480 } while (!submit_rand_io (r
));
483 static void rand_io_cb (void *opaque
, int ret
)
485 RandomIO
*r
= opaque
;
488 if (fail_prob
<= 0) {
489 fprintf (stderr
, "Request %s sector_num=%" PRId64
490 " nb_sectors=%d failed while fail_prob=0. "
491 "Pause for debugging...\n",
492 op_type_str
[r
->type
], r
->sector_num
, r
->nb_sectors
);
495 /* Failed. Retry the operation. */
496 QDEBUG ("TESTER %03d: retry %s test%" PRIX64
" sector_num=%"
497 PRId64
" nb_sectors=%d niov=%d\n",
498 r
->tester
, op_type_str
[r
->type
], r
->uuid
,
499 r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
500 if (!submit_rand_io (r
)) {
506 QDEBUG ("TESTER %03d: finished %s test%" PRIX64
" sector_num=%"PRId64
507 " nb_sectors=%d niov=%d\n", r
->tester
, op_type_str
[r
->type
],
508 r
->uuid
, r
->sector_num
, r
->nb_sectors
, r
->qiov
.niov
);
517 truth_io (r
->truth_buf
, r
->sector_num
, r
->nb_sectors
, TRUE
);
518 verify (r
->truth_buf
, r
->test_buf
, r
->sector_num
, r
->nb_sectors
);
523 truth_io (r
->test_buf
, r
->sector_num
, r
->nb_sectors
, FALSE
);
525 /* Perform a read for the same data. */
528 /* To verify the write, this read cannot be cancelled. */
529 r
->allow_cancel
= FALSE
;
531 r
->qiov
.iov
[0].iov_len
= r
->qiov
.size
;
532 memset (r
->test_buf
, 0xA5, r
->qiov
.size
); /* Fill in garbage. */
545 static int read_bool (const char *arg
)
548 if (strcmp (optarg
, "true") == 0) {
550 } else if (strcmp (optarg
, "false") == 0) {
553 printf ("%s is neither 'true' nor 'false'\n", arg
);
561 static void perform_test(const char *truth_file
, const char *test_file
,
562 const char *format
, int compare_before
,
567 bs
= bdrv_new ("hda");
569 die ("bdrv_new failed\n");
572 BlockDriver
*drv
= NULL
;
574 drv
= bdrv_find_format (format
);
576 die ("Found no driver for format '%s'.\n", format
);
580 flags
= BDRV_O_RDWR
| BDRV_O_CACHE_WB
;
582 if (bdrv_open (bs
, test_file
, flags
, drv
) < 0) {
583 die ("Failed to open '%s'\n", test_file
);
586 fd
= open (truth_file
, O_RDWR
| O_LARGEFILE
, 0);
589 die ("Failed to open '%s'\n", truth_file
);
592 int64_t l0
= lseek (fd
, 0, SEEK_END
);
593 int64_t l1
= bdrv_getlength (bs
);
594 if (l0
< 0 || l1
< 0 || l0
< l1
) {
595 die ("Mismatch: truth image %s length %" PRId64
", test image %s "
596 "length %" PRId64
"\n", truth_file
, l0
, test_file
, l1
);
599 total_sectors
= l1
/ 512;
600 if (total_sectors
<= 1) {
601 die ("Total sectors: %" PRId64
"\n", total_sectors
);
607 } else if (io_size
> total_sectors
/ 2) {
608 io_size
= total_sectors
/ 2;
611 if (compare_before
) {
612 if (compare_full_images ()) {
613 die ("The original two files do not match.\n");
618 /* Create testers. */
619 testers
= g_malloc(sizeof(RandomIO
) * parallel
);
620 for (i
= 0; i
< parallel
; i
++) {
621 RandomIO
*r
= &testers
[i
];
622 r
->test_buf
= qemu_blockalign (bs
, io_size
* 512);
623 if (posix_memalign ((void **) &r
->truth_buf
, 512, io_size
* 512)) {
624 die ("posix_memalign");
626 r
->qiov
.iov
= g_malloc(sizeof(struct iovec
) * max_iov
);
632 for (i
= 0; i
< parallel
; i
++) {
633 perform_next_io (&testers
[i
]);
637 sim_all_tasks (); /* Run tests. */
640 /* Create testers. */
642 if (compare_full_images ()) {
643 die ("The two files do not match after I/O operations.\n");
647 for (i
= 0; i
< parallel
; i
++) {
648 RandomIO
*r
= &testers
[i
];
649 qemu_vfree (r
->test_buf
);
656 printf ("Test process %d finished successfully\n", getpid ());
658 int fvd
= (strncmp (bs
->drv
->format_name
, "fvd", 3) == 0);
661 fvd_check_memory_usage ();
666 int main (int argc
, char **argv
)
669 const char *truth_file
= NULL
;
670 const char *test_file
= NULL
;
671 const char *format
= NULL
;
672 int compare_before
= FALSE
;
673 int compare_after
= TRUE
;
676 const struct option lopt
[] = {
679 {"truth", 1, 0, 'b'},
681 {"format", 1, 0, 'f'},
682 {"rand_time", 1, 0, 'n'},
683 {"fail_prob", 1, 0, 'u'},
684 {"cancel_prob", 1, 0, 'c'},
685 {"flush_prob", 1, 0, 'w'},
686 {"round", 1, 0, 'r'},
687 {"parallel", 1, 0, 'p'},
688 {"compare_before", 1, 0, 'm'},
689 {"verify_write", 1, 0, 'v'},
690 {"compare_after", 1, 0, 'a'},
691 {"max_iov", 1, 0, 'i'},
692 {"io_size", 1, 0, 's'},
693 {"instant_qemubh", 1, 0, 'q'},
697 progname
= basename (argv
[0]);
699 while ((c
= getopt_long (argc
, argv
, "hc:u:p:q:i:f:d:b:t:r:m:v:a:s:",
700 lopt
, NULL
)) != -1) {
707 instant_qemubh
= read_bool (optarg
);
711 flush_prob
= atof (optarg
);
715 cancel_prob
= atof (optarg
);
719 fail_prob
= atof (optarg
);
723 rand_time
= atoll (optarg
);
727 max_iov
= atoi (optarg
);
731 parallel
= atoi (optarg
);
735 verify_write
= read_bool (optarg
);
739 compare_before
= read_bool (optarg
);
743 compare_after
= read_bool (optarg
);
747 seed
= atoll (optarg
);
763 io_size
= atoll (optarg
);
767 round
= atoll (optarg
);
776 if (!truth_file
|| !test_file
) {
785 /* Convince FVD this is not in a qemu-tool. */
786 in_qemu_tool
= false;
787 enable_block_sim (FALSE
/*no print */ , rand_time
);
788 fvd_enable_host_crash_test ();
790 perform_test (truth_file
, test_file
, format
, compare_before
, compare_after
);