Add missing G_GNUC_PRINTF to function qemu_set_info_str
[qemu/ar7.git] / qemu-test.c
blob742911ce3cd3234b3548eeee6bcbed2a81b5bd14
1 /*
2 * Copyright (c) 2010-2011 IBM
4 * Authors:
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.
9 */
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"
18 #include <getopt.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,...) \
26 do { \
27 fprintf (stderr, "%s:%d --- ", __FILE__, __LINE__); \
28 fprintf (stderr, format, ##__VA_ARGS__); \
29 exit (-1);\
30 } while(0)
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 {
36 QEMUIOVector qiov;
37 struct iovec iov;
38 int64_t sector_num;
39 int nb_sectors;
40 int max_nb_sectors;
41 uint8_t *truth_buf;
42 } CompareFullCB;
44 typedef struct RandomIO {
45 QEMUIOVector qiov;
46 int64_t sector_num;
47 int nb_sectors;
48 uint8_t *truth_buf;
49 uint8_t *test_buf;
50 op_type_t type;
51 int tester;
52 int64_t uuid;
53 int allow_cancel;
54 BlockDriverAIOCB *acb;
55 } RandomIO;
57 static char *progname;
58 static BlockDriverState *bs;
59 static int fd;
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)
95 sim_free_timer (ts);
98 void timer_del(QEMUTimer *ts)
100 sim_del_timer (ts);
103 QEMUBH *qemu_bh_new (QEMUBHFunc * cb, void *opaque)
105 return sim_new_timer (cb, opaque);
108 int qemu_bh_poll (void)
110 return 0;
113 void qemu_bh_schedule (QEMUBH * bh)
115 if (instant_qemubh) {
116 sim_mod_timer (bh, -1); /* Run this bh next. */
117 } else {
118 sim_mod_timer (bh, sim_get_time ());
122 void qemu_bh_cancel (QEMUBH * bh)
124 sim_del_timer (bh);
127 void qemu_bh_delete (QEMUBH * bh)
129 sim_free_timer (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"
138 "\t[--round=<#d>]\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);
149 exit (1);
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;
157 while (size > 0) {
158 int r;
159 if (do_read) {
160 r = pread (fd, buf, size, offset);
161 } else {
162 r = pwrite (fd, buf, size, offset);
164 if (r >= 0) {
165 size -= r;
166 offset += r;
167 buf = (void *) (((char *) buf) + r);
168 } else if (errno != EINTR) {
169 perror ("io");
170 die ("I/O error on the truth file.\n");
171 return -1;
175 return 0;
178 static int verify (uint8_t * truth_buf, uint8_t * test_buf,
179 int64_t sector_num, int nb_sectors)
181 int i;
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) {
185 int j;
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]);
192 } else {
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 ());
199 fgetc (stdin);
201 return -1;
205 return 0;
208 static void compare_full_images_cb (void *opaque, int ret)
210 CompareFullCB *cf = opaque;
212 if (ret) {
213 /* Failed. Retry the operation. */
214 bdrv_aio_readv (bs, cf->sector_num, &cf->qiov, cf->nb_sectors,
215 compare_full_images_cb, cf);
216 return;
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) {
224 /* Finished. */
225 free (cf->truth_buf);
226 qemu_vfree (cf->iov.iov_base);
227 g_free(cf);
228 return;
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;
234 } else {
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)
247 CompareFullCB *cf;
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;
268 cf->sector_num = 0;
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");
275 sim_all_tasks ();
277 if (!strncmp (bs->drv->format_name, "fvd", 3)) {
278 fvd_set_copy_on_read (bs, old_copy_on_read);
281 return 0;
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)
294 int i;
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)) {
300 continue;
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,
324 r->qiov.niov);
326 int ret;
327 if (fail_prob <= 0) {
328 ret = 0;
329 } else if (random () / (double) RAND_MAX <= fail_prob) {
330 ret = -EIO;
331 } else {
332 ret = 0;
335 /* This affects whether this request will fail or not. */
336 sim_set_disk_io_return_code (ret);
338 switch (r->type) {
339 case OP_READ:
340 if (!(acb = bdrv_aio_readv (bs, r->sector_num, &r->qiov, r->nb_sectors,
341 rand_io_cb, r))) {
342 die ("bdrv_aio_readv\n");
344 break;
345 case OP_WRITE:
346 if (!(acb = bdrv_aio_writev (bs, r->sector_num, &r->qiov, r->nb_sectors,
347 rand_io_cb, r))) {
348 die ("bdrv_aio_writev\n");
350 break;
351 case OP_FLUSH:
352 if (!(acb = bdrv_aio_flush (bs, rand_io_cb, r))) {
353 die ("bdrv_aio_flush\n");
355 break;
356 case OP_NULL:
357 die ("OP_NULL");
358 break;
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);
372 return FALSE;
373 } else {
374 return TRUE;
378 static void prepare_read_write (RandomIO * r)
380 /* Do a READ or WRITE? */
381 if (random () % 2) {
382 r->type = OP_READ;
383 } else {
384 r->type = OP_WRITE;
387 /* Find the next region to perform io. */
388 do {
389 if (parallel <= 1 || (random () % 2 == 0)) {
390 /* Perform a random I/O. */
391 r->sector_num = rand64 () % total_sectors;
392 } else {
393 /* Perform an I/O next to a currently ongoing I/O. */
394 int id;
395 do {
396 id = random () % parallel;
397 } while (id == r->tester);
399 RandomIO *p = &testers[id];
400 r->sector_num =
401 p->sector_num + 2 * io_size - rand64 () % (4 * io_size);
402 if (r->sector_num < 0) {
403 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. */
417 int i, j;
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
422 * debugging. */
423 uint64_t *p = (uint64_t *) & r->test_buf[i * 512];
424 *p = r->uuid;
425 cpu_to_be64s (p);
426 p++;
427 *p = TEST_MAGIC;
428 cpu_to_be64s (p);
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++) {
434 *q++ = random ();
439 /* Determine the number of iov. */
440 int niov = 0;
441 uint8_t *p = r->test_buf;
442 int left = r->nb_sectors;
443 do {
444 if (niov == max_iov - 1) {
445 r->qiov.iov[niov].iov_len = left * 512;
446 r->qiov.iov[niov].iov_base = p;
447 niov++;
448 break;
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;
455 left -= nb;
456 niov++;
457 } while (left > 0);
459 qemu_iovec_init_external (&r->qiov, r->qiov.iov, niov);
462 static void perform_next_io (RandomIO * r)
464 if (finished_round >= round) {
465 return;
468 finished_round++;
469 r->allow_cancel = TRUE;
471 do {
472 r->uuid = test_uuid++;
474 if (flush_prob > 0 && random () / (double) RAND_MAX < flush_prob) {
475 r->type = OP_FLUSH;
476 } else {
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;
486 if (ret) {
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);
492 fgetc (stdin);
493 } else {
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)) {
500 perform_next_io (r);
502 return;
504 } else {
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);
510 switch (r->type) {
511 case OP_FLUSH:
512 perform_next_io (r);
513 return;
515 case OP_READ:
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);
518 perform_next_io (r);
519 return;
521 case OP_WRITE:
522 truth_io (r->test_buf, r->sector_num, r->nb_sectors, FALSE);
523 if (verify_write) {
524 /* Perform a read for the same data. */
525 r->type = OP_READ;
527 /* To verify the write, this read cannot be cancelled. */
528 r->allow_cancel = FALSE;
529 r->qiov.niov = 1;
530 r->qiov.iov[0].iov_len = r->qiov.size;
531 memset (r->test_buf, 0xA5, r->qiov.size); /* Fill in garbage. */
532 submit_rand_io (r);
533 } else {
534 perform_next_io (r);
536 return;
538 case OP_NULL:
539 die ("OP_NULL");
540 return;
544 static int read_bool (const char *arg)
546 int val = TRUE;
547 if (strcmp (optarg, "true") == 0) {
548 val = TRUE;
549 } else if (strcmp (optarg, "false") == 0) {
550 val = FALSE;
551 } else {
552 printf ("%s is neither 'true' nor 'false'\n", arg);
553 usage ();
556 return val;
560 static void perform_test(const char *truth_file, const char *test_file,
561 const char *format, int compare_before,
562 int compare_after)
564 int flags, i;
566 bs = bdrv_new ("hda");
567 if (!bs) {
568 die ("bdrv_new failed\n");
571 BlockDriver *drv = NULL;
572 if (format) {
573 drv = bdrv_find_format (format);
574 if (!drv) {
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);
586 if (fd < 0) {
587 perror ("open");
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);
603 io_size /= 512;
604 if (io_size <= 0) {
605 io_size = 1;
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");
616 if (round > 0) {
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);
626 r->sector_num = 0;
627 r->nb_sectors = 0;
628 r->type = OP_READ;
629 r->tester = i;
631 for (i = 0; i < parallel; i++) {
632 perform_next_io (&testers[i]);
636 sim_all_tasks (); /* Run tests. */
638 if (round > 0) {
639 /* Create testers. */
640 if (compare_after) {
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);
649 free (r->truth_buf);
650 g_free(r->qiov.iov);
652 g_free(testers);
655 printf ("Test process %d finished successfully\n", getpid ());
657 int fvd = (strncmp (bs->drv->format_name, "fvd", 3) == 0);
658 bdrv_delete (bs);
659 if (fvd) {
660 fvd_check_memory_usage ();
662 close (fd);
665 int main (int argc, char **argv)
667 int c;
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;
673 int seed = 0;
675 const struct option lopt[] = {
676 {"help", 0, 0, 'h'},
677 {"seed", 1, 0, 'd'},
678 {"truth", 1, 0, 'b'},
679 {"test", 1, 0, 't'},
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'},
693 {NULL, 0, NULL, 0}
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) {
700 switch (c) {
701 case 'h':
702 usage ();
703 return 0;
705 case 'q':
706 instant_qemubh = read_bool (optarg);
707 break;
709 case 'w':
710 flush_prob = atof (optarg);
711 break;
713 case 'c':
714 cancel_prob = atof (optarg);
715 break;
717 case 'u':
718 fail_prob = atof (optarg);
719 break;
721 case 'n':
722 rand_time = atoll (optarg);
723 break;
725 case 'i':
726 max_iov = atoi (optarg);
727 break;
729 case 'p':
730 parallel = atoi (optarg);
731 break;
733 case 'v':
734 verify_write = read_bool (optarg);
735 break;
737 case 'm':
738 compare_before = read_bool (optarg);
739 break;
741 case 'a':
742 compare_after = read_bool (optarg);
743 break;
745 case 'd':
746 seed = atoll (optarg);
747 break;
749 case 'f':
750 format = optarg;
751 break;
753 case 'b':
754 truth_file = optarg;
755 break;
757 case 't':
758 test_file = optarg;
759 break;
761 case 's':
762 io_size = atoll (optarg);
763 break;
765 case 'r':
766 round = atoll (optarg);
767 break;
769 default:
770 usage ();
771 return 1;
775 if (!truth_file || !test_file) {
776 usage ();
777 return 1;
780 if (parallel <= 0) {
781 parallel = 1;
783 srandom (seed);
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 ();
788 bdrv_init ();
789 perform_test (truth_file, test_file, format, compare_before, compare_after);
790 return 0;