Patchwork [3/3] FVD: Made qemu-io working with simulation (blksim)

login
register
mail settings
Submitter Chunqiang Tang
Date Jan. 21, 2011, 10:19 p.m.
Message ID <1295648355-17359-3-git-send-email-ctang@us.ibm.com>
Download mbox | patch
Permalink /patch/79952/
State New
Headers show

Comments

Chunqiang Tang - Jan. 21, 2011, 10:19 p.m.
This patch is part of the Fast Virtual Disk (FVD) proposal. See the related
discussions at
http://lists.gnu.org/archive/html/qemu-devel/2011-01/msg00426.html.

This patch adds the 'sim' command to qemu-io, which works  with the blksim
driver. With this extension, now a developer can use qemu-io to precisely
control the order of disk I/Os, the order of callbacks, and the return code of
every I/O operation. The purpose is to comprehensively test a block device
driver under failures and race conditions. Bugs found by blksim under rare
race conditions are guaranteed to be precisely reproducible, with no
dependency on thread timing etc., which makes debugging much easier.

Signed-off-by: Chunqiang Tang <ctang@us.ibm.com>
---
 qemu-io-sim.c |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-io.c     |   38 +++++++++++++++-----
 2 files changed, 138 insertions(+), 9 deletions(-)
 create mode 100644 qemu-io-sim.c

Patch

diff --git a/qemu-io-sim.c b/qemu-io-sim.c
new file mode 100644
index 0000000..816f8ae
--- /dev/null
+++ b/qemu-io-sim.c
@@ -0,0 +1,109 @@ 
+/*
+ * Copyright (c) 2010-2011 IBM
+ *
+ * Authors:
+ *         Chunqiang Tang <ctang@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*=============================================================================
+ * qemu-io-sim works with qemu-io to perform simulated testing. The 'sim'
+ * command allows the user to control the order of disk I/O and callback
+ * activities in order to test rare race conditions. See block/blksim.c
+ * Note that in the manual mode, qemu-io's 'sim' command can only work with
+ * qemu-io's 'aio_read' and 'aio_write' commands. The automated testing mode,
+ * 'qemu-io --auto', performs a much more comprehensive fully automated test
+ * (see qemu-io-auto.c). Below is one example of using qemu-io to perform
+ * manual testing in the simulation mode.
+ 
+$ qemu-img create -f qcow2 -obacking_fmt=blksim -b base.raw test.qcow2
+$ qemu-io -f qcow2 blksim:test.qcow2
+qemu-io> aio_read 0 512
+Added READ uuid=0  filename=base.raw  sector_num=0  nb_sectors=1
+qemu-io> aio_read 0 1024
+Added READ uuid=1  filename=base.raw  sector_num=0  nb_sectors=2
+qemu-io> sim list
+uuid=0  READ           file=base.raw  sector_num=0  nb_sectors=1
+uuid=1  READ           file=base.raw  sector_num=0  nb_sectors=2
+qemu-io> aio_write 512 1024
+Added WRITE uuid=2  filename=test.qcow2  sector_num=33297  nb_sectors=2
+qemu-io> sim list
+uuid=0  READ           file=base.raw  sector_num=0  nb_sectors=1
+uuid=1  READ           file=base.raw  sector_num=0  nb_sectors=2
+uuid=2  WRITE          file=test.qcow2  sector_num=33297  nb_sectors=2
+qemu-io> sim 2
+Added WRITE_CALLBACK uuid=3  filename=test.qcow2  sector_num=33297  nb_sectors=2
+qemu-io> sim list
+uuid=0  READ           file=base.raw  sector_num=0  nb_sectors=1
+uuid=1  READ           file=base.raw  sector_num=0  nb_sectors=2
+uuid=3  CALLBACK WRITE file=test.qcow2  sector_num=33297  nb_sectors=2
+qemu-io> sim 1
+Added READ_CALLBACK uuid=4  filename=base.raw  sector_num=0  nb_sectors=2
+qemu-io> sim list
+uuid=0  READ           file=base.raw  sector_num=0  nb_sectors=1
+uuid=3  CALLBACK WRITE file=test.qcow2  sector_num=33297  nb_sectors=2
+uuid=4  CALLBACK READ  file=base.raw  sector_num=0  nb_sectors=2
+qemu-io> sim 3
+Added WRITE uuid=5  filename=test.qcow2  sector_num=528  nb_sectors=1
+qemu-io> sim list
+uuid=0  READ           file=base.raw  sector_num=0  nb_sectors=1
+uuid=4  CALLBACK READ  file=base.raw  sector_num=0  nb_sectors=2
+uuid=5  WRITE          file=test.qcow2  sector_num=528  nb_sectors=1
+
+*=============================================================================*/
+
+#include "block/blksim.h"
+
+static void sim_help (void)
+{
+    printf ("\n"
+            " sim list\t\tlist all simulation tasks\n"
+            " sim <#task> [#ret]\trun a simulation task, optionally "
+                    "using #ret as the return value of a read/write operation\n"
+            " sim all [#ret]\t\trun all tasks, optionally using #ret as "
+                    "the return value of read/write tasks\n"
+            " sim prefetch\t\tstart prefetching\n");
+}
+
+static int sim_f (int argc, char **argv)
+{
+    int ret = 0;
+
+    if (argc == 3) {
+        ret = atoi (argv[2]);
+    }
+    else if (argc != 2) {
+        sim_help ();
+        return 0;
+    }
+
+    if (strcmp (argv[1], "list") == 0) {
+        blksim_list_tasks ();
+    }
+    else if (strcmp (argv[1], "all") == 0) {
+        blksim_set_disk_io_return_code (ret);
+        int n = blksim_run_all_tasks ();
+        blksim_set_disk_io_return_code (0);
+        printf ("Executed %d tasks.\n", n);
+    }
+    else {
+        blksim_set_disk_io_return_code (ret);
+        blksim_run_task_by_uuid (atoll (argv[1]));
+        blksim_set_disk_io_return_code (0);
+    }
+
+    return 0;
+}
+
+static const cmdinfo_t sim_cmd = {
+    .name = "sim",
+    .altname = "s",
+    .cfunc = sim_f,
+    .argmin = 1,
+    .argmax = 2,
+    .args = "",
+    .oneline = "use simulation to control the order of disk I/Os and callbacks",
+    .help = sim_help,
+};
diff --git a/qemu-io.c b/qemu-io.c
index 5b24c5e..9144a6a 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1584,7 +1584,7 @@  static const cmdinfo_t close_cmd = {
 	.oneline	= "close the current open file",
 };
 
-static int openfile(char *name, int flags, int growable)
+static int openfile(char *name, const char *fmt, int flags, int growable)
 {
 	if (bs) {
 		fprintf(stderr, "file open already, try 'help close'\n");
@@ -1597,9 +1597,17 @@  static int openfile(char *name, int flags, int growable)
 			return 1;
 		}
 	} else {
+                BlockDriver *drv = NULL;
+                if (fmt && !(drv = bdrv_find_format (fmt))) {
+                        fprintf(stderr, "%s: can't find driver for format "
+                                "%s \n", progname, fmt);
+                        bs = NULL;
+                        return 1;
+                }
+
 		bs = bdrv_new("hda");
 
-		if (bdrv_open(bs, name, flags, NULL) < 0) {
+		if (bdrv_open(bs, name, flags, drv) < 0) {
 			fprintf(stderr, "%s: can't open device %s\n", progname, name);
 			bs = NULL;
 			return 1;
@@ -1636,7 +1644,7 @@  static const cmdinfo_t open_cmd = {
 	.argmin		= 1,
 	.argmax		= -1,
 	.flags		= CMD_NOFILE_OK,
-	.args		= "[-Crsn] [path]",
+	.args		= "[-Crsn] [-f <format>] [path]",
 	.oneline	= "open the file specified by path",
 	.help		= open_help,
 };
@@ -1648,8 +1656,9 @@  open_f(int argc, char **argv)
 	int readonly = 0;
 	int growable = 0;
 	int c;
+        const char *fmt = NULL;
 
-	while ((c = getopt(argc, argv, "snrg")) != EOF) {
+	while ((c = getopt(argc, argv, "snrgf:")) != EOF) {
 		switch (c) {
 		case 's':
 			flags |= BDRV_O_SNAPSHOT;
@@ -1663,6 +1672,9 @@  open_f(int argc, char **argv)
 		case 'g':
 			growable = 1;
 			break;
+		case 'f':
+                        fmt = optarg;
+			break;
 		default:
 			return command_usage(&open_cmd);
 		}
@@ -1675,7 +1687,7 @@  open_f(int argc, char **argv)
 	if (optind != argc - 1)
 		return command_usage(&open_cmd);
 
-	return openfile(argv[optind], flags, growable);
+	return openfile(argv[optind], fmt, flags, growable);
 }
 
 static int
@@ -1701,10 +1713,12 @@  init_check_command(
 	return 1;
 }
 
+#include "qemu-io-sim.c"
+
 static void usage(const char *name)
 {
 	printf(
-"Usage: %s [-h] [-V] [-rsnm] [-c cmd] ... [file]\n"
+"Usage: %s [-h] [-a] [-V] [-rsnm] [-c cmd] ... [file]\n"
 "QEMU Disk exerciser\n"
 "\n"
 "  -c, --cmd            command to execute\n"
@@ -1714,18 +1728,18 @@  static void usage(const char *name)
 "  -g, --growable       allow file to grow (only applies to protocols)\n"
 "  -m, --misalign       misalign allocations for O_DIRECT\n"
 "  -k, --native-aio     use kernel AIO implementation (on Linux only)\n"
+"  -f, --format         image format of the file\n"
 "  -h, --help           display this help and exit\n"
 "  -V, --version        output version information and exit\n"
 "\n",
 	name);
 }
 
-
 int main(int argc, char **argv)
 {
 	int readonly = 0;
 	int growable = 0;
-	const char *sopt = "hVc:rsnmgk";
+	const char *sopt = "hVc:rsnmgkaf:";
         const struct option lopt[] = {
 		{ "help", 0, NULL, 'h' },
 		{ "version", 0, NULL, 'V' },
@@ -1737,11 +1751,13 @@  int main(int argc, char **argv)
 		{ "misalign", 0, NULL, 'm' },
 		{ "growable", 0, NULL, 'g' },
 		{ "native-aio", 0, NULL, 'k' },
+		{ "format", 1, NULL, 'f' },
 		{ NULL, 0, NULL, 0 }
 	};
 	int c;
 	int opt_index = 0;
 	int flags = 0;
+        const char *fmt = NULL;
 
 	progname = basename(argv[0]);
 
@@ -1768,6 +1784,9 @@  int main(int argc, char **argv)
 		case 'k':
 			flags |= BDRV_O_NATIVE_AIO;
 			break;
+		case 'f':
+                        fmt = optarg;
+                        break;
 		case 'V':
 			printf("%s version %s\n", progname, VERSION);
 			exit(0);
@@ -1807,6 +1826,7 @@  int main(int argc, char **argv)
 	add_command(&discard_cmd);
 	add_command(&alloc_cmd);
 	add_command(&map_cmd);
+        add_command(&sim_cmd);
 
 	add_args_command(init_args_command);
 	add_check_command(init_check_command);
@@ -1817,7 +1837,7 @@  int main(int argc, char **argv)
         }
 
 	if ((argc - optind) == 1)
-		openfile(argv[optind], flags, growable);
+		openfile(argv[optind], fmt, flags, growable);
 	command_loop();
 
 	/*