* [Qemu-devel] [PULL 00/26] Block patches
@ 2013-06-07 11:58 Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 01/26] blockdev: reset werror/rerror on drive_del Stefan Hajnoczi
` (26 more replies)
0 siblings, 27 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori, Stefan Hajnoczi
The following changes since commit 8819c10b5d55d537d59a0ffd5d623f348fc36c47:
Merge remote-tracking branch 'sstabellini/xen_fixes_20130603' into staging (2013-06-04 14:58:58 -0500)
are available in the git repository at:
git://github.com/stefanha/qemu.git block
for you to fetch changes up to e73fe2b46c38776288415ce7bc8ba3fcd23721c4:
hmp: add parameters device and -v for info block (2013-06-07 13:45:01 +0200)
----------------------------------------------------------------
Andreas Färber (1):
ide: Set BSY bit during FLUSH
Kevin Wolf (19):
qemu-io: Remove unused args_command
cutils: Support 'P' and 'E' suffixes in strtosz()
qemu-io: Make cvtnum() a wrapper around strtosz_suffix()
qemu-io: Handle cvtnum() errors in 'alloc'
qemu-io: Don't use global bs in command implementations
qemu-io: Split off commands to qemu-io-cmds.c
qemu-io: Factor out qemuio_command
qemu-io: Move 'help' function
qemu-io: Move 'quit' function
qemu-io: Move qemu_strsep() to cutils.c
qemu-io: Move functions for registering and running commands
qemu-io: Move command_loop() and friends
qemu-io: Move remaining helpers from cmd.c
qemu-io: Interface cleanup
qemu-io: Use the qemu version for -V
Make qemu-io commands available in HMP
blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events
ide-test: Add enum value for DEV
ide-test: Add FLUSH CACHE test case
Stefan Hajnoczi (1):
blockdev: reset werror/rerror on drive_del
Wenchao Xia (5):
block: add snapshot info query function bdrv_query_snapshot_info_list()
block: add image info query function bdrv_query_image_info()
qmp: add ImageInfo in BlockDeviceInfo used by query-block
hmp: show ImageInfo in 'info block'
hmp: add parameters device and -v for info block
Makefile | 2 +-
Makefile.objs | 1 +
block.c | 8 +-
block/blkdebug.c | 3 +
block/qapi.c | 148 +++-
blockdev.c | 4 +
cmd.c | 612 -------------
cmd.h | 79 --
hmp-commands.hx | 18 +
hmp.c | 39 +
hmp.h | 1 +
hw/ide/core.c | 1 +
include/block/block.h | 3 +
include/block/qapi.h | 14 +-
include/qemu-common.h | 3 +
include/qemu-io.h | 46 +
monitor.c | 15 +-
qapi-schema.json | 10 +-
qemu-img.c | 20 +-
qemu-io-cmds.c | 2118 ++++++++++++++++++++++++++++++++++++++++++++
qemu-io.c | 1990 ++++-------------------------------------
qmp-commands.hx | 69 +-
tests/ide-test.c | 43 +-
tests/qemu-iotests/049.out | 8 +-
util/cutils.c | 25 +
25 files changed, 2717 insertions(+), 2563 deletions(-)
delete mode 100644 cmd.c
delete mode 100644 cmd.h
create mode 100644 include/qemu-io.h
create mode 100644 qemu-io-cmds.c
--
1.8.1.4
^ permalink raw reply [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 01/26] blockdev: reset werror/rerror on drive_del
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 02/26] qemu-io: Remove unused args_command Stefan Hajnoczi
` (25 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori, Stefan Hajnoczi
Paolo Bonzini <pbonzini@redhat.com> suggested the following test case:
1. Launch a guest and wait at the GRUB boot menu:
qemu-system-x86_64 -enable-kvm -m 1024 \
-drive if=none,cache=none,file=test.img,id=foo,werror=stop,rerror=stop
-device virtio-blk-pci,drive=foo,id=virtio0,addr=4
2. Hot unplug the device:
(qemu) drive_del foo
3. Select the first boot menu entry
Without this patch the guest pauses due to ENOMEDIUM. The guest is
stuck in a continuous pause loop since the I/O request is retried and
fails immediately again when the guest is resumed.
With this patch the error is reported to the guest.
Note that this scenario actually happens sometimes during libvirt disk
hot unplug, where device_del is followed by drive_del. I/O may still be
submitted to the drive after drive_del if the guest does not process the
PCI hot unplug notification.
Reported-by: Dafna Ron <dron@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
---
blockdev.c | 4 ++++
hmp-commands.hx | 2 ++
2 files changed, 6 insertions(+)
diff --git a/blockdev.c b/blockdev.c
index b9b2d10..9937311 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1180,6 +1180,10 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
*/
if (bdrv_get_attached_dev(bs)) {
bdrv_make_anon(bs);
+
+ /* Further I/O must not pause the guest */
+ bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
+ BLOCKDEV_ON_ERROR_REPORT);
} else {
drive_uninit(drive_get_by_blockdev(bs));
}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 9cea415..4f5a3fd 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -185,6 +185,8 @@ Remove host block device. The result is that guest generated IO is no longer
submitted against the host device underlying the disk. Once a drive has
been deleted, the QEMU Block layer returns -EIO which results in IO
errors in the guest for applications that are reading/writing to the device.
+These errors are always reported to the guest, regardless of the drive's error
+actions (drive options rerror, werror).
ETEXI
{
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 02/26] qemu-io: Remove unused args_command
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 01/26] blockdev: reset werror/rerror on drive_del Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 03/26] cutils: Support 'P' and 'E' suffixes in strtosz() Stefan Hajnoczi
` (24 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
The original intention seems to be something with handling multiple
images at once, but this has never been implemented and the only
function ever registered is implemented to make everything behave like a
"global" command. Just do that unconditionally now.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 28 ++--------------------------
cmd.h | 2 --
qemu-io.c | 10 ----------
3 files changed, 2 insertions(+), 38 deletions(-)
diff --git a/cmd.c b/cmd.c
index 10a8688..4e7579b 100644
--- a/cmd.c
+++ b/cmd.c
@@ -34,7 +34,6 @@
cmdinfo_t *cmdtab;
int ncmds;
-static argsfunc_t args_func;
static checkfunc_t check_func;
static int ncmdline;
static char **cmdline;
@@ -127,22 +126,6 @@ void add_user_command(char *optarg)
cmdline[ncmdline-1] = optarg;
}
-static int
-args_command(
- int index)
-{
- if (args_func)
- return args_func(index);
- return 0;
-}
-
-void
-add_args_command(
- argsfunc_t af)
-{
- args_func = af;
-}
-
static void prep_fetchline(void *opaque)
{
int *fetchable = opaque;
@@ -155,7 +138,7 @@ static char *get_prompt(void);
void command_loop(void)
{
- int c, i, j = 0, done = 0, fetchable = 0, prompted = 0;
+ int c, i, done = 0, fetchable = 0, prompted = 0;
char *input;
char **v;
const cmdinfo_t *ct;
@@ -171,14 +154,7 @@ void command_loop(void)
if (c) {
ct = find_command(v[0]);
if (ct) {
- if (ct->flags & CMD_FLAG_GLOBAL) {
- done = command(ct, c, v);
- } else {
- j = 0;
- while (!done && (j = args_command(j))) {
- done = command(ct, c, v);
- }
- }
+ done = command(ct, c, v);
} else {
fprintf(stderr, _("command \"%s\" not found\n"), v[0]);
}
diff --git a/cmd.h b/cmd.h
index b763b19..8e6f753 100644
--- a/cmd.h
+++ b/cmd.h
@@ -41,12 +41,10 @@ extern int ncmds;
void help_init(void);
void quit_init(void);
-typedef int (*argsfunc_t)(int index);
typedef int (*checkfunc_t)(const cmdinfo_t *ci);
void add_command(const cmdinfo_t *ci);
void add_user_command(char *optarg);
-void add_args_command(argsfunc_t af);
void add_check_command(checkfunc_t cf);
const cmdinfo_t *find_command(const char *cmd);
diff --git a/qemu-io.c b/qemu-io.c
index 5e6680b..4288b8c 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1888,15 +1888,6 @@ static int open_f(int argc, char **argv)
return openfile(argv[optind], flags, growable);
}
-static int init_args_command(int index)
-{
- /* only one device allowed so far */
- if (index >= 1) {
- return 0;
- }
- return ++index;
-}
-
static int init_check_command(const cmdinfo_t *ct)
{
if (ct->flags & CMD_FLAG_GLOBAL) {
@@ -2043,7 +2034,6 @@ int main(int argc, char **argv)
add_command(&wait_break_cmd);
add_command(&abort_cmd);
- add_args_command(init_args_command);
add_check_command(init_check_command);
/* open the device */
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 03/26] cutils: Support 'P' and 'E' suffixes in strtosz()
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 01/26] blockdev: reset werror/rerror on drive_del Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 02/26] qemu-io: Remove unused args_command Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 04/26] qemu-io: Make cvtnum() a wrapper around strtosz_suffix() Stefan Hajnoczi
` (23 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/qemu-common.h | 2 ++
monitor.c | 8 ++++----
qemu-img.c | 10 ++++++----
tests/qemu-iotests/049.out | 8 ++++----
util/cutils.c | 4 ++++
5 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/include/qemu-common.h b/include/qemu-common.h
index cb82ef3..d95ea1e 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -191,6 +191,8 @@ int parse_uint_full(const char *s, unsigned long long *value, int base);
* A-Z, as strtosz() will use qemu_toupper() on the given argument
* prior to comparison.
*/
+#define STRTOSZ_DEFSUFFIX_EB 'E'
+#define STRTOSZ_DEFSUFFIX_PB 'P'
#define STRTOSZ_DEFSUFFIX_TB 'T'
#define STRTOSZ_DEFSUFFIX_GB 'G'
#define STRTOSZ_DEFSUFFIX_MB 'M'
diff --git a/monitor.c b/monitor.c
index eefc7f0..9d279b8 100644
--- a/monitor.c
+++ b/monitor.c
@@ -93,10 +93,10 @@
* 'M' Non-negative target long (32 or 64 bit), in user mode the
* value is multiplied by 2^20 (think Mebibyte)
* 'o' octets (aka bytes)
- * user mode accepts an optional T, t, G, g, M, m, K, k
- * suffix, which multiplies the value by 2^40 for
- * suffixes T and t, 2^30 for suffixes G and g, 2^20 for
- * M and m, 2^10 for K and k
+ * user mode accepts an optional E, e, P, p, T, t, G, g, M, m,
+ * K, k suffix, which multiplies the value by 2^60 for suffixes E
+ * and e, 2^50 for suffixes P and p, 2^40 for suffixes T and t,
+ * 2^30 for suffixes G and g, 2^20 for M and m, 2^10 for K and k
* 'T' double
* user mode accepts an optional ms, us, ns suffix,
* which divides the value by 1e3, 1e6, 1e9, respectively
diff --git a/qemu-img.c b/qemu-img.c
index 82c7977..e089c78 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -85,8 +85,9 @@ static void help(void)
" options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
" 'directsync' and 'unsafe' (default for convert)\n"
" 'size' is the disk image size in bytes. Optional suffixes\n"
- " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
- " and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
+ " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),\n"
+ " 'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P) are\n"
+ " supported. 'b' is ignored.\n"
" 'output_filename' is the destination disk image filename\n"
" 'output_fmt' is the destination format\n"
" 'options' is a comma separated list of format specific options in a\n"
@@ -387,8 +388,9 @@ static int img_create(int argc, char **argv)
error_report("Image size must be less than 8 EiB!");
} else {
error_report("Invalid image size specified! You may use k, M, "
- "G or T suffixes for ");
- error_report("kilobytes, megabytes, gigabytes and terabytes.");
+ "G, T, P or E suffixes for ");
+ error_report("kilobytes, megabytes, gigabytes, terabytes, "
+ "petabytes and exabytes.");
}
return 1;
}
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
index 72db13f..d2f0efe 100644
--- a/tests/qemu-iotests/049.out
+++ b/tests/qemu-iotests/049.out
@@ -108,15 +108,15 @@ qemu-img: Formatting or formatting option not supported for file format 'qcow2'
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
-qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for
-qemu-img: kilobytes, megabytes, gigabytes and terabytes.
+qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
+qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar
-qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for
-qemu-img: kilobytes, megabytes, gigabytes and terabytes.
+qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
+qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2
qemu-img: Parameter 'size' expects a size
diff --git a/util/cutils.c b/util/cutils.c
index a165819..8f28896 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -267,6 +267,10 @@ static int64_t suffix_mul(char suffix, int64_t unit)
return unit * unit * unit;
case STRTOSZ_DEFSUFFIX_TB:
return unit * unit * unit * unit;
+ case STRTOSZ_DEFSUFFIX_PB:
+ return unit * unit * unit * unit * unit;
+ case STRTOSZ_DEFSUFFIX_EB:
+ return unit * unit * unit * unit * unit * unit;
}
return -1;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 04/26] qemu-io: Make cvtnum() a wrapper around strtosz_suffix()
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (2 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 03/26] cutils: Support 'P' and 'E' suffixes in strtosz() Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 05/26] qemu-io: Handle cvtnum() errors in 'alloc' Stefan Hajnoczi
` (22 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
No reason to implement the same thing multiple times. A nice side effect
is that fractional numbers like 0.5M can be used in qemu-io now.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 37 -------------------------------------
cmd.h | 1 -
qemu-io.c | 6 ++++++
3 files changed, 6 insertions(+), 38 deletions(-)
diff --git a/cmd.c b/cmd.c
index 4e7579b..214c6f7 100644
--- a/cmd.c
+++ b/cmd.c
@@ -344,43 +344,6 @@ doneline(
#define MEGABYTES(x) ((long long)(x) << 20)
#define KILOBYTES(x) ((long long)(x) << 10)
-long long
-cvtnum(
- char *s)
-{
- long long i;
- char *sp;
- int c;
-
- i = strtoll(s, &sp, 0);
- if (i == 0 && sp == s)
- return -1LL;
- if (*sp == '\0')
- return i;
-
- if (sp[1] != '\0')
- return -1LL;
-
- c = qemu_tolower(*sp);
- switch (c) {
- default:
- return i;
- case 'k':
- return KILOBYTES(i);
- case 'm':
- return MEGABYTES(i);
- case 'g':
- return GIGABYTES(i);
- case 't':
- return TERABYTES(i);
- case 'p':
- return PETABYTES(i);
- case 'e':
- return EXABYTES(i);
- }
- return -1LL;
-}
-
#define TO_EXABYTES(x) ((x) / EXABYTES(1))
#define TO_PETABYTES(x) ((x) / PETABYTES(1))
#define TO_TERABYTES(x) ((x) / TERABYTES(1))
diff --git a/cmd.h b/cmd.h
index 8e6f753..4dcfe88 100644
--- a/cmd.h
+++ b/cmd.h
@@ -58,7 +58,6 @@ char **breakline(char *input, int *count);
void doneline(char *input, char **vec);
char *fetchline(void);
-long long cvtnum(char *s);
void cvtstr(double value, char *str, size_t sz);
struct timeval tsub(struct timeval t1, struct timeval t2);
diff --git a/qemu-io.c b/qemu-io.c
index 4288b8c..8a719a8 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -29,6 +29,12 @@ static BlockDriverState *bs;
static int misalign;
+static int64_t cvtnum(const char *s)
+{
+ char *end;
+ return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B);
+}
+
/*
* Parse the pattern argument to various sub-commands.
*
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 05/26] qemu-io: Handle cvtnum() errors in 'alloc'
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (3 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 04/26] qemu-io: Make cvtnum() a wrapper around strtosz_suffix() Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 06/26] qemu-io: Don't use global bs in command implementations Stefan Hajnoczi
` (21 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
qemu-io.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/qemu-io.c b/qemu-io.c
index 8a719a8..b4f56fc 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1596,7 +1596,10 @@ static int alloc_f(int argc, char **argv)
int ret;
offset = cvtnum(argv[1]);
- if (offset & 0x1ff) {
+ if (offset < 0) {
+ printf("non-numeric offset argument -- %s\n", argv[1]);
+ return 0;
+ } else if (offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
offset);
return 0;
@@ -1604,6 +1607,10 @@ static int alloc_f(int argc, char **argv)
if (argc == 3) {
nb_sectors = cvtnum(argv[2]);
+ if (nb_sectors < 0) {
+ printf("non-numeric length argument -- %s\n", argv[2]);
+ return 0;
+ }
} else {
nb_sectors = 1;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 06/26] qemu-io: Don't use global bs in command implementations
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (4 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 05/26] qemu-io: Handle cvtnum() errors in 'alloc' Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 07/26] qemu-io: Split off commands to qemu-io-cmds.c Stefan Hajnoczi
` (20 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Pass in the BlockDriverState to the command handlers instead of using
the global variable. This is an important step to make the commands
usable outside of qemu-io.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 6 ++-
cmd.h | 8 ++-
qemu-io.c | 167 ++++++++++++++++++++++++++++++++++----------------------------
3 files changed, 101 insertions(+), 80 deletions(-)
diff --git a/cmd.c b/cmd.c
index 214c6f7..d501aab 100644
--- a/cmd.c
+++ b/cmd.c
@@ -57,7 +57,7 @@ check_command(
const cmdinfo_t *ci)
{
if (check_func)
- return check_func(ci);
+ return check_func(qemuio_bs, ci);
return 1;
}
@@ -103,7 +103,7 @@ command(
return 0;
}
optind = 0;
- return ct->cfunc(argc, argv);
+ return ct->cfunc(qemuio_bs, argc, argv);
}
const cmdinfo_t *
@@ -452,6 +452,7 @@ static cmdinfo_t quit_cmd;
/* ARGSUSED */
static int
quit_f(
+ BlockDriverState *bs,
int argc,
char **argv)
{
@@ -490,6 +491,7 @@ help_all(void)
static int
help_f(
+ BlockDriverState *bs,
int argc,
char **argv)
{
diff --git a/cmd.h b/cmd.h
index 4dcfe88..ccf6336 100644
--- a/cmd.h
+++ b/cmd.h
@@ -17,9 +17,13 @@
#ifndef __COMMAND_H__
#define __COMMAND_H__
+#include "qemu-common.h"
+
#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */
-typedef int (*cfunc_t)(int argc, char **argv);
+extern BlockDriverState *qemuio_bs;
+
+typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv);
typedef void (*helpfunc_t)(void);
typedef struct cmdinfo {
@@ -41,7 +45,7 @@ extern int ncmds;
void help_init(void);
void quit_init(void);
-typedef int (*checkfunc_t)(const cmdinfo_t *ci);
+typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci);
void add_command(const cmdinfo_t *ci);
void add_user_command(char *optarg);
diff --git a/qemu-io.c b/qemu-io.c
index b4f56fc..39d7063 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -25,8 +25,8 @@
#define CMD_NOFILE_OK 0x01
char *progname;
-static BlockDriverState *bs;
+BlockDriverState *qemuio_bs;
static int misalign;
static int64_t cvtnum(const char *s)
@@ -63,7 +63,7 @@ static int parse_pattern(const char *arg)
*/
#define MISALIGN_OFFSET 16
-static void *qemu_io_alloc(size_t len, int pattern)
+static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern)
{
void *buf;
@@ -136,7 +136,8 @@ static void print_report(const char *op, struct timeval *t, int64_t offset,
* vector matching it.
*/
static void *
-create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
+create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov,
+ int pattern)
{
size_t *sizes = g_new0(size_t, nr_iov);
size_t count = 0;
@@ -172,7 +173,7 @@ create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
qemu_iovec_init(qiov, nr_iov);
- buf = p = qemu_io_alloc(count, pattern);
+ buf = p = qemu_io_alloc(bs, count, pattern);
for (i = 0; i < nr_iov; i++) {
qemu_iovec_add(qiov, p, sizes[i]);
@@ -184,7 +185,8 @@ fail:
return buf;
}
-static int do_read(char *buf, int64_t offset, int count, int *total)
+static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count,
+ int *total)
{
int ret;
@@ -196,7 +198,8 @@ static int do_read(char *buf, int64_t offset, int count, int *total)
return 1;
}
-static int do_write(char *buf, int64_t offset, int count, int *total)
+static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count,
+ int *total)
{
int ret;
@@ -208,7 +211,8 @@ static int do_write(char *buf, int64_t offset, int count, int *total)
return 1;
}
-static int do_pread(char *buf, int64_t offset, int count, int *total)
+static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count,
+ int *total)
{
*total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
if (*total < 0) {
@@ -217,7 +221,8 @@ static int do_pread(char *buf, int64_t offset, int count, int *total)
return 1;
}
-static int do_pwrite(char *buf, int64_t offset, int count, int *total)
+static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count,
+ int *total)
{
*total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
if (*total < 0) {
@@ -227,6 +232,7 @@ static int do_pwrite(char *buf, int64_t offset, int count, int *total)
}
typedef struct {
+ BlockDriverState *bs;
int64_t offset;
int count;
int *total;
@@ -238,7 +244,7 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
{
CoWriteZeroes *data = opaque;
- data->ret = bdrv_co_write_zeroes(bs, data->offset / BDRV_SECTOR_SIZE,
+ data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE,
data->count / BDRV_SECTOR_SIZE);
data->done = true;
if (data->ret < 0) {
@@ -249,10 +255,12 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque)
*data->total = data->count;
}
-static int do_co_write_zeroes(int64_t offset, int count, int *total)
+static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count,
+ int *total)
{
Coroutine *co;
CoWriteZeroes data = {
+ .bs = bs,
.offset = offset,
.count = count,
.total = total,
@@ -271,7 +279,8 @@ static int do_co_write_zeroes(int64_t offset, int count, int *total)
}
}
-static int do_write_compressed(char *buf, int64_t offset, int count, int *total)
+static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset,
+ int count, int *total)
{
int ret;
@@ -283,7 +292,8 @@ static int do_write_compressed(char *buf, int64_t offset, int count, int *total)
return 1;
}
-static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
+static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
+ int count, int *total)
{
*total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
if (*total < 0) {
@@ -292,7 +302,8 @@ static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
return 1;
}
-static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
+static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
+ int count, int *total)
{
*total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
if (*total < 0) {
@@ -307,7 +318,8 @@ static void aio_rw_done(void *opaque, int ret)
*(int *)opaque = ret;
}
-static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
+static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov,
+ int64_t offset, int *total)
{
int async_ret = NOT_DONE;
@@ -321,7 +333,8 @@ static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
return async_ret < 0 ? async_ret : 1;
}
-static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
+static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov,
+ int64_t offset, int *total)
{
int async_ret = NOT_DONE;
@@ -350,7 +363,8 @@ static void multiwrite_cb(void *opaque, int ret)
}
}
-static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total)
+static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs,
+ int num_reqs, int *total)
{
int i, ret;
struct multiwrite_async_ret async_ret = {
@@ -399,7 +413,7 @@ static void read_help(void)
"\n");
}
-static int read_f(int argc, char **argv);
+static int read_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t read_cmd = {
.name = "read",
@@ -412,7 +426,7 @@ static const cmdinfo_t read_cmd = {
.help = read_help,
};
-static int read_f(int argc, char **argv)
+static int read_f(BlockDriverState *bs, int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
@@ -518,15 +532,15 @@ static int read_f(int argc, char **argv)
}
}
- buf = qemu_io_alloc(count, 0xab);
+ buf = qemu_io_alloc(bs, count, 0xab);
gettimeofday(&t1, NULL);
if (pflag) {
- cnt = do_pread(buf, offset, count, &total);
+ cnt = do_pread(bs, buf, offset, count, &total);
} else if (bflag) {
- cnt = do_load_vmstate(buf, offset, count, &total);
+ cnt = do_load_vmstate(bs, buf, offset, count, &total);
} else {
- cnt = do_read(buf, offset, count, &total);
+ cnt = do_read(bs, buf, offset, count, &total);
}
gettimeofday(&t2, NULL);
@@ -583,7 +597,7 @@ static void readv_help(void)
"\n");
}
-static int readv_f(int argc, char **argv);
+static int readv_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t readv_cmd = {
.name = "readv",
@@ -595,7 +609,7 @@ static const cmdinfo_t readv_cmd = {
.help = readv_help,
};
-static int readv_f(int argc, char **argv)
+static int readv_f(BlockDriverState *bs, int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, qflag = 0, vflag = 0;
@@ -651,13 +665,13 @@ static int readv_f(int argc, char **argv)
}
nr_iov = argc - optind;
- buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
+ buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab);
if (buf == NULL) {
return 0;
}
gettimeofday(&t1, NULL);
- cnt = do_aio_readv(&qiov, offset, &total);
+ cnt = do_aio_readv(bs, &qiov, offset, &total);
gettimeofday(&t2, NULL);
if (cnt < 0) {
@@ -714,7 +728,7 @@ static void write_help(void)
"\n");
}
-static int write_f(int argc, char **argv);
+static int write_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t write_cmd = {
.name = "write",
@@ -727,7 +741,7 @@ static const cmdinfo_t write_cmd = {
.help = write_help,
};
-static int write_f(int argc, char **argv)
+static int write_f(BlockDriverState *bs, int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
@@ -814,20 +828,20 @@ static int write_f(int argc, char **argv)
}
if (!zflag) {
- buf = qemu_io_alloc(count, pattern);
+ buf = qemu_io_alloc(bs, count, pattern);
}
gettimeofday(&t1, NULL);
if (pflag) {
- cnt = do_pwrite(buf, offset, count, &total);
+ cnt = do_pwrite(bs, buf, offset, count, &total);
} else if (bflag) {
- cnt = do_save_vmstate(buf, offset, count, &total);
+ cnt = do_save_vmstate(bs, buf, offset, count, &total);
} else if (zflag) {
- cnt = do_co_write_zeroes(offset, count, &total);
+ cnt = do_co_write_zeroes(bs, offset, count, &total);
} else if (cflag) {
- cnt = do_write_compressed(buf, offset, count, &total);
+ cnt = do_write_compressed(bs, buf, offset, count, &total);
} else {
- cnt = do_write(buf, offset, count, &total);
+ cnt = do_write(bs, buf, offset, count, &total);
}
gettimeofday(&t2, NULL);
@@ -870,7 +884,7 @@ writev_help(void)
"\n");
}
-static int writev_f(int argc, char **argv);
+static int writev_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t writev_cmd = {
.name = "writev",
@@ -882,7 +896,7 @@ static const cmdinfo_t writev_cmd = {
.help = writev_help,
};
-static int writev_f(int argc, char **argv)
+static int writev_f(BlockDriverState *bs, int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, qflag = 0;
@@ -932,13 +946,13 @@ static int writev_f(int argc, char **argv)
}
nr_iov = argc - optind;
- buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
+ buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern);
if (buf == NULL) {
return 0;
}
gettimeofday(&t1, NULL);
- cnt = do_aio_writev(&qiov, offset, &total);
+ cnt = do_aio_writev(bs, &qiov, offset, &total);
gettimeofday(&t2, NULL);
if (cnt < 0) {
@@ -979,7 +993,7 @@ static void multiwrite_help(void)
"\n");
}
-static int multiwrite_f(int argc, char **argv);
+static int multiwrite_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t multiwrite_cmd = {
.name = "multiwrite",
@@ -991,7 +1005,7 @@ static const cmdinfo_t multiwrite_cmd = {
.help = multiwrite_help,
};
-static int multiwrite_f(int argc, char **argv)
+static int multiwrite_f(BlockDriverState *bs, int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, qflag = 0;
@@ -1072,7 +1086,7 @@ static int multiwrite_f(int argc, char **argv)
nr_iov = j - optind;
/* Build request */
- buf[i] = create_iovec(&qiovs[i], &argv[optind], nr_iov, pattern);
+ buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern);
if (buf[i] == NULL) {
goto out;
}
@@ -1090,7 +1104,7 @@ static int multiwrite_f(int argc, char **argv)
nr_reqs = i;
gettimeofday(&t1, NULL);
- cnt = do_aio_multiwrite(reqs, nr_reqs, &total);
+ cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total);
gettimeofday(&t2, NULL);
if (cnt < 0) {
@@ -1218,7 +1232,7 @@ static void aio_read_help(void)
"\n");
}
-static int aio_read_f(int argc, char **argv);
+static int aio_read_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t aio_read_cmd = {
.name = "aio_read",
@@ -1230,7 +1244,7 @@ static const cmdinfo_t aio_read_cmd = {
.help = aio_read_help,
};
-static int aio_read_f(int argc, char **argv)
+static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
{
int nr_iov, c;
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
@@ -1281,7 +1295,7 @@ static int aio_read_f(int argc, char **argv)
}
nr_iov = argc - optind;
- ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
+ ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab);
if (ctx->buf == NULL) {
g_free(ctx);
return 0;
@@ -1313,7 +1327,7 @@ static void aio_write_help(void)
"\n");
}
-static int aio_write_f(int argc, char **argv);
+static int aio_write_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t aio_write_cmd = {
.name = "aio_write",
@@ -1325,7 +1339,7 @@ static const cmdinfo_t aio_write_cmd = {
.help = aio_write_help,
};
-static int aio_write_f(int argc, char **argv)
+static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
{
int nr_iov, c;
int pattern = 0xcd;
@@ -1373,7 +1387,7 @@ static int aio_write_f(int argc, char **argv)
}
nr_iov = argc - optind;
- ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
+ ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern);
if (ctx->buf == NULL) {
g_free(ctx);
return 0;
@@ -1385,7 +1399,7 @@ static int aio_write_f(int argc, char **argv)
return 0;
}
-static int aio_flush_f(int argc, char **argv)
+static int aio_flush_f(BlockDriverState *bs, int argc, char **argv)
{
bdrv_drain_all();
return 0;
@@ -1397,7 +1411,7 @@ static const cmdinfo_t aio_flush_cmd = {
.oneline = "completes all outstanding aio requests"
};
-static int flush_f(int argc, char **argv)
+static int flush_f(BlockDriverState *bs, int argc, char **argv)
{
bdrv_flush(bs);
return 0;
@@ -1410,7 +1424,7 @@ static const cmdinfo_t flush_cmd = {
.oneline = "flush all in-core file state to disk",
};
-static int truncate_f(int argc, char **argv)
+static int truncate_f(BlockDriverState *bs, int argc, char **argv)
{
int64_t offset;
int ret;
@@ -1440,7 +1454,7 @@ static const cmdinfo_t truncate_cmd = {
.oneline = "truncates the current file at the given offset",
};
-static int length_f(int argc, char **argv)
+static int length_f(BlockDriverState *bs, int argc, char **argv)
{
int64_t size;
char s1[64];
@@ -1465,7 +1479,7 @@ static const cmdinfo_t length_cmd = {
};
-static int info_f(int argc, char **argv)
+static int info_f(BlockDriverState *bs, int argc, char **argv)
{
BlockDriverInfo bdi;
char s1[64], s2[64];
@@ -1516,7 +1530,7 @@ static void discard_help(void)
"\n");
}
-static int discard_f(int argc, char **argv);
+static int discard_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t discard_cmd = {
.name = "discard",
@@ -1529,7 +1543,7 @@ static const cmdinfo_t discard_cmd = {
.help = discard_help,
};
-static int discard_f(int argc, char **argv)
+static int discard_f(BlockDriverState *bs, int argc, char **argv)
{
struct timeval t1, t2;
int Cflag = 0, qflag = 0;
@@ -1587,7 +1601,7 @@ out:
return 0;
}
-static int alloc_f(int argc, char **argv)
+static int alloc_f(BlockDriverState *bs, int argc, char **argv)
{
int64_t offset, sector_num;
int nb_sectors, remaining;
@@ -1649,7 +1663,8 @@ static const cmdinfo_t alloc_cmd = {
};
-static int map_is_allocated(int64_t sector_num, int64_t nb_sectors, int64_t *pnum)
+static int map_is_allocated(BlockDriverState *bs, int64_t sector_num,
+ int64_t nb_sectors, int64_t *pnum)
{
int num, num_checked;
int ret, firstret;
@@ -1679,7 +1694,7 @@ static int map_is_allocated(int64_t sector_num, int64_t nb_sectors, int64_t *pnu
return firstret;
}
-static int map_f(int argc, char **argv)
+static int map_f(BlockDriverState *bs, int argc, char **argv)
{
int64_t offset;
int64_t nb_sectors;
@@ -1692,7 +1707,7 @@ static int map_f(int argc, char **argv)
nb_sectors = bs->total_sectors;
do {
- ret = map_is_allocated(offset, nb_sectors, &num);
+ ret = map_is_allocated(bs, offset, nb_sectors, &num);
if (ret < 0) {
error_report("Failed to get allocation status: %s", strerror(-ret));
return 0;
@@ -1720,7 +1735,7 @@ static const cmdinfo_t map_cmd = {
.oneline = "prints the allocated areas of a file",
};
-static int break_f(int argc, char **argv)
+static int break_f(BlockDriverState *bs, int argc, char **argv)
{
int ret;
@@ -1742,7 +1757,7 @@ static const cmdinfo_t break_cmd = {
"request as tag",
};
-static int resume_f(int argc, char **argv)
+static int resume_f(BlockDriverState *bs, int argc, char **argv)
{
int ret;
@@ -1763,7 +1778,7 @@ static const cmdinfo_t resume_cmd = {
.oneline = "resumes the request tagged as tag",
};
-static int wait_break_f(int argc, char **argv)
+static int wait_break_f(BlockDriverState *bs, int argc, char **argv)
{
while (!bdrv_debug_is_suspended(bs, argv[1])) {
qemu_aio_wait();
@@ -1781,7 +1796,7 @@ static const cmdinfo_t wait_break_cmd = {
.oneline = "waits for the suspension of a request",
};
-static int abort_f(int argc, char **argv)
+static int abort_f(BlockDriverState *bs, int argc, char **argv)
{
abort();
}
@@ -1793,10 +1808,10 @@ static const cmdinfo_t abort_cmd = {
.oneline = "simulate a program crash using abort(3)",
};
-static int close_f(int argc, char **argv)
+static int close_f(BlockDriverState *bs, int argc, char **argv)
{
bdrv_delete(bs);
- bs = NULL;
+ qemuio_bs = NULL;
return 0;
}
@@ -1809,23 +1824,23 @@ static const cmdinfo_t close_cmd = {
static int openfile(char *name, int flags, int growable)
{
- if (bs) {
+ if (qemuio_bs) {
fprintf(stderr, "file open already, try 'help close'\n");
return 1;
}
if (growable) {
- if (bdrv_file_open(&bs, name, NULL, flags)) {
+ if (bdrv_file_open(&qemuio_bs, name, NULL, flags)) {
fprintf(stderr, "%s: can't open device %s\n", progname, name);
return 1;
}
} else {
- bs = bdrv_new("hda");
+ qemuio_bs = bdrv_new("hda");
- if (bdrv_open(bs, name, NULL, flags, NULL) < 0) {
+ if (bdrv_open(qemuio_bs, name, NULL, flags, NULL) < 0) {
fprintf(stderr, "%s: can't open device %s\n", progname, name);
- bdrv_delete(bs);
- bs = NULL;
+ bdrv_delete(qemuio_bs);
+ qemuio_bs = NULL;
return 1;
}
}
@@ -1850,7 +1865,7 @@ static void open_help(void)
"\n");
}
-static int open_f(int argc, char **argv);
+static int open_f(BlockDriverState *bs, int argc, char **argv);
static const cmdinfo_t open_cmd = {
.name = "open",
@@ -1864,7 +1879,7 @@ static const cmdinfo_t open_cmd = {
.help = open_help,
};
-static int open_f(int argc, char **argv)
+static int open_f(BlockDriverState *bs, int argc, char **argv)
{
int flags = 0;
int readonly = 0;
@@ -1901,7 +1916,7 @@ static int open_f(int argc, char **argv)
return openfile(argv[optind], flags, growable);
}
-static int init_check_command(const cmdinfo_t *ct)
+static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
{
if (ct->flags & CMD_FLAG_GLOBAL) {
return 1;
@@ -2064,8 +2079,8 @@ int main(int argc, char **argv)
*/
bdrv_drain_all();
- if (bs) {
- bdrv_delete(bs);
+ if (qemuio_bs) {
+ bdrv_delete(qemuio_bs);
}
return 0;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 07/26] qemu-io: Split off commands to qemu-io-cmds.c
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (5 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 06/26] qemu-io: Don't use global bs in command implementations Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 08/26] qemu-io: Factor out qemuio_command Stefan Hajnoczi
` (19 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
This is the implementation of all qemu-io commands that make sense to be
called from the qemu monitor, i.e. everything except open, close and
quit.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
Makefile | 2 +-
qemu-io-cmds.c | 1835 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
qemu-io.c | 1817 +------------------------------------------------------
3 files changed, 1838 insertions(+), 1816 deletions(-)
create mode 100644 qemu-io-cmds.c
diff --git a/Makefile b/Makefile
index a96736b..cf932eb 100644
--- a/Makefile
+++ b/Makefile
@@ -186,7 +186,7 @@ qemu-img.o: qemu-img-cmds.h
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
-qemu-io$(EXESUF): qemu-io.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a
+qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
new file mode 100644
index 0000000..0a3817a
--- /dev/null
+++ b/qemu-io-cmds.c
@@ -0,0 +1,1835 @@
+/*
+ * Command line utility to exercise the QEMU I/O path.
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (c) 2003-2005 Silicon Graphics, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "block/block_int.h"
+#include "cmd.h"
+
+#define CMD_NOFILE_OK 0x01
+
+int qemuio_misalign;
+
+static int64_t cvtnum(const char *s)
+{
+ char *end;
+ return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B);
+}
+
+/*
+ * Parse the pattern argument to various sub-commands.
+ *
+ * Because the pattern is used as an argument to memset it must evaluate
+ * to an unsigned integer that fits into a single byte.
+ */
+static int parse_pattern(const char *arg)
+{
+ char *endptr = NULL;
+ long pattern;
+
+ pattern = strtol(arg, &endptr, 0);
+ if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
+ printf("%s is not a valid pattern byte\n", arg);
+ return -1;
+ }
+
+ return pattern;
+}
+
+/*
+ * Memory allocation helpers.
+ *
+ * Make sure memory is aligned by default, or purposefully misaligned if
+ * that is specified on the command line.
+ */
+
+#define MISALIGN_OFFSET 16
+static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern)
+{
+ void *buf;
+
+ if (qemuio_misalign) {
+ len += MISALIGN_OFFSET;
+ }
+ buf = qemu_blockalign(bs, len);
+ memset(buf, pattern, len);
+ if (qemuio_misalign) {
+ buf += MISALIGN_OFFSET;
+ }
+ return buf;
+}
+
+static void qemu_io_free(void *p)
+{
+ if (qemuio_misalign) {
+ p -= MISALIGN_OFFSET;
+ }
+ qemu_vfree(p);
+}
+
+static void dump_buffer(const void *buffer, int64_t offset, int len)
+{
+ int i, j;
+ const uint8_t *p;
+
+ for (i = 0, p = buffer; i < len; i += 16) {
+ const uint8_t *s = p;
+
+ printf("%08" PRIx64 ": ", offset + i);
+ for (j = 0; j < 16 && i + j < len; j++, p++) {
+ printf("%02x ", *p);
+ }
+ printf(" ");
+ for (j = 0; j < 16 && i + j < len; j++, s++) {
+ if (isalnum(*s)) {
+ printf("%c", *s);
+ } else {
+ printf(".");
+ }
+ }
+ printf("\n");
+ }
+}
+
+static void print_report(const char *op, struct timeval *t, int64_t offset,
+ int count, int total, int cnt, int Cflag)
+{
+ char s1[64], s2[64], ts[64];
+
+ timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
+ if (!Cflag) {
+ cvtstr((double)total, s1, sizeof(s1));
+ cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
+ printf("%s %d/%d bytes at offset %" PRId64 "\n",
+ op, total, count, offset);
+ printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
+ s1, cnt, ts, s2, tdiv((double)cnt, *t));
+ } else {/* bytes,ops,time,bytes/sec,ops/sec */
+ printf("%d,%d,%s,%.3f,%.3f\n",
+ total, cnt, ts,
+ tdiv((double)total, *t),
+ tdiv((double)cnt, *t));
+ }
+}
+
+/*
+ * Parse multiple length statements for vectored I/O, and construct an I/O
+ * vector matching it.
+ */
+static void *
+create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov,
+ int pattern)
+{
+ size_t *sizes = g_new0(size_t, nr_iov);
+ size_t count = 0;
+ void *buf = NULL;
+ void *p;
+ int i;
+
+ for (i = 0; i < nr_iov; i++) {
+ char *arg = argv[i];
+ int64_t len;
+
+ len = cvtnum(arg);
+ if (len < 0) {
+ printf("non-numeric length argument -- %s\n", arg);
+ goto fail;
+ }
+
+ /* should be SIZE_T_MAX, but that doesn't exist */
+ if (len > INT_MAX) {
+ printf("too large length argument -- %s\n", arg);
+ goto fail;
+ }
+
+ if (len & 0x1ff) {
+ printf("length argument %" PRId64
+ " is not sector aligned\n", len);
+ goto fail;
+ }
+
+ sizes[i] = len;
+ count += len;
+ }
+
+ qemu_iovec_init(qiov, nr_iov);
+
+ buf = p = qemu_io_alloc(bs, count, pattern);
+
+ for (i = 0; i < nr_iov; i++) {
+ qemu_iovec_add(qiov, p, sizes[i]);
+ p += sizes[i];
+ }
+
+fail:
+ g_free(sizes);
+ return buf;
+}
+
+static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count,
+ int *total)
+{
+ int ret;
+
+ ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+ if (ret < 0) {
+ return ret;
+ }
+ *total = count;
+ return 1;
+}
+
+static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count,
+ int *total)
+{
+ int ret;
+
+ ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+ if (ret < 0) {
+ return ret;
+ }
+ *total = count;
+ return 1;
+}
+
+static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count,
+ int *total)
+{
+ *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
+ if (*total < 0) {
+ return *total;
+ }
+ return 1;
+}
+
+static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count,
+ int *total)
+{
+ *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
+ if (*total < 0) {
+ return *total;
+ }
+ return 1;
+}
+
+typedef struct {
+ BlockDriverState *bs;
+ int64_t offset;
+ int count;
+ int *total;
+ int ret;
+ bool done;
+} CoWriteZeroes;
+
+static void coroutine_fn co_write_zeroes_entry(void *opaque)
+{
+ CoWriteZeroes *data = opaque;
+
+ data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE,
+ data->count / BDRV_SECTOR_SIZE);
+ data->done = true;
+ if (data->ret < 0) {
+ *data->total = data->ret;
+ return;
+ }
+
+ *data->total = data->count;
+}
+
+static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count,
+ int *total)
+{
+ Coroutine *co;
+ CoWriteZeroes data = {
+ .bs = bs,
+ .offset = offset,
+ .count = count,
+ .total = total,
+ .done = false,
+ };
+
+ co = qemu_coroutine_create(co_write_zeroes_entry);
+ qemu_coroutine_enter(co, &data);
+ while (!data.done) {
+ qemu_aio_wait();
+ }
+ if (data.ret < 0) {
+ return data.ret;
+ } else {
+ return 1;
+ }
+}
+
+static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset,
+ int count, int *total)
+{
+ int ret;
+
+ ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+ if (ret < 0) {
+ return ret;
+ }
+ *total = count;
+ return 1;
+}
+
+static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
+ int count, int *total)
+{
+ *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
+ if (*total < 0) {
+ return *total;
+ }
+ return 1;
+}
+
+static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
+ int count, int *total)
+{
+ *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
+ if (*total < 0) {
+ return *total;
+ }
+ return 1;
+}
+
+#define NOT_DONE 0x7fffffff
+static void aio_rw_done(void *opaque, int ret)
+{
+ *(int *)opaque = ret;
+}
+
+static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov,
+ int64_t offset, int *total)
+{
+ int async_ret = NOT_DONE;
+
+ bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
+ aio_rw_done, &async_ret);
+ while (async_ret == NOT_DONE) {
+ main_loop_wait(false);
+ }
+
+ *total = qiov->size;
+ return async_ret < 0 ? async_ret : 1;
+}
+
+static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov,
+ int64_t offset, int *total)
+{
+ int async_ret = NOT_DONE;
+
+ bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
+ aio_rw_done, &async_ret);
+ while (async_ret == NOT_DONE) {
+ main_loop_wait(false);
+ }
+
+ *total = qiov->size;
+ return async_ret < 0 ? async_ret : 1;
+}
+
+struct multiwrite_async_ret {
+ int num_done;
+ int error;
+};
+
+static void multiwrite_cb(void *opaque, int ret)
+{
+ struct multiwrite_async_ret *async_ret = opaque;
+
+ async_ret->num_done++;
+ if (ret < 0) {
+ async_ret->error = ret;
+ }
+}
+
+static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs,
+ int num_reqs, int *total)
+{
+ int i, ret;
+ struct multiwrite_async_ret async_ret = {
+ .num_done = 0,
+ .error = 0,
+ };
+
+ *total = 0;
+ for (i = 0; i < num_reqs; i++) {
+ reqs[i].cb = multiwrite_cb;
+ reqs[i].opaque = &async_ret;
+ *total += reqs[i].qiov->size;
+ }
+
+ ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ while (async_ret.num_done < num_reqs) {
+ main_loop_wait(false);
+ }
+
+ return async_ret.error < 0 ? async_ret.error : 1;
+}
+
+static void read_help(void)
+{
+ printf(
+"\n"
+" reads a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" -b, -- read from the VM state rather than the virtual disk\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -l, -- length for pattern verification (only with -P)\n"
+" -p, -- use bdrv_pread to read the file\n"
+" -P, -- use a pattern to verify read data\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+" -s, -- start offset for pattern verification (only with -P)\n"
+" -v, -- dump buffer to standard output\n"
+"\n");
+}
+
+static int read_f(BlockDriverState *bs, int argc, char **argv);
+
+static const cmdinfo_t read_cmd = {
+ .name = "read",
+ .altname = "r",
+ .cfunc = read_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
+ .oneline = "reads a number of bytes at a specified offset",
+ .help = read_help,
+};
+
+static int read_f(BlockDriverState *bs, int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
+ int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
+ int c, cnt;
+ char *buf;
+ int64_t offset;
+ int count;
+ /* Some compilers get confused and warn if this is not initialized. */
+ int total = 0;
+ int pattern = 0, pattern_offset = 0, pattern_count = 0;
+
+ while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
+ switch (c) {
+ case 'b':
+ bflag = 1;
+ break;
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ pattern_count = cvtnum(optarg);
+ if (pattern_count < 0) {
+ printf("non-numeric length argument -- %s\n", optarg);
+ return 0;
+ }
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ pattern = parse_pattern(optarg);
+ if (pattern < 0) {
+ return 0;
+ }
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ pattern_offset = cvtnum(optarg);
+ if (pattern_offset < 0) {
+ printf("non-numeric length argument -- %s\n", optarg);
+ return 0;
+ }
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ return command_usage(&read_cmd);
+ }
+ }
+
+ if (optind != argc - 2) {
+ return command_usage(&read_cmd);
+ }
+
+ if (bflag && pflag) {
+ printf("-b and -p cannot be specified at the same time\n");
+ return 0;
+ }
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ optind++;
+ count = cvtnum(argv[optind]);
+ if (count < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ if (!Pflag && (lflag || sflag)) {
+ return command_usage(&read_cmd);
+ }
+
+ if (!lflag) {
+ pattern_count = count - pattern_offset;
+ }
+
+ if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) {
+ printf("pattern verification range exceeds end of read data\n");
+ return 0;
+ }
+
+ if (!pflag) {
+ if (offset & 0x1ff) {
+ printf("offset %" PRId64 " is not sector aligned\n",
+ offset);
+ return 0;
+ }
+ if (count & 0x1ff) {
+ printf("count %d is not sector aligned\n",
+ count);
+ return 0;
+ }
+ }
+
+ buf = qemu_io_alloc(bs, count, 0xab);
+
+ gettimeofday(&t1, NULL);
+ if (pflag) {
+ cnt = do_pread(bs, buf, offset, count, &total);
+ } else if (bflag) {
+ cnt = do_load_vmstate(bs, buf, offset, count, &total);
+ } else {
+ cnt = do_read(bs, buf, offset, count, &total);
+ }
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("read failed: %s\n", strerror(-cnt));
+ goto out;
+ }
+
+ if (Pflag) {
+ void *cmp_buf = g_malloc(pattern_count);
+ memset(cmp_buf, pattern, pattern_count);
+ if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
+ printf("Pattern verification failed at offset %"
+ PRId64 ", %d bytes\n",
+ offset + pattern_offset, pattern_count);
+ }
+ g_free(cmp_buf);
+ }
+
+ if (qflag) {
+ goto out;
+ }
+
+ if (vflag) {
+ dump_buffer(buf, offset, count);
+ }
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("read", &t2, offset, count, total, cnt, Cflag);
+
+out:
+ qemu_io_free(buf);
+
+ return 0;
+}
+
+static void readv_help(void)
+{
+ printf(
+"\n"
+" reads a range of bytes from the given offset into multiple buffers\n"
+"\n"
+" Example:\n"
+" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" Uses multiple iovec buffers if more than one byte range is specified.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -P, -- use a pattern to verify read data\n"
+" -v, -- dump buffer to standard output\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int readv_f(BlockDriverState *bs, int argc, char **argv);
+
+static const cmdinfo_t readv_cmd = {
+ .name = "readv",
+ .cfunc = readv_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cqv] [-P pattern ] off len [len..]",
+ .oneline = "reads a number of bytes at a specified offset",
+ .help = readv_help,
+};
+
+static int readv_f(BlockDriverState *bs, int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, qflag = 0, vflag = 0;
+ int c, cnt;
+ char *buf;
+ int64_t offset;
+ /* Some compilers get confused and warn if this is not initialized. */
+ int total = 0;
+ int nr_iov;
+ QEMUIOVector qiov;
+ int pattern = 0;
+ int Pflag = 0;
+
+ while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ pattern = parse_pattern(optarg);
+ if (pattern < 0) {
+ return 0;
+ }
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ return command_usage(&readv_cmd);
+ }
+ }
+
+ if (optind > argc - 2) {
+ return command_usage(&readv_cmd);
+ }
+
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+ optind++;
+
+ if (offset & 0x1ff) {
+ printf("offset %" PRId64 " is not sector aligned\n",
+ offset);
+ return 0;
+ }
+
+ nr_iov = argc - optind;
+ buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab);
+ if (buf == NULL) {
+ return 0;
+ }
+
+ gettimeofday(&t1, NULL);
+ cnt = do_aio_readv(bs, &qiov, offset, &total);
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("readv failed: %s\n", strerror(-cnt));
+ goto out;
+ }
+
+ if (Pflag) {
+ void *cmp_buf = g_malloc(qiov.size);
+ memset(cmp_buf, pattern, qiov.size);
+ if (memcmp(buf, cmp_buf, qiov.size)) {
+ printf("Pattern verification failed at offset %"
+ PRId64 ", %zd bytes\n", offset, qiov.size);
+ }
+ g_free(cmp_buf);
+ }
+
+ if (qflag) {
+ goto out;
+ }
+
+ if (vflag) {
+ dump_buffer(buf, offset, qiov.size);
+ }
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
+
+out:
+ qemu_iovec_destroy(&qiov);
+ qemu_io_free(buf);
+ return 0;
+}
+
+static void write_help(void)
+{
+ printf(
+"\n"
+" writes a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" -b, -- write to the VM state rather than the virtual disk\n"
+" -c, -- write compressed data with bdrv_write_compressed\n"
+" -p, -- use bdrv_pwrite to write the file\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+" -z, -- write zeroes using bdrv_co_write_zeroes\n"
+"\n");
+}
+
+static int write_f(BlockDriverState *bs, int argc, char **argv);
+
+static const cmdinfo_t write_cmd = {
+ .name = "write",
+ .altname = "w",
+ .cfunc = write_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-bcCpqz] [-P pattern ] off len",
+ .oneline = "writes a number of bytes at a specified offset",
+ .help = write_help,
+};
+
+static int write_f(BlockDriverState *bs, int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
+ int cflag = 0;
+ int c, cnt;
+ char *buf = NULL;
+ int64_t offset;
+ int count;
+ /* Some compilers get confused and warn if this is not initialized. */
+ int total = 0;
+ int pattern = 0xcd;
+
+ while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) {
+ switch (c) {
+ case 'b':
+ bflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ pattern = parse_pattern(optarg);
+ if (pattern < 0) {
+ return 0;
+ }
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'z':
+ zflag = 1;
+ break;
+ default:
+ return command_usage(&write_cmd);
+ }
+ }
+
+ if (optind != argc - 2) {
+ return command_usage(&write_cmd);
+ }
+
+ if (bflag + pflag + zflag > 1) {
+ printf("-b, -p, or -z cannot be specified at the same time\n");
+ return 0;
+ }
+
+ if (zflag && Pflag) {
+ printf("-z and -P cannot be specified at the same time\n");
+ return 0;
+ }
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ optind++;
+ count = cvtnum(argv[optind]);
+ if (count < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ if (!pflag) {
+ if (offset & 0x1ff) {
+ printf("offset %" PRId64 " is not sector aligned\n",
+ offset);
+ return 0;
+ }
+
+ if (count & 0x1ff) {
+ printf("count %d is not sector aligned\n",
+ count);
+ return 0;
+ }
+ }
+
+ if (!zflag) {
+ buf = qemu_io_alloc(bs, count, pattern);
+ }
+
+ gettimeofday(&t1, NULL);
+ if (pflag) {
+ cnt = do_pwrite(bs, buf, offset, count, &total);
+ } else if (bflag) {
+ cnt = do_save_vmstate(bs, buf, offset, count, &total);
+ } else if (zflag) {
+ cnt = do_co_write_zeroes(bs, offset, count, &total);
+ } else if (cflag) {
+ cnt = do_write_compressed(bs, buf, offset, count, &total);
+ } else {
+ cnt = do_write(bs, buf, offset, count, &total);
+ }
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("write failed: %s\n", strerror(-cnt));
+ goto out;
+ }
+
+ if (qflag) {
+ goto out;
+ }
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("wrote", &t2, offset, count, total, cnt, Cflag);
+
+out:
+ if (!zflag) {
+ qemu_io_free(buf);
+ }
+
+ return 0;
+}
+
+static void
+writev_help(void)
+{
+ printf(
+"\n"
+" writes a range of bytes from the given offset source from multiple buffers\n"
+"\n"
+" Example:\n"
+" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int writev_f(BlockDriverState *bs, int argc, char **argv);
+
+static const cmdinfo_t writev_cmd = {
+ .name = "writev",
+ .cfunc = writev_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cq] [-P pattern ] off len [len..]",
+ .oneline = "writes a number of bytes at a specified offset",
+ .help = writev_help,
+};
+
+static int writev_f(BlockDriverState *bs, int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, qflag = 0;
+ int c, cnt;
+ char *buf;
+ int64_t offset;
+ /* Some compilers get confused and warn if this is not initialized. */
+ int total = 0;
+ int nr_iov;
+ int pattern = 0xcd;
+ QEMUIOVector qiov;
+
+ while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'P':
+ pattern = parse_pattern(optarg);
+ if (pattern < 0) {
+ return 0;
+ }
+ break;
+ default:
+ return command_usage(&writev_cmd);
+ }
+ }
+
+ if (optind > argc - 2) {
+ return command_usage(&writev_cmd);
+ }
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+ optind++;
+
+ if (offset & 0x1ff) {
+ printf("offset %" PRId64 " is not sector aligned\n",
+ offset);
+ return 0;
+ }
+
+ nr_iov = argc - optind;
+ buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern);
+ if (buf == NULL) {
+ return 0;
+ }
+
+ gettimeofday(&t1, NULL);
+ cnt = do_aio_writev(bs, &qiov, offset, &total);
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("writev failed: %s\n", strerror(-cnt));
+ goto out;
+ }
+
+ if (qflag) {
+ goto out;
+ }
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
+out:
+ qemu_iovec_destroy(&qiov);
+ qemu_io_free(buf);
+ return 0;
+}
+
+static void multiwrite_help(void)
+{
+ printf(
+"\n"
+" writes a range of bytes from the given offset source from multiple buffers,\n"
+" in a batch of requests that may be merged by qemu\n"
+"\n"
+" Example:\n"
+" 'multiwrite 512 1k 1k ; 4k 1k'\n"
+" writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
+" by one for each request contained in the multiwrite command.\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int multiwrite_f(BlockDriverState *bs, int argc, char **argv);
+
+static const cmdinfo_t multiwrite_cmd = {
+ .name = "multiwrite",
+ .cfunc = multiwrite_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
+ .oneline = "issues multiple write requests at once",
+ .help = multiwrite_help,
+};
+
+static int multiwrite_f(BlockDriverState *bs, int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, qflag = 0;
+ int c, cnt;
+ char **buf;
+ int64_t offset, first_offset = 0;
+ /* Some compilers get confused and warn if this is not initialized. */
+ int total = 0;
+ int nr_iov;
+ int nr_reqs;
+ int pattern = 0xcd;
+ QEMUIOVector *qiovs;
+ int i;
+ BlockRequest *reqs;
+
+ while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'P':
+ pattern = parse_pattern(optarg);
+ if (pattern < 0) {
+ return 0;
+ }
+ break;
+ default:
+ return command_usage(&writev_cmd);
+ }
+ }
+
+ if (optind > argc - 2) {
+ return command_usage(&writev_cmd);
+ }
+
+ nr_reqs = 1;
+ for (i = optind; i < argc; i++) {
+ if (!strcmp(argv[i], ";")) {
+ nr_reqs++;
+ }
+ }
+
+ reqs = g_malloc0(nr_reqs * sizeof(*reqs));
+ buf = g_malloc0(nr_reqs * sizeof(*buf));
+ qiovs = g_malloc(nr_reqs * sizeof(*qiovs));
+
+ for (i = 0; i < nr_reqs && optind < argc; i++) {
+ int j;
+
+ /* Read the offset of the request */
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric offset argument -- %s\n", argv[optind]);
+ goto out;
+ }
+ optind++;
+
+ if (offset & 0x1ff) {
+ printf("offset %lld is not sector aligned\n",
+ (long long)offset);
+ goto out;
+ }
+
+ if (i == 0) {
+ first_offset = offset;
+ }
+
+ /* Read lengths for qiov entries */
+ for (j = optind; j < argc; j++) {
+ if (!strcmp(argv[j], ";")) {
+ break;
+ }
+ }
+
+ nr_iov = j - optind;
+
+ /* Build request */
+ buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern);
+ if (buf[i] == NULL) {
+ goto out;
+ }
+
+ reqs[i].qiov = &qiovs[i];
+ reqs[i].sector = offset >> 9;
+ reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
+
+ optind = j + 1;
+
+ pattern++;
+ }
+
+ /* If there were empty requests at the end, ignore them */
+ nr_reqs = i;
+
+ gettimeofday(&t1, NULL);
+ cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total);
+ gettimeofday(&t2, NULL);
+
+ if (cnt < 0) {
+ printf("aio_multiwrite failed: %s\n", strerror(-cnt));
+ goto out;
+ }
+
+ if (qflag) {
+ goto out;
+ }
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, t1);
+ print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
+out:
+ for (i = 0; i < nr_reqs; i++) {
+ qemu_io_free(buf[i]);
+ if (reqs[i].qiov != NULL) {
+ qemu_iovec_destroy(&qiovs[i]);
+ }
+ }
+ g_free(buf);
+ g_free(reqs);
+ g_free(qiovs);
+ return 0;
+}
+
+struct aio_ctx {
+ QEMUIOVector qiov;
+ int64_t offset;
+ char *buf;
+ int qflag;
+ int vflag;
+ int Cflag;
+ int Pflag;
+ int pattern;
+ struct timeval t1;
+};
+
+static void aio_write_done(void *opaque, int ret)
+{
+ struct aio_ctx *ctx = opaque;
+ struct timeval t2;
+
+ gettimeofday(&t2, NULL);
+
+
+ if (ret < 0) {
+ printf("aio_write failed: %s\n", strerror(-ret));
+ goto out;
+ }
+
+ if (ctx->qflag) {
+ goto out;
+ }
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, ctx->t1);
+ print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
+ ctx->qiov.size, 1, ctx->Cflag);
+out:
+ qemu_io_free(ctx->buf);
+ qemu_iovec_destroy(&ctx->qiov);
+ g_free(ctx);
+}
+
+static void aio_read_done(void *opaque, int ret)
+{
+ struct aio_ctx *ctx = opaque;
+ struct timeval t2;
+
+ gettimeofday(&t2, NULL);
+
+ if (ret < 0) {
+ printf("readv failed: %s\n", strerror(-ret));
+ goto out;
+ }
+
+ if (ctx->Pflag) {
+ void *cmp_buf = g_malloc(ctx->qiov.size);
+
+ memset(cmp_buf, ctx->pattern, ctx->qiov.size);
+ if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
+ printf("Pattern verification failed at offset %"
+ PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
+ }
+ g_free(cmp_buf);
+ }
+
+ if (ctx->qflag) {
+ goto out;
+ }
+
+ if (ctx->vflag) {
+ dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
+ }
+
+ /* Finally, report back -- -C gives a parsable format */
+ t2 = tsub(t2, ctx->t1);
+ print_report("read", &t2, ctx->offset, ctx->qiov.size,
+ ctx->qiov.size, 1, ctx->Cflag);
+out:
+ qemu_io_free(ctx->buf);
+ qemu_iovec_destroy(&ctx->qiov);
+ g_free(ctx);
+}
+
+static void aio_read_help(void)
+{
+ printf(
+"\n"
+" asynchronously reads a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
+"\n"
+" Reads a segment of the currently open file, optionally dumping it to the\n"
+" standard output stream (with -v option) for subsequent inspection.\n"
+" The read is performed asynchronously and the aio_flush command must be\n"
+" used to ensure all outstanding aio requests have been completed.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -P, -- use a pattern to verify read data\n"
+" -v, -- dump buffer to standard output\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int aio_read_f(BlockDriverState *bs, int argc, char **argv);
+
+static const cmdinfo_t aio_read_cmd = {
+ .name = "aio_read",
+ .cfunc = aio_read_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cqv] [-P pattern ] off len [len..]",
+ .oneline = "asynchronously reads a number of bytes",
+ .help = aio_read_help,
+};
+
+static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
+{
+ int nr_iov, c;
+ struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
+
+ while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
+ switch (c) {
+ case 'C':
+ ctx->Cflag = 1;
+ break;
+ case 'P':
+ ctx->Pflag = 1;
+ ctx->pattern = parse_pattern(optarg);
+ if (ctx->pattern < 0) {
+ g_free(ctx);
+ return 0;
+ }
+ break;
+ case 'q':
+ ctx->qflag = 1;
+ break;
+ case 'v':
+ ctx->vflag = 1;
+ break;
+ default:
+ g_free(ctx);
+ return command_usage(&aio_read_cmd);
+ }
+ }
+
+ if (optind > argc - 2) {
+ g_free(ctx);
+ return command_usage(&aio_read_cmd);
+ }
+
+ ctx->offset = cvtnum(argv[optind]);
+ if (ctx->offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ g_free(ctx);
+ return 0;
+ }
+ optind++;
+
+ if (ctx->offset & 0x1ff) {
+ printf("offset %" PRId64 " is not sector aligned\n",
+ ctx->offset);
+ g_free(ctx);
+ return 0;
+ }
+
+ nr_iov = argc - optind;
+ ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab);
+ if (ctx->buf == NULL) {
+ g_free(ctx);
+ return 0;
+ }
+
+ gettimeofday(&ctx->t1, NULL);
+ bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
+ ctx->qiov.size >> 9, aio_read_done, ctx);
+ return 0;
+}
+
+static void aio_write_help(void)
+{
+ printf(
+"\n"
+" asynchronously writes a range of bytes from the given offset source\n"
+" from multiple buffers\n"
+"\n"
+" Example:\n"
+" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
+"\n"
+" Writes into a segment of the currently open file, using a buffer\n"
+" filled with a set pattern (0xcdcdcdcd).\n"
+" The write is performed asynchronously and the aio_flush command must be\n"
+" used to ensure all outstanding aio requests have been completed.\n"
+" -P, -- use different pattern to fill file\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int aio_write_f(BlockDriverState *bs, int argc, char **argv);
+
+static const cmdinfo_t aio_write_cmd = {
+ .name = "aio_write",
+ .cfunc = aio_write_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cq] [-P pattern ] off len [len..]",
+ .oneline = "asynchronously writes a number of bytes",
+ .help = aio_write_help,
+};
+
+static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
+{
+ int nr_iov, c;
+ int pattern = 0xcd;
+ struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
+
+ while ((c = getopt(argc, argv, "CqP:")) != EOF) {
+ switch (c) {
+ case 'C':
+ ctx->Cflag = 1;
+ break;
+ case 'q':
+ ctx->qflag = 1;
+ break;
+ case 'P':
+ pattern = parse_pattern(optarg);
+ if (pattern < 0) {
+ g_free(ctx);
+ return 0;
+ }
+ break;
+ default:
+ g_free(ctx);
+ return command_usage(&aio_write_cmd);
+ }
+ }
+
+ if (optind > argc - 2) {
+ g_free(ctx);
+ return command_usage(&aio_write_cmd);
+ }
+
+ ctx->offset = cvtnum(argv[optind]);
+ if (ctx->offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ g_free(ctx);
+ return 0;
+ }
+ optind++;
+
+ if (ctx->offset & 0x1ff) {
+ printf("offset %" PRId64 " is not sector aligned\n",
+ ctx->offset);
+ g_free(ctx);
+ return 0;
+ }
+
+ nr_iov = argc - optind;
+ ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern);
+ if (ctx->buf == NULL) {
+ g_free(ctx);
+ return 0;
+ }
+
+ gettimeofday(&ctx->t1, NULL);
+ bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
+ ctx->qiov.size >> 9, aio_write_done, ctx);
+ return 0;
+}
+
+static int aio_flush_f(BlockDriverState *bs, int argc, char **argv)
+{
+ bdrv_drain_all();
+ return 0;
+}
+
+static const cmdinfo_t aio_flush_cmd = {
+ .name = "aio_flush",
+ .cfunc = aio_flush_f,
+ .oneline = "completes all outstanding aio requests"
+};
+
+static int flush_f(BlockDriverState *bs, int argc, char **argv)
+{
+ bdrv_flush(bs);
+ return 0;
+}
+
+static const cmdinfo_t flush_cmd = {
+ .name = "flush",
+ .altname = "f",
+ .cfunc = flush_f,
+ .oneline = "flush all in-core file state to disk",
+};
+
+static int truncate_f(BlockDriverState *bs, int argc, char **argv)
+{
+ int64_t offset;
+ int ret;
+
+ offset = cvtnum(argv[1]);
+ if (offset < 0) {
+ printf("non-numeric truncate argument -- %s\n", argv[1]);
+ return 0;
+ }
+
+ ret = bdrv_truncate(bs, offset);
+ if (ret < 0) {
+ printf("truncate: %s\n", strerror(-ret));
+ return 0;
+ }
+
+ return 0;
+}
+
+static const cmdinfo_t truncate_cmd = {
+ .name = "truncate",
+ .altname = "t",
+ .cfunc = truncate_f,
+ .argmin = 1,
+ .argmax = 1,
+ .args = "off",
+ .oneline = "truncates the current file at the given offset",
+};
+
+static int length_f(BlockDriverState *bs, int argc, char **argv)
+{
+ int64_t size;
+ char s1[64];
+
+ size = bdrv_getlength(bs);
+ if (size < 0) {
+ printf("getlength: %s\n", strerror(-size));
+ return 0;
+ }
+
+ cvtstr(size, s1, sizeof(s1));
+ printf("%s\n", s1);
+ return 0;
+}
+
+
+static const cmdinfo_t length_cmd = {
+ .name = "length",
+ .altname = "l",
+ .cfunc = length_f,
+ .oneline = "gets the length of the current file",
+};
+
+
+static int info_f(BlockDriverState *bs, int argc, char **argv)
+{
+ BlockDriverInfo bdi;
+ char s1[64], s2[64];
+ int ret;
+
+ if (bs->drv && bs->drv->format_name) {
+ printf("format name: %s\n", bs->drv->format_name);
+ }
+ if (bs->drv && bs->drv->protocol_name) {
+ printf("format name: %s\n", bs->drv->protocol_name);
+ }
+
+ ret = bdrv_get_info(bs, &bdi);
+ if (ret) {
+ return 0;
+ }
+
+ cvtstr(bdi.cluster_size, s1, sizeof(s1));
+ cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
+
+ printf("cluster size: %s\n", s1);
+ printf("vm state offset: %s\n", s2);
+
+ return 0;
+}
+
+
+
+static const cmdinfo_t info_cmd = {
+ .name = "info",
+ .altname = "i",
+ .cfunc = info_f,
+ .oneline = "prints information about the current file",
+};
+
+static void discard_help(void)
+{
+ printf(
+"\n"
+" discards a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
+"\n"
+" Discards a segment of the currently open file.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+"\n");
+}
+
+static int discard_f(BlockDriverState *bs, int argc, char **argv);
+
+static const cmdinfo_t discard_cmd = {
+ .name = "discard",
+ .altname = "d",
+ .cfunc = discard_f,
+ .argmin = 2,
+ .argmax = -1,
+ .args = "[-Cq] off len",
+ .oneline = "discards a number of bytes at a specified offset",
+ .help = discard_help,
+};
+
+static int discard_f(BlockDriverState *bs, int argc, char **argv)
+{
+ struct timeval t1, t2;
+ int Cflag = 0, qflag = 0;
+ int c, ret;
+ int64_t offset;
+ int count;
+
+ while ((c = getopt(argc, argv, "Cq")) != EOF) {
+ switch (c) {
+ case 'C':
+ Cflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ default:
+ return command_usage(&discard_cmd);
+ }
+ }
+
+ if (optind != argc - 2) {
+ return command_usage(&discard_cmd);
+ }
+
+ offset = cvtnum(argv[optind]);
+ if (offset < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ optind++;
+ count = cvtnum(argv[optind]);
+ if (count < 0) {
+ printf("non-numeric length argument -- %s\n", argv[optind]);
+ return 0;
+ }
+
+ gettimeofday(&t1, NULL);
+ ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
+ count >> BDRV_SECTOR_BITS);
+ gettimeofday(&t2, NULL);
+
+ if (ret < 0) {
+ printf("discard failed: %s\n", strerror(-ret));
+ goto out;
+ }
+
+ /* Finally, report back -- -C gives a parsable format */
+ if (!qflag) {
+ t2 = tsub(t2, t1);
+ print_report("discard", &t2, offset, count, count, 1, Cflag);
+ }
+
+out:
+ return 0;
+}
+
+static int alloc_f(BlockDriverState *bs, int argc, char **argv)
+{
+ int64_t offset, sector_num;
+ int nb_sectors, remaining;
+ char s1[64];
+ int num, sum_alloc;
+ int ret;
+
+ offset = cvtnum(argv[1]);
+ if (offset < 0) {
+ printf("non-numeric offset argument -- %s\n", argv[1]);
+ return 0;
+ } else if (offset & 0x1ff) {
+ printf("offset %" PRId64 " is not sector aligned\n",
+ offset);
+ return 0;
+ }
+
+ if (argc == 3) {
+ nb_sectors = cvtnum(argv[2]);
+ if (nb_sectors < 0) {
+ printf("non-numeric length argument -- %s\n", argv[2]);
+ return 0;
+ }
+ } else {
+ nb_sectors = 1;
+ }
+
+ remaining = nb_sectors;
+ sum_alloc = 0;
+ sector_num = offset >> 9;
+ while (remaining) {
+ ret = bdrv_is_allocated(bs, sector_num, remaining, &num);
+ sector_num += num;
+ remaining -= num;
+ if (ret) {
+ sum_alloc += num;
+ }
+ if (num == 0) {
+ nb_sectors -= remaining;
+ remaining = 0;
+ }
+ }
+
+ cvtstr(offset, s1, sizeof(s1));
+
+ printf("%d/%d sectors allocated at offset %s\n",
+ sum_alloc, nb_sectors, s1);
+ return 0;
+}
+
+static const cmdinfo_t alloc_cmd = {
+ .name = "alloc",
+ .altname = "a",
+ .argmin = 1,
+ .argmax = 2,
+ .cfunc = alloc_f,
+ .args = "off [sectors]",
+ .oneline = "checks if a sector is present in the file",
+};
+
+
+static int map_is_allocated(BlockDriverState *bs, int64_t sector_num,
+ int64_t nb_sectors, int64_t *pnum)
+{
+ int num, num_checked;
+ int ret, firstret;
+
+ num_checked = MIN(nb_sectors, INT_MAX);
+ ret = bdrv_is_allocated(bs, sector_num, num_checked, &num);
+ if (ret < 0) {
+ return ret;
+ }
+
+ firstret = ret;
+ *pnum = num;
+
+ while (nb_sectors > 0 && ret == firstret) {
+ sector_num += num;
+ nb_sectors -= num;
+
+ num_checked = MIN(nb_sectors, INT_MAX);
+ ret = bdrv_is_allocated(bs, sector_num, num_checked, &num);
+ if (ret == firstret) {
+ *pnum += num;
+ } else {
+ break;
+ }
+ }
+
+ return firstret;
+}
+
+static int map_f(BlockDriverState *bs, int argc, char **argv)
+{
+ int64_t offset;
+ int64_t nb_sectors;
+ char s1[64];
+ int64_t num;
+ int ret;
+ const char *retstr;
+
+ offset = 0;
+ nb_sectors = bs->total_sectors;
+
+ do {
+ ret = map_is_allocated(bs, offset, nb_sectors, &num);
+ if (ret < 0) {
+ error_report("Failed to get allocation status: %s", strerror(-ret));
+ return 0;
+ }
+
+ retstr = ret ? " allocated" : "not allocated";
+ cvtstr(offset << 9ULL, s1, sizeof(s1));
+ printf("[% 24" PRId64 "] % 8" PRId64 "/% 8" PRId64 " sectors %s "
+ "at offset %s (%d)\n",
+ offset << 9ULL, num, nb_sectors, retstr, s1, ret);
+
+ offset += num;
+ nb_sectors -= num;
+ } while (offset < bs->total_sectors);
+
+ return 0;
+}
+
+static const cmdinfo_t map_cmd = {
+ .name = "map",
+ .argmin = 0,
+ .argmax = 0,
+ .cfunc = map_f,
+ .args = "",
+ .oneline = "prints the allocated areas of a file",
+};
+
+static int break_f(BlockDriverState *bs, int argc, char **argv)
+{
+ int ret;
+
+ ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]);
+ if (ret < 0) {
+ printf("Could not set breakpoint: %s\n", strerror(-ret));
+ }
+
+ return 0;
+}
+
+static const cmdinfo_t break_cmd = {
+ .name = "break",
+ .argmin = 2,
+ .argmax = 2,
+ .cfunc = break_f,
+ .args = "event tag",
+ .oneline = "sets a breakpoint on event and tags the stopped "
+ "request as tag",
+};
+
+static int resume_f(BlockDriverState *bs, int argc, char **argv)
+{
+ int ret;
+
+ ret = bdrv_debug_resume(bs, argv[1]);
+ if (ret < 0) {
+ printf("Could not resume request: %s\n", strerror(-ret));
+ }
+
+ return 0;
+}
+
+static const cmdinfo_t resume_cmd = {
+ .name = "resume",
+ .argmin = 1,
+ .argmax = 1,
+ .cfunc = resume_f,
+ .args = "tag",
+ .oneline = "resumes the request tagged as tag",
+};
+
+static int wait_break_f(BlockDriverState *bs, int argc, char **argv)
+{
+ while (!bdrv_debug_is_suspended(bs, argv[1])) {
+ qemu_aio_wait();
+ }
+
+ return 0;
+}
+
+static const cmdinfo_t wait_break_cmd = {
+ .name = "wait_break",
+ .argmin = 1,
+ .argmax = 1,
+ .cfunc = wait_break_f,
+ .args = "tag",
+ .oneline = "waits for the suspension of a request",
+};
+
+static int abort_f(BlockDriverState *bs, int argc, char **argv)
+{
+ abort();
+}
+
+static const cmdinfo_t abort_cmd = {
+ .name = "abort",
+ .cfunc = abort_f,
+ .flags = CMD_NOFILE_OK,
+ .oneline = "simulate a program crash using abort(3)",
+};
+
+static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
+{
+ if (ct->flags & CMD_FLAG_GLOBAL) {
+ return 1;
+ }
+ if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+ fprintf(stderr, "no file open, try 'help open'\n");
+ return 0;
+ }
+ return 1;
+}
+
+static void __attribute((constructor)) init_qemuio_commands(void)
+{
+ /* initialize commands */
+ help_init();
+ add_command(&read_cmd);
+ add_command(&readv_cmd);
+ add_command(&write_cmd);
+ add_command(&writev_cmd);
+ add_command(&multiwrite_cmd);
+ add_command(&aio_read_cmd);
+ add_command(&aio_write_cmd);
+ add_command(&aio_flush_cmd);
+ add_command(&flush_cmd);
+ add_command(&truncate_cmd);
+ add_command(&length_cmd);
+ add_command(&info_cmd);
+ add_command(&discard_cmd);
+ add_command(&alloc_cmd);
+ add_command(&map_cmd);
+ add_command(&break_cmd);
+ add_command(&resume_cmd);
+ add_command(&wait_break_cmd);
+ add_command(&abort_cmd);
+
+ add_check_command(init_check_command);
+}
diff --git a/qemu-io.c b/qemu-io.c
index 39d7063..14eef2c 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -27,1786 +27,7 @@
char *progname;
BlockDriverState *qemuio_bs;
-static int misalign;
-
-static int64_t cvtnum(const char *s)
-{
- char *end;
- return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B);
-}
-
-/*
- * Parse the pattern argument to various sub-commands.
- *
- * Because the pattern is used as an argument to memset it must evaluate
- * to an unsigned integer that fits into a single byte.
- */
-static int parse_pattern(const char *arg)
-{
- char *endptr = NULL;
- long pattern;
-
- pattern = strtol(arg, &endptr, 0);
- if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
- printf("%s is not a valid pattern byte\n", arg);
- return -1;
- }
-
- return pattern;
-}
-
-/*
- * Memory allocation helpers.
- *
- * Make sure memory is aligned by default, or purposefully misaligned if
- * that is specified on the command line.
- */
-
-#define MISALIGN_OFFSET 16
-static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern)
-{
- void *buf;
-
- if (misalign) {
- len += MISALIGN_OFFSET;
- }
- buf = qemu_blockalign(bs, len);
- memset(buf, pattern, len);
- if (misalign) {
- buf += MISALIGN_OFFSET;
- }
- return buf;
-}
-
-static void qemu_io_free(void *p)
-{
- if (misalign) {
- p -= MISALIGN_OFFSET;
- }
- qemu_vfree(p);
-}
-
-static void dump_buffer(const void *buffer, int64_t offset, int len)
-{
- int i, j;
- const uint8_t *p;
-
- for (i = 0, p = buffer; i < len; i += 16) {
- const uint8_t *s = p;
-
- printf("%08" PRIx64 ": ", offset + i);
- for (j = 0; j < 16 && i + j < len; j++, p++) {
- printf("%02x ", *p);
- }
- printf(" ");
- for (j = 0; j < 16 && i + j < len; j++, s++) {
- if (isalnum(*s)) {
- printf("%c", *s);
- } else {
- printf(".");
- }
- }
- printf("\n");
- }
-}
-
-static void print_report(const char *op, struct timeval *t, int64_t offset,
- int count, int total, int cnt, int Cflag)
-{
- char s1[64], s2[64], ts[64];
-
- timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
- if (!Cflag) {
- cvtstr((double)total, s1, sizeof(s1));
- cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
- printf("%s %d/%d bytes at offset %" PRId64 "\n",
- op, total, count, offset);
- printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
- s1, cnt, ts, s2, tdiv((double)cnt, *t));
- } else {/* bytes,ops,time,bytes/sec,ops/sec */
- printf("%d,%d,%s,%.3f,%.3f\n",
- total, cnt, ts,
- tdiv((double)total, *t),
- tdiv((double)cnt, *t));
- }
-}
-
-/*
- * Parse multiple length statements for vectored I/O, and construct an I/O
- * vector matching it.
- */
-static void *
-create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov,
- int pattern)
-{
- size_t *sizes = g_new0(size_t, nr_iov);
- size_t count = 0;
- void *buf = NULL;
- void *p;
- int i;
-
- for (i = 0; i < nr_iov; i++) {
- char *arg = argv[i];
- int64_t len;
-
- len = cvtnum(arg);
- if (len < 0) {
- printf("non-numeric length argument -- %s\n", arg);
- goto fail;
- }
-
- /* should be SIZE_T_MAX, but that doesn't exist */
- if (len > INT_MAX) {
- printf("too large length argument -- %s\n", arg);
- goto fail;
- }
-
- if (len & 0x1ff) {
- printf("length argument %" PRId64
- " is not sector aligned\n", len);
- goto fail;
- }
-
- sizes[i] = len;
- count += len;
- }
-
- qemu_iovec_init(qiov, nr_iov);
-
- buf = p = qemu_io_alloc(bs, count, pattern);
-
- for (i = 0; i < nr_iov; i++) {
- qemu_iovec_add(qiov, p, sizes[i]);
- p += sizes[i];
- }
-
-fail:
- g_free(sizes);
- return buf;
-}
-
-static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count,
- int *total)
-{
- int ret;
-
- ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
- if (ret < 0) {
- return ret;
- }
- *total = count;
- return 1;
-}
-
-static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count,
- int *total)
-{
- int ret;
-
- ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
- if (ret < 0) {
- return ret;
- }
- *total = count;
- return 1;
-}
-
-static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count,
- int *total)
-{
- *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
- if (*total < 0) {
- return *total;
- }
- return 1;
-}
-
-static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count,
- int *total)
-{
- *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
- if (*total < 0) {
- return *total;
- }
- return 1;
-}
-
-typedef struct {
- BlockDriverState *bs;
- int64_t offset;
- int count;
- int *total;
- int ret;
- bool done;
-} CoWriteZeroes;
-
-static void coroutine_fn co_write_zeroes_entry(void *opaque)
-{
- CoWriteZeroes *data = opaque;
-
- data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE,
- data->count / BDRV_SECTOR_SIZE);
- data->done = true;
- if (data->ret < 0) {
- *data->total = data->ret;
- return;
- }
-
- *data->total = data->count;
-}
-
-static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count,
- int *total)
-{
- Coroutine *co;
- CoWriteZeroes data = {
- .bs = bs,
- .offset = offset,
- .count = count,
- .total = total,
- .done = false,
- };
-
- co = qemu_coroutine_create(co_write_zeroes_entry);
- qemu_coroutine_enter(co, &data);
- while (!data.done) {
- qemu_aio_wait();
- }
- if (data.ret < 0) {
- return data.ret;
- } else {
- return 1;
- }
-}
-
-static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset,
- int count, int *total)
-{
- int ret;
-
- ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9);
- if (ret < 0) {
- return ret;
- }
- *total = count;
- return 1;
-}
-
-static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
- int count, int *total)
-{
- *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
- if (*total < 0) {
- return *total;
- }
- return 1;
-}
-
-static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
- int count, int *total)
-{
- *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
- if (*total < 0) {
- return *total;
- }
- return 1;
-}
-
-#define NOT_DONE 0x7fffffff
-static void aio_rw_done(void *opaque, int ret)
-{
- *(int *)opaque = ret;
-}
-
-static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov,
- int64_t offset, int *total)
-{
- int async_ret = NOT_DONE;
-
- bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
- aio_rw_done, &async_ret);
- while (async_ret == NOT_DONE) {
- main_loop_wait(false);
- }
-
- *total = qiov->size;
- return async_ret < 0 ? async_ret : 1;
-}
-
-static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov,
- int64_t offset, int *total)
-{
- int async_ret = NOT_DONE;
-
- bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
- aio_rw_done, &async_ret);
- while (async_ret == NOT_DONE) {
- main_loop_wait(false);
- }
-
- *total = qiov->size;
- return async_ret < 0 ? async_ret : 1;
-}
-
-struct multiwrite_async_ret {
- int num_done;
- int error;
-};
-
-static void multiwrite_cb(void *opaque, int ret)
-{
- struct multiwrite_async_ret *async_ret = opaque;
-
- async_ret->num_done++;
- if (ret < 0) {
- async_ret->error = ret;
- }
-}
-
-static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs,
- int num_reqs, int *total)
-{
- int i, ret;
- struct multiwrite_async_ret async_ret = {
- .num_done = 0,
- .error = 0,
- };
-
- *total = 0;
- for (i = 0; i < num_reqs; i++) {
- reqs[i].cb = multiwrite_cb;
- reqs[i].opaque = &async_ret;
- *total += reqs[i].qiov->size;
- }
-
- ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
- if (ret < 0) {
- return ret;
- }
-
- while (async_ret.num_done < num_reqs) {
- main_loop_wait(false);
- }
-
- return async_ret.error < 0 ? async_ret.error : 1;
-}
-
-static void read_help(void)
-{
- printf(
-"\n"
-" reads a range of bytes from the given offset\n"
-"\n"
-" Example:\n"
-" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
-"\n"
-" Reads a segment of the currently open file, optionally dumping it to the\n"
-" standard output stream (with -v option) for subsequent inspection.\n"
-" -b, -- read from the VM state rather than the virtual disk\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -l, -- length for pattern verification (only with -P)\n"
-" -p, -- use bdrv_pread to read the file\n"
-" -P, -- use a pattern to verify read data\n"
-" -q, -- quiet mode, do not show I/O statistics\n"
-" -s, -- start offset for pattern verification (only with -P)\n"
-" -v, -- dump buffer to standard output\n"
-"\n");
-}
-
-static int read_f(BlockDriverState *bs, int argc, char **argv);
-
-static const cmdinfo_t read_cmd = {
- .name = "read",
- .altname = "r",
- .cfunc = read_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
- .oneline = "reads a number of bytes at a specified offset",
- .help = read_help,
-};
-
-static int read_f(BlockDriverState *bs, int argc, char **argv)
-{
- struct timeval t1, t2;
- int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
- int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
- int c, cnt;
- char *buf;
- int64_t offset;
- int count;
- /* Some compilers get confused and warn if this is not initialized. */
- int total = 0;
- int pattern = 0, pattern_offset = 0, pattern_count = 0;
-
- while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
- switch (c) {
- case 'b':
- bflag = 1;
- break;
- case 'C':
- Cflag = 1;
- break;
- case 'l':
- lflag = 1;
- pattern_count = cvtnum(optarg);
- if (pattern_count < 0) {
- printf("non-numeric length argument -- %s\n", optarg);
- return 0;
- }
- break;
- case 'p':
- pflag = 1;
- break;
- case 'P':
- Pflag = 1;
- pattern = parse_pattern(optarg);
- if (pattern < 0) {
- return 0;
- }
- break;
- case 'q':
- qflag = 1;
- break;
- case 's':
- sflag = 1;
- pattern_offset = cvtnum(optarg);
- if (pattern_offset < 0) {
- printf("non-numeric length argument -- %s\n", optarg);
- return 0;
- }
- break;
- case 'v':
- vflag = 1;
- break;
- default:
- return command_usage(&read_cmd);
- }
- }
-
- if (optind != argc - 2) {
- return command_usage(&read_cmd);
- }
-
- if (bflag && pflag) {
- printf("-b and -p cannot be specified at the same time\n");
- return 0;
- }
-
- offset = cvtnum(argv[optind]);
- if (offset < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- return 0;
- }
-
- optind++;
- count = cvtnum(argv[optind]);
- if (count < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- return 0;
- }
-
- if (!Pflag && (lflag || sflag)) {
- return command_usage(&read_cmd);
- }
-
- if (!lflag) {
- pattern_count = count - pattern_offset;
- }
-
- if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) {
- printf("pattern verification range exceeds end of read data\n");
- return 0;
- }
-
- if (!pflag) {
- if (offset & 0x1ff) {
- printf("offset %" PRId64 " is not sector aligned\n",
- offset);
- return 0;
- }
- if (count & 0x1ff) {
- printf("count %d is not sector aligned\n",
- count);
- return 0;
- }
- }
-
- buf = qemu_io_alloc(bs, count, 0xab);
-
- gettimeofday(&t1, NULL);
- if (pflag) {
- cnt = do_pread(bs, buf, offset, count, &total);
- } else if (bflag) {
- cnt = do_load_vmstate(bs, buf, offset, count, &total);
- } else {
- cnt = do_read(bs, buf, offset, count, &total);
- }
- gettimeofday(&t2, NULL);
-
- if (cnt < 0) {
- printf("read failed: %s\n", strerror(-cnt));
- goto out;
- }
-
- if (Pflag) {
- void *cmp_buf = g_malloc(pattern_count);
- memset(cmp_buf, pattern, pattern_count);
- if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
- printf("Pattern verification failed at offset %"
- PRId64 ", %d bytes\n",
- offset + pattern_offset, pattern_count);
- }
- g_free(cmp_buf);
- }
-
- if (qflag) {
- goto out;
- }
-
- if (vflag) {
- dump_buffer(buf, offset, count);
- }
-
- /* Finally, report back -- -C gives a parsable format */
- t2 = tsub(t2, t1);
- print_report("read", &t2, offset, count, total, cnt, Cflag);
-
-out:
- qemu_io_free(buf);
-
- return 0;
-}
-
-static void readv_help(void)
-{
- printf(
-"\n"
-" reads a range of bytes from the given offset into multiple buffers\n"
-"\n"
-" Example:\n"
-" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
-"\n"
-" Reads a segment of the currently open file, optionally dumping it to the\n"
-" standard output stream (with -v option) for subsequent inspection.\n"
-" Uses multiple iovec buffers if more than one byte range is specified.\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -P, -- use a pattern to verify read data\n"
-" -v, -- dump buffer to standard output\n"
-" -q, -- quiet mode, do not show I/O statistics\n"
-"\n");
-}
-
-static int readv_f(BlockDriverState *bs, int argc, char **argv);
-
-static const cmdinfo_t readv_cmd = {
- .name = "readv",
- .cfunc = readv_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cqv] [-P pattern ] off len [len..]",
- .oneline = "reads a number of bytes at a specified offset",
- .help = readv_help,
-};
-
-static int readv_f(BlockDriverState *bs, int argc, char **argv)
-{
- struct timeval t1, t2;
- int Cflag = 0, qflag = 0, vflag = 0;
- int c, cnt;
- char *buf;
- int64_t offset;
- /* Some compilers get confused and warn if this is not initialized. */
- int total = 0;
- int nr_iov;
- QEMUIOVector qiov;
- int pattern = 0;
- int Pflag = 0;
-
- while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
- switch (c) {
- case 'C':
- Cflag = 1;
- break;
- case 'P':
- Pflag = 1;
- pattern = parse_pattern(optarg);
- if (pattern < 0) {
- return 0;
- }
- break;
- case 'q':
- qflag = 1;
- break;
- case 'v':
- vflag = 1;
- break;
- default:
- return command_usage(&readv_cmd);
- }
- }
-
- if (optind > argc - 2) {
- return command_usage(&readv_cmd);
- }
-
-
- offset = cvtnum(argv[optind]);
- if (offset < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- return 0;
- }
- optind++;
-
- if (offset & 0x1ff) {
- printf("offset %" PRId64 " is not sector aligned\n",
- offset);
- return 0;
- }
-
- nr_iov = argc - optind;
- buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab);
- if (buf == NULL) {
- return 0;
- }
-
- gettimeofday(&t1, NULL);
- cnt = do_aio_readv(bs, &qiov, offset, &total);
- gettimeofday(&t2, NULL);
-
- if (cnt < 0) {
- printf("readv failed: %s\n", strerror(-cnt));
- goto out;
- }
-
- if (Pflag) {
- void *cmp_buf = g_malloc(qiov.size);
- memset(cmp_buf, pattern, qiov.size);
- if (memcmp(buf, cmp_buf, qiov.size)) {
- printf("Pattern verification failed at offset %"
- PRId64 ", %zd bytes\n", offset, qiov.size);
- }
- g_free(cmp_buf);
- }
-
- if (qflag) {
- goto out;
- }
-
- if (vflag) {
- dump_buffer(buf, offset, qiov.size);
- }
-
- /* Finally, report back -- -C gives a parsable format */
- t2 = tsub(t2, t1);
- print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
-
-out:
- qemu_iovec_destroy(&qiov);
- qemu_io_free(buf);
- return 0;
-}
-
-static void write_help(void)
-{
- printf(
-"\n"
-" writes a range of bytes from the given offset\n"
-"\n"
-" Example:\n"
-" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
-"\n"
-" Writes into a segment of the currently open file, using a buffer\n"
-" filled with a set pattern (0xcdcdcdcd).\n"
-" -b, -- write to the VM state rather than the virtual disk\n"
-" -c, -- write compressed data with bdrv_write_compressed\n"
-" -p, -- use bdrv_pwrite to write the file\n"
-" -P, -- use different pattern to fill file\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -q, -- quiet mode, do not show I/O statistics\n"
-" -z, -- write zeroes using bdrv_co_write_zeroes\n"
-"\n");
-}
-
-static int write_f(BlockDriverState *bs, int argc, char **argv);
-
-static const cmdinfo_t write_cmd = {
- .name = "write",
- .altname = "w",
- .cfunc = write_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-bcCpqz] [-P pattern ] off len",
- .oneline = "writes a number of bytes at a specified offset",
- .help = write_help,
-};
-
-static int write_f(BlockDriverState *bs, int argc, char **argv)
-{
- struct timeval t1, t2;
- int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
- int cflag = 0;
- int c, cnt;
- char *buf = NULL;
- int64_t offset;
- int count;
- /* Some compilers get confused and warn if this is not initialized. */
- int total = 0;
- int pattern = 0xcd;
-
- while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) {
- switch (c) {
- case 'b':
- bflag = 1;
- break;
- case 'c':
- cflag = 1;
- break;
- case 'C':
- Cflag = 1;
- break;
- case 'p':
- pflag = 1;
- break;
- case 'P':
- Pflag = 1;
- pattern = parse_pattern(optarg);
- if (pattern < 0) {
- return 0;
- }
- break;
- case 'q':
- qflag = 1;
- break;
- case 'z':
- zflag = 1;
- break;
- default:
- return command_usage(&write_cmd);
- }
- }
-
- if (optind != argc - 2) {
- return command_usage(&write_cmd);
- }
-
- if (bflag + pflag + zflag > 1) {
- printf("-b, -p, or -z cannot be specified at the same time\n");
- return 0;
- }
-
- if (zflag && Pflag) {
- printf("-z and -P cannot be specified at the same time\n");
- return 0;
- }
-
- offset = cvtnum(argv[optind]);
- if (offset < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- return 0;
- }
-
- optind++;
- count = cvtnum(argv[optind]);
- if (count < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- return 0;
- }
-
- if (!pflag) {
- if (offset & 0x1ff) {
- printf("offset %" PRId64 " is not sector aligned\n",
- offset);
- return 0;
- }
-
- if (count & 0x1ff) {
- printf("count %d is not sector aligned\n",
- count);
- return 0;
- }
- }
-
- if (!zflag) {
- buf = qemu_io_alloc(bs, count, pattern);
- }
-
- gettimeofday(&t1, NULL);
- if (pflag) {
- cnt = do_pwrite(bs, buf, offset, count, &total);
- } else if (bflag) {
- cnt = do_save_vmstate(bs, buf, offset, count, &total);
- } else if (zflag) {
- cnt = do_co_write_zeroes(bs, offset, count, &total);
- } else if (cflag) {
- cnt = do_write_compressed(bs, buf, offset, count, &total);
- } else {
- cnt = do_write(bs, buf, offset, count, &total);
- }
- gettimeofday(&t2, NULL);
-
- if (cnt < 0) {
- printf("write failed: %s\n", strerror(-cnt));
- goto out;
- }
-
- if (qflag) {
- goto out;
- }
-
- /* Finally, report back -- -C gives a parsable format */
- t2 = tsub(t2, t1);
- print_report("wrote", &t2, offset, count, total, cnt, Cflag);
-
-out:
- if (!zflag) {
- qemu_io_free(buf);
- }
-
- return 0;
-}
-
-static void
-writev_help(void)
-{
- printf(
-"\n"
-" writes a range of bytes from the given offset source from multiple buffers\n"
-"\n"
-" Example:\n"
-" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
-"\n"
-" Writes into a segment of the currently open file, using a buffer\n"
-" filled with a set pattern (0xcdcdcdcd).\n"
-" -P, -- use different pattern to fill file\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -q, -- quiet mode, do not show I/O statistics\n"
-"\n");
-}
-
-static int writev_f(BlockDriverState *bs, int argc, char **argv);
-
-static const cmdinfo_t writev_cmd = {
- .name = "writev",
- .cfunc = writev_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cq] [-P pattern ] off len [len..]",
- .oneline = "writes a number of bytes at a specified offset",
- .help = writev_help,
-};
-
-static int writev_f(BlockDriverState *bs, int argc, char **argv)
-{
- struct timeval t1, t2;
- int Cflag = 0, qflag = 0;
- int c, cnt;
- char *buf;
- int64_t offset;
- /* Some compilers get confused and warn if this is not initialized. */
- int total = 0;
- int nr_iov;
- int pattern = 0xcd;
- QEMUIOVector qiov;
-
- while ((c = getopt(argc, argv, "CqP:")) != EOF) {
- switch (c) {
- case 'C':
- Cflag = 1;
- break;
- case 'q':
- qflag = 1;
- break;
- case 'P':
- pattern = parse_pattern(optarg);
- if (pattern < 0) {
- return 0;
- }
- break;
- default:
- return command_usage(&writev_cmd);
- }
- }
-
- if (optind > argc - 2) {
- return command_usage(&writev_cmd);
- }
-
- offset = cvtnum(argv[optind]);
- if (offset < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- return 0;
- }
- optind++;
-
- if (offset & 0x1ff) {
- printf("offset %" PRId64 " is not sector aligned\n",
- offset);
- return 0;
- }
-
- nr_iov = argc - optind;
- buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern);
- if (buf == NULL) {
- return 0;
- }
-
- gettimeofday(&t1, NULL);
- cnt = do_aio_writev(bs, &qiov, offset, &total);
- gettimeofday(&t2, NULL);
-
- if (cnt < 0) {
- printf("writev failed: %s\n", strerror(-cnt));
- goto out;
- }
-
- if (qflag) {
- goto out;
- }
-
- /* Finally, report back -- -C gives a parsable format */
- t2 = tsub(t2, t1);
- print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
-out:
- qemu_iovec_destroy(&qiov);
- qemu_io_free(buf);
- return 0;
-}
-
-static void multiwrite_help(void)
-{
- printf(
-"\n"
-" writes a range of bytes from the given offset source from multiple buffers,\n"
-" in a batch of requests that may be merged by qemu\n"
-"\n"
-" Example:\n"
-" 'multiwrite 512 1k 1k ; 4k 1k'\n"
-" writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
-"\n"
-" Writes into a segment of the currently open file, using a buffer\n"
-" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
-" by one for each request contained in the multiwrite command.\n"
-" -P, -- use different pattern to fill file\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -q, -- quiet mode, do not show I/O statistics\n"
-"\n");
-}
-
-static int multiwrite_f(BlockDriverState *bs, int argc, char **argv);
-
-static const cmdinfo_t multiwrite_cmd = {
- .name = "multiwrite",
- .cfunc = multiwrite_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
- .oneline = "issues multiple write requests at once",
- .help = multiwrite_help,
-};
-
-static int multiwrite_f(BlockDriverState *bs, int argc, char **argv)
-{
- struct timeval t1, t2;
- int Cflag = 0, qflag = 0;
- int c, cnt;
- char **buf;
- int64_t offset, first_offset = 0;
- /* Some compilers get confused and warn if this is not initialized. */
- int total = 0;
- int nr_iov;
- int nr_reqs;
- int pattern = 0xcd;
- QEMUIOVector *qiovs;
- int i;
- BlockRequest *reqs;
-
- while ((c = getopt(argc, argv, "CqP:")) != EOF) {
- switch (c) {
- case 'C':
- Cflag = 1;
- break;
- case 'q':
- qflag = 1;
- break;
- case 'P':
- pattern = parse_pattern(optarg);
- if (pattern < 0) {
- return 0;
- }
- break;
- default:
- return command_usage(&writev_cmd);
- }
- }
-
- if (optind > argc - 2) {
- return command_usage(&writev_cmd);
- }
-
- nr_reqs = 1;
- for (i = optind; i < argc; i++) {
- if (!strcmp(argv[i], ";")) {
- nr_reqs++;
- }
- }
-
- reqs = g_malloc0(nr_reqs * sizeof(*reqs));
- buf = g_malloc0(nr_reqs * sizeof(*buf));
- qiovs = g_malloc(nr_reqs * sizeof(*qiovs));
-
- for (i = 0; i < nr_reqs && optind < argc; i++) {
- int j;
-
- /* Read the offset of the request */
- offset = cvtnum(argv[optind]);
- if (offset < 0) {
- printf("non-numeric offset argument -- %s\n", argv[optind]);
- goto out;
- }
- optind++;
-
- if (offset & 0x1ff) {
- printf("offset %lld is not sector aligned\n",
- (long long)offset);
- goto out;
- }
-
- if (i == 0) {
- first_offset = offset;
- }
-
- /* Read lengths for qiov entries */
- for (j = optind; j < argc; j++) {
- if (!strcmp(argv[j], ";")) {
- break;
- }
- }
-
- nr_iov = j - optind;
-
- /* Build request */
- buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern);
- if (buf[i] == NULL) {
- goto out;
- }
-
- reqs[i].qiov = &qiovs[i];
- reqs[i].sector = offset >> 9;
- reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
-
- optind = j + 1;
-
- pattern++;
- }
-
- /* If there were empty requests at the end, ignore them */
- nr_reqs = i;
-
- gettimeofday(&t1, NULL);
- cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total);
- gettimeofday(&t2, NULL);
-
- if (cnt < 0) {
- printf("aio_multiwrite failed: %s\n", strerror(-cnt));
- goto out;
- }
-
- if (qflag) {
- goto out;
- }
-
- /* Finally, report back -- -C gives a parsable format */
- t2 = tsub(t2, t1);
- print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
-out:
- for (i = 0; i < nr_reqs; i++) {
- qemu_io_free(buf[i]);
- if (reqs[i].qiov != NULL) {
- qemu_iovec_destroy(&qiovs[i]);
- }
- }
- g_free(buf);
- g_free(reqs);
- g_free(qiovs);
- return 0;
-}
-
-struct aio_ctx {
- QEMUIOVector qiov;
- int64_t offset;
- char *buf;
- int qflag;
- int vflag;
- int Cflag;
- int Pflag;
- int pattern;
- struct timeval t1;
-};
-
-static void aio_write_done(void *opaque, int ret)
-{
- struct aio_ctx *ctx = opaque;
- struct timeval t2;
-
- gettimeofday(&t2, NULL);
-
-
- if (ret < 0) {
- printf("aio_write failed: %s\n", strerror(-ret));
- goto out;
- }
-
- if (ctx->qflag) {
- goto out;
- }
-
- /* Finally, report back -- -C gives a parsable format */
- t2 = tsub(t2, ctx->t1);
- print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
- ctx->qiov.size, 1, ctx->Cflag);
-out:
- qemu_io_free(ctx->buf);
- qemu_iovec_destroy(&ctx->qiov);
- g_free(ctx);
-}
-
-static void aio_read_done(void *opaque, int ret)
-{
- struct aio_ctx *ctx = opaque;
- struct timeval t2;
-
- gettimeofday(&t2, NULL);
-
- if (ret < 0) {
- printf("readv failed: %s\n", strerror(-ret));
- goto out;
- }
-
- if (ctx->Pflag) {
- void *cmp_buf = g_malloc(ctx->qiov.size);
-
- memset(cmp_buf, ctx->pattern, ctx->qiov.size);
- if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
- printf("Pattern verification failed at offset %"
- PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
- }
- g_free(cmp_buf);
- }
-
- if (ctx->qflag) {
- goto out;
- }
-
- if (ctx->vflag) {
- dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
- }
-
- /* Finally, report back -- -C gives a parsable format */
- t2 = tsub(t2, ctx->t1);
- print_report("read", &t2, ctx->offset, ctx->qiov.size,
- ctx->qiov.size, 1, ctx->Cflag);
-out:
- qemu_io_free(ctx->buf);
- qemu_iovec_destroy(&ctx->qiov);
- g_free(ctx);
-}
-
-static void aio_read_help(void)
-{
- printf(
-"\n"
-" asynchronously reads a range of bytes from the given offset\n"
-"\n"
-" Example:\n"
-" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
-"\n"
-" Reads a segment of the currently open file, optionally dumping it to the\n"
-" standard output stream (with -v option) for subsequent inspection.\n"
-" The read is performed asynchronously and the aio_flush command must be\n"
-" used to ensure all outstanding aio requests have been completed.\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -P, -- use a pattern to verify read data\n"
-" -v, -- dump buffer to standard output\n"
-" -q, -- quiet mode, do not show I/O statistics\n"
-"\n");
-}
-
-static int aio_read_f(BlockDriverState *bs, int argc, char **argv);
-
-static const cmdinfo_t aio_read_cmd = {
- .name = "aio_read",
- .cfunc = aio_read_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cqv] [-P pattern ] off len [len..]",
- .oneline = "asynchronously reads a number of bytes",
- .help = aio_read_help,
-};
-
-static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
-{
- int nr_iov, c;
- struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
-
- while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
- switch (c) {
- case 'C':
- ctx->Cflag = 1;
- break;
- case 'P':
- ctx->Pflag = 1;
- ctx->pattern = parse_pattern(optarg);
- if (ctx->pattern < 0) {
- g_free(ctx);
- return 0;
- }
- break;
- case 'q':
- ctx->qflag = 1;
- break;
- case 'v':
- ctx->vflag = 1;
- break;
- default:
- g_free(ctx);
- return command_usage(&aio_read_cmd);
- }
- }
-
- if (optind > argc - 2) {
- g_free(ctx);
- return command_usage(&aio_read_cmd);
- }
-
- ctx->offset = cvtnum(argv[optind]);
- if (ctx->offset < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- g_free(ctx);
- return 0;
- }
- optind++;
-
- if (ctx->offset & 0x1ff) {
- printf("offset %" PRId64 " is not sector aligned\n",
- ctx->offset);
- g_free(ctx);
- return 0;
- }
-
- nr_iov = argc - optind;
- ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab);
- if (ctx->buf == NULL) {
- g_free(ctx);
- return 0;
- }
-
- gettimeofday(&ctx->t1, NULL);
- bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
- ctx->qiov.size >> 9, aio_read_done, ctx);
- return 0;
-}
-
-static void aio_write_help(void)
-{
- printf(
-"\n"
-" asynchronously writes a range of bytes from the given offset source\n"
-" from multiple buffers\n"
-"\n"
-" Example:\n"
-" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
-"\n"
-" Writes into a segment of the currently open file, using a buffer\n"
-" filled with a set pattern (0xcdcdcdcd).\n"
-" The write is performed asynchronously and the aio_flush command must be\n"
-" used to ensure all outstanding aio requests have been completed.\n"
-" -P, -- use different pattern to fill file\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -q, -- quiet mode, do not show I/O statistics\n"
-"\n");
-}
-
-static int aio_write_f(BlockDriverState *bs, int argc, char **argv);
-
-static const cmdinfo_t aio_write_cmd = {
- .name = "aio_write",
- .cfunc = aio_write_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cq] [-P pattern ] off len [len..]",
- .oneline = "asynchronously writes a number of bytes",
- .help = aio_write_help,
-};
-
-static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
-{
- int nr_iov, c;
- int pattern = 0xcd;
- struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
-
- while ((c = getopt(argc, argv, "CqP:")) != EOF) {
- switch (c) {
- case 'C':
- ctx->Cflag = 1;
- break;
- case 'q':
- ctx->qflag = 1;
- break;
- case 'P':
- pattern = parse_pattern(optarg);
- if (pattern < 0) {
- g_free(ctx);
- return 0;
- }
- break;
- default:
- g_free(ctx);
- return command_usage(&aio_write_cmd);
- }
- }
-
- if (optind > argc - 2) {
- g_free(ctx);
- return command_usage(&aio_write_cmd);
- }
-
- ctx->offset = cvtnum(argv[optind]);
- if (ctx->offset < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- g_free(ctx);
- return 0;
- }
- optind++;
-
- if (ctx->offset & 0x1ff) {
- printf("offset %" PRId64 " is not sector aligned\n",
- ctx->offset);
- g_free(ctx);
- return 0;
- }
-
- nr_iov = argc - optind;
- ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern);
- if (ctx->buf == NULL) {
- g_free(ctx);
- return 0;
- }
-
- gettimeofday(&ctx->t1, NULL);
- bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
- ctx->qiov.size >> 9, aio_write_done, ctx);
- return 0;
-}
-
-static int aio_flush_f(BlockDriverState *bs, int argc, char **argv)
-{
- bdrv_drain_all();
- return 0;
-}
-
-static const cmdinfo_t aio_flush_cmd = {
- .name = "aio_flush",
- .cfunc = aio_flush_f,
- .oneline = "completes all outstanding aio requests"
-};
-
-static int flush_f(BlockDriverState *bs, int argc, char **argv)
-{
- bdrv_flush(bs);
- return 0;
-}
-
-static const cmdinfo_t flush_cmd = {
- .name = "flush",
- .altname = "f",
- .cfunc = flush_f,
- .oneline = "flush all in-core file state to disk",
-};
-
-static int truncate_f(BlockDriverState *bs, int argc, char **argv)
-{
- int64_t offset;
- int ret;
-
- offset = cvtnum(argv[1]);
- if (offset < 0) {
- printf("non-numeric truncate argument -- %s\n", argv[1]);
- return 0;
- }
-
- ret = bdrv_truncate(bs, offset);
- if (ret < 0) {
- printf("truncate: %s\n", strerror(-ret));
- return 0;
- }
-
- return 0;
-}
-
-static const cmdinfo_t truncate_cmd = {
- .name = "truncate",
- .altname = "t",
- .cfunc = truncate_f,
- .argmin = 1,
- .argmax = 1,
- .args = "off",
- .oneline = "truncates the current file at the given offset",
-};
-
-static int length_f(BlockDriverState *bs, int argc, char **argv)
-{
- int64_t size;
- char s1[64];
-
- size = bdrv_getlength(bs);
- if (size < 0) {
- printf("getlength: %s\n", strerror(-size));
- return 0;
- }
-
- cvtstr(size, s1, sizeof(s1));
- printf("%s\n", s1);
- return 0;
-}
-
-
-static const cmdinfo_t length_cmd = {
- .name = "length",
- .altname = "l",
- .cfunc = length_f,
- .oneline = "gets the length of the current file",
-};
-
-
-static int info_f(BlockDriverState *bs, int argc, char **argv)
-{
- BlockDriverInfo bdi;
- char s1[64], s2[64];
- int ret;
-
- if (bs->drv && bs->drv->format_name) {
- printf("format name: %s\n", bs->drv->format_name);
- }
- if (bs->drv && bs->drv->protocol_name) {
- printf("format name: %s\n", bs->drv->protocol_name);
- }
-
- ret = bdrv_get_info(bs, &bdi);
- if (ret) {
- return 0;
- }
-
- cvtstr(bdi.cluster_size, s1, sizeof(s1));
- cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
-
- printf("cluster size: %s\n", s1);
- printf("vm state offset: %s\n", s2);
-
- return 0;
-}
-
-
-
-static const cmdinfo_t info_cmd = {
- .name = "info",
- .altname = "i",
- .cfunc = info_f,
- .oneline = "prints information about the current file",
-};
-
-static void discard_help(void)
-{
- printf(
-"\n"
-" discards a range of bytes from the given offset\n"
-"\n"
-" Example:\n"
-" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
-"\n"
-" Discards a segment of the currently open file.\n"
-" -C, -- report statistics in a machine parsable format\n"
-" -q, -- quiet mode, do not show I/O statistics\n"
-"\n");
-}
-
-static int discard_f(BlockDriverState *bs, int argc, char **argv);
-
-static const cmdinfo_t discard_cmd = {
- .name = "discard",
- .altname = "d",
- .cfunc = discard_f,
- .argmin = 2,
- .argmax = -1,
- .args = "[-Cq] off len",
- .oneline = "discards a number of bytes at a specified offset",
- .help = discard_help,
-};
-
-static int discard_f(BlockDriverState *bs, int argc, char **argv)
-{
- struct timeval t1, t2;
- int Cflag = 0, qflag = 0;
- int c, ret;
- int64_t offset;
- int count;
-
- while ((c = getopt(argc, argv, "Cq")) != EOF) {
- switch (c) {
- case 'C':
- Cflag = 1;
- break;
- case 'q':
- qflag = 1;
- break;
- default:
- return command_usage(&discard_cmd);
- }
- }
-
- if (optind != argc - 2) {
- return command_usage(&discard_cmd);
- }
-
- offset = cvtnum(argv[optind]);
- if (offset < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- return 0;
- }
-
- optind++;
- count = cvtnum(argv[optind]);
- if (count < 0) {
- printf("non-numeric length argument -- %s\n", argv[optind]);
- return 0;
- }
-
- gettimeofday(&t1, NULL);
- ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
- count >> BDRV_SECTOR_BITS);
- gettimeofday(&t2, NULL);
-
- if (ret < 0) {
- printf("discard failed: %s\n", strerror(-ret));
- goto out;
- }
-
- /* Finally, report back -- -C gives a parsable format */
- if (!qflag) {
- t2 = tsub(t2, t1);
- print_report("discard", &t2, offset, count, count, 1, Cflag);
- }
-
-out:
- return 0;
-}
-
-static int alloc_f(BlockDriverState *bs, int argc, char **argv)
-{
- int64_t offset, sector_num;
- int nb_sectors, remaining;
- char s1[64];
- int num, sum_alloc;
- int ret;
-
- offset = cvtnum(argv[1]);
- if (offset < 0) {
- printf("non-numeric offset argument -- %s\n", argv[1]);
- return 0;
- } else if (offset & 0x1ff) {
- printf("offset %" PRId64 " is not sector aligned\n",
- offset);
- return 0;
- }
-
- if (argc == 3) {
- nb_sectors = cvtnum(argv[2]);
- if (nb_sectors < 0) {
- printf("non-numeric length argument -- %s\n", argv[2]);
- return 0;
- }
- } else {
- nb_sectors = 1;
- }
-
- remaining = nb_sectors;
- sum_alloc = 0;
- sector_num = offset >> 9;
- while (remaining) {
- ret = bdrv_is_allocated(bs, sector_num, remaining, &num);
- sector_num += num;
- remaining -= num;
- if (ret) {
- sum_alloc += num;
- }
- if (num == 0) {
- nb_sectors -= remaining;
- remaining = 0;
- }
- }
-
- cvtstr(offset, s1, sizeof(s1));
-
- printf("%d/%d sectors allocated at offset %s\n",
- sum_alloc, nb_sectors, s1);
- return 0;
-}
-
-static const cmdinfo_t alloc_cmd = {
- .name = "alloc",
- .altname = "a",
- .argmin = 1,
- .argmax = 2,
- .cfunc = alloc_f,
- .args = "off [sectors]",
- .oneline = "checks if a sector is present in the file",
-};
-
-
-static int map_is_allocated(BlockDriverState *bs, int64_t sector_num,
- int64_t nb_sectors, int64_t *pnum)
-{
- int num, num_checked;
- int ret, firstret;
-
- num_checked = MIN(nb_sectors, INT_MAX);
- ret = bdrv_is_allocated(bs, sector_num, num_checked, &num);
- if (ret < 0) {
- return ret;
- }
-
- firstret = ret;
- *pnum = num;
-
- while (nb_sectors > 0 && ret == firstret) {
- sector_num += num;
- nb_sectors -= num;
-
- num_checked = MIN(nb_sectors, INT_MAX);
- ret = bdrv_is_allocated(bs, sector_num, num_checked, &num);
- if (ret == firstret) {
- *pnum += num;
- } else {
- break;
- }
- }
-
- return firstret;
-}
-
-static int map_f(BlockDriverState *bs, int argc, char **argv)
-{
- int64_t offset;
- int64_t nb_sectors;
- char s1[64];
- int64_t num;
- int ret;
- const char *retstr;
-
- offset = 0;
- nb_sectors = bs->total_sectors;
-
- do {
- ret = map_is_allocated(bs, offset, nb_sectors, &num);
- if (ret < 0) {
- error_report("Failed to get allocation status: %s", strerror(-ret));
- return 0;
- }
-
- retstr = ret ? " allocated" : "not allocated";
- cvtstr(offset << 9ULL, s1, sizeof(s1));
- printf("[% 24" PRId64 "] % 8" PRId64 "/% 8" PRId64 " sectors %s "
- "at offset %s (%d)\n",
- offset << 9ULL, num, nb_sectors, retstr, s1, ret);
-
- offset += num;
- nb_sectors -= num;
- } while (offset < bs->total_sectors);
-
- return 0;
-}
-
-static const cmdinfo_t map_cmd = {
- .name = "map",
- .argmin = 0,
- .argmax = 0,
- .cfunc = map_f,
- .args = "",
- .oneline = "prints the allocated areas of a file",
-};
-
-static int break_f(BlockDriverState *bs, int argc, char **argv)
-{
- int ret;
-
- ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]);
- if (ret < 0) {
- printf("Could not set breakpoint: %s\n", strerror(-ret));
- }
-
- return 0;
-}
-
-static const cmdinfo_t break_cmd = {
- .name = "break",
- .argmin = 2,
- .argmax = 2,
- .cfunc = break_f,
- .args = "event tag",
- .oneline = "sets a breakpoint on event and tags the stopped "
- "request as tag",
-};
-
-static int resume_f(BlockDriverState *bs, int argc, char **argv)
-{
- int ret;
-
- ret = bdrv_debug_resume(bs, argv[1]);
- if (ret < 0) {
- printf("Could not resume request: %s\n", strerror(-ret));
- }
-
- return 0;
-}
-
-static const cmdinfo_t resume_cmd = {
- .name = "resume",
- .argmin = 1,
- .argmax = 1,
- .cfunc = resume_f,
- .args = "tag",
- .oneline = "resumes the request tagged as tag",
-};
-
-static int wait_break_f(BlockDriverState *bs, int argc, char **argv)
-{
- while (!bdrv_debug_is_suspended(bs, argv[1])) {
- qemu_aio_wait();
- }
-
- return 0;
-}
-
-static const cmdinfo_t wait_break_cmd = {
- .name = "wait_break",
- .argmin = 1,
- .argmax = 1,
- .cfunc = wait_break_f,
- .args = "tag",
- .oneline = "waits for the suspension of a request",
-};
-
-static int abort_f(BlockDriverState *bs, int argc, char **argv)
-{
- abort();
-}
-
-static const cmdinfo_t abort_cmd = {
- .name = "abort",
- .cfunc = abort_f,
- .flags = CMD_NOFILE_OK,
- .oneline = "simulate a program crash using abort(3)",
-};
+extern int qemuio_misalign;
static int close_f(BlockDriverState *bs, int argc, char **argv)
{
@@ -1916,18 +137,6 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
return openfile(argv[optind], flags, growable);
}
-static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
-{
- if (ct->flags & CMD_FLAG_GLOBAL) {
- return 1;
- }
- if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
- fprintf(stderr, "no file open, try 'help open'\n");
- return 0;
- }
- return 1;
-}
-
static void usage(const char *name)
{
printf(
@@ -1998,7 +207,7 @@ int main(int argc, char **argv)
readonly = 1;
break;
case 'm':
- misalign = 1;
+ qemuio_misalign = 1;
break;
case 'g':
growable = 1;
@@ -2039,30 +248,8 @@ int main(int argc, char **argv)
/* initialize commands */
quit_init();
- help_init();
add_command(&open_cmd);
add_command(&close_cmd);
- add_command(&read_cmd);
- add_command(&readv_cmd);
- add_command(&write_cmd);
- add_command(&writev_cmd);
- add_command(&multiwrite_cmd);
- add_command(&aio_read_cmd);
- add_command(&aio_write_cmd);
- add_command(&aio_flush_cmd);
- add_command(&flush_cmd);
- add_command(&truncate_cmd);
- add_command(&length_cmd);
- add_command(&info_cmd);
- add_command(&discard_cmd);
- add_command(&alloc_cmd);
- add_command(&map_cmd);
- add_command(&break_cmd);
- add_command(&resume_cmd);
- add_command(&wait_break_cmd);
- add_command(&abort_cmd);
-
- add_check_command(init_check_command);
/* open the device */
if (!readonly) {
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 08/26] qemu-io: Factor out qemuio_command
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (6 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 07/26] qemu-io: Split off commands to qemu-io-cmds.c Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 09/26] qemu-io: Move 'help' function Stefan Hajnoczi
` (18 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
It's duplicated code. Move it to qemu-io-cmds.c because it's not
dependent on any static data of the qemu-io tool.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 43 +++++--------------------------------------
cmd.h | 3 ++-
qemu-io-cmds.c | 24 ++++++++++++++++++++++++
3 files changed, 31 insertions(+), 39 deletions(-)
diff --git a/cmd.c b/cmd.c
index d501aab..7ae978f 100644
--- a/cmd.c
+++ b/cmd.c
@@ -138,28 +138,11 @@ static char *get_prompt(void);
void command_loop(void)
{
- int c, i, done = 0, fetchable = 0, prompted = 0;
+ int i, done = 0, fetchable = 0, prompted = 0;
char *input;
- char **v;
- const cmdinfo_t *ct;
for (i = 0; !done && i < ncmdline; i++) {
- input = strdup(cmdline[i]);
- if (!input) {
- fprintf(stderr, _("cannot strdup command '%s': %s\n"),
- cmdline[i], strerror(errno));
- exit(1);
- }
- v = breakline(input, &c);
- if (c) {
- ct = find_command(v[0]);
- if (ct) {
- done = command(ct, c, v);
- } else {
- fprintf(stderr, _("command \"%s\" not found\n"), v[0]);
- }
- }
- doneline(input, v);
+ done = qemuio_command(cmdline[i]);
}
if (cmdline) {
g_free(cmdline);
@@ -179,20 +162,13 @@ void command_loop(void)
if (!fetchable) {
continue;
}
+
input = fetchline();
if (input == NULL) {
break;
}
- v = breakline(input, &c);
- if (c) {
- ct = find_command(v[0]);
- if (ct) {
- done = command(ct, c, v);
- } else {
- fprintf(stderr, _("command \"%s\" not found\n"), v[0]);
- }
- }
- doneline(input, v);
+ done = qemuio_command(input);
+ free(input);
prompted = 0;
fetchable = 0;
@@ -328,15 +304,6 @@ char **breakline(char *input, int *count)
return rval;
}
-void
-doneline(
- char *input,
- char **vec)
-{
- free(input);
- free(vec);
-}
-
#define EXABYTES(x) ((long long)(x) << 60)
#define PETABYTES(x) ((long long)(x) << 50)
#define TERABYTES(x) ((long long)(x) << 40)
diff --git a/cmd.h b/cmd.h
index ccf6336..d676408 100644
--- a/cmd.h
+++ b/cmd.h
@@ -59,7 +59,6 @@ int command(const cmdinfo_t *ci, int argc, char **argv);
/* from input.h */
char **breakline(char *input, int *count);
-void doneline(char *input, char **vec);
char *fetchline(void);
void cvtstr(double value, char *str, size_t sz);
@@ -77,4 +76,6 @@ void timestr(struct timeval *tv, char *str, size_t sz, int flags);
extern char *progname;
+bool qemuio_command(const char *cmd);
+
#endif /* __COMMAND_H__ */
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 0a3817a..8b12446 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -1807,6 +1807,30 @@ static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
return 1;
}
+bool qemuio_command(const char *cmd)
+{
+ char *input;
+ const cmdinfo_t *ct;
+ char **v;
+ int c;
+ bool done = false;
+
+ input = g_strdup(cmd);
+ v = breakline(input, &c);
+ if (c) {
+ ct = find_command(v[0]);
+ if (ct) {
+ done = command(ct, c, v);
+ } else {
+ fprintf(stderr, "command \"%s\" not found\n", v[0]);
+ }
+ }
+ g_free(input);
+ g_free(v);
+
+ return done;
+}
+
static void __attribute((constructor)) init_qemuio_commands(void)
{
/* initialize commands */
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 09/26] qemu-io: Move 'help' function
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (7 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 08/26] qemu-io: Factor out qemuio_command Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 10/26] qemu-io: Move 'quit' function Stefan Hajnoczi
` (17 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
No reason to treat it different from other commands. Move it to
qemu-io-cmds.c, adapt the coding style and register it like any other
command.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 79 ----------------------------------------------------------
cmd.h | 1 -
qemu-io-cmds.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 66 insertions(+), 81 deletions(-)
diff --git a/cmd.c b/cmd.c
index 7ae978f..2941ad3 100644
--- a/cmd.c
+++ b/cmd.c
@@ -439,82 +439,3 @@ quit_init(void)
add_command(&quit_cmd);
}
-
-/* from libxcmd/help.c */
-
-static cmdinfo_t help_cmd;
-static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
-static void help_oneline(const char *cmd, const cmdinfo_t *ct);
-
-static void
-help_all(void)
-{
- const cmdinfo_t *ct;
-
- for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++)
- help_oneline(ct->name, ct);
- printf(_("\nUse 'help commandname' for extended help.\n"));
-}
-
-static int
-help_f(
- BlockDriverState *bs,
- int argc,
- char **argv)
-{
- const cmdinfo_t *ct;
-
- if (argc == 1) {
- help_all();
- return 0;
- }
- ct = find_command(argv[1]);
- if (ct == NULL) {
- printf(_("command %s not found\n"), argv[1]);
- return 0;
- }
- help_onecmd(argv[1], ct);
- return 0;
-}
-
-static void
-help_onecmd(
- const char *cmd,
- const cmdinfo_t *ct)
-{
- help_oneline(cmd, ct);
- if (ct->help)
- ct->help();
-}
-
-static void
-help_oneline(
- const char *cmd,
- const cmdinfo_t *ct)
-{
- if (cmd)
- printf("%s ", cmd);
- else {
- printf("%s ", ct->name);
- if (ct->altname)
- printf("(or %s) ", ct->altname);
- }
- if (ct->args)
- printf("%s ", ct->args);
- printf("-- %s\n", ct->oneline);
-}
-
-void
-help_init(void)
-{
- help_cmd.name = _("help");
- help_cmd.altname = _("?");
- help_cmd.cfunc = help_f;
- help_cmd.argmin = 0;
- help_cmd.argmax = 1;
- help_cmd.flags = CMD_FLAG_GLOBAL;
- help_cmd.args = _("[command]");
- help_cmd.oneline = _("help for one or all commands");
-
- add_command(&help_cmd);
-}
diff --git a/cmd.h b/cmd.h
index d676408..89e7c6e 100644
--- a/cmd.h
+++ b/cmd.h
@@ -42,7 +42,6 @@ typedef struct cmdinfo {
extern cmdinfo_t *cmdtab;
extern int ncmds;
-void help_init(void);
void quit_init(void);
typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci);
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 8b12446..fa8d9a0 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -1795,6 +1795,71 @@ static const cmdinfo_t abort_cmd = {
.oneline = "simulate a program crash using abort(3)",
};
+static void help_oneline(const char *cmd, const cmdinfo_t *ct)
+{
+ if (cmd) {
+ printf("%s ", cmd);
+ } else {
+ printf("%s ", ct->name);
+ if (ct->altname) {
+ printf("(or %s) ", ct->altname);
+ }
+ }
+
+ if (ct->args) {
+ printf("%s ", ct->args);
+ }
+ printf("-- %s\n", ct->oneline);
+}
+
+static void help_onecmd(const char *cmd, const cmdinfo_t *ct)
+{
+ help_oneline(cmd, ct);
+ if (ct->help) {
+ ct->help();
+ }
+}
+
+static void help_all(void)
+{
+ const cmdinfo_t *ct;
+
+ for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
+ help_oneline(ct->name, ct);
+ }
+ printf("\nUse 'help commandname' for extended help.\n");
+}
+
+static int help_f(BlockDriverState *bs, int argc, char **argv)
+{
+ const cmdinfo_t *ct;
+
+ if (argc == 1) {
+ help_all();
+ return 0;
+ }
+
+ ct = find_command(argv[1]);
+ if (ct == NULL) {
+ printf("command %s not found\n", argv[1]);
+ return 0;
+ }
+
+ help_onecmd(argv[1], ct);
+ return 0;
+}
+
+static const cmdinfo_t help_cmd = {
+ .name = "help",
+ .altname = "?",
+ .cfunc = help_f,
+ .argmin = 0,
+ .argmax = 1,
+ .flags = CMD_FLAG_GLOBAL,
+ .args = "[command]",
+ .oneline = "help for one or all commands",
+};
+
static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
{
if (ct->flags & CMD_FLAG_GLOBAL) {
@@ -1834,7 +1899,7 @@ bool qemuio_command(const char *cmd)
static void __attribute((constructor)) init_qemuio_commands(void)
{
/* initialize commands */
- help_init();
+ add_command(&help_cmd);
add_command(&read_cmd);
add_command(&readv_cmd);
add_command(&write_cmd);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 10/26] qemu-io: Move 'quit' function
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (8 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 09/26] qemu-io: Move 'help' function Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 11/26] qemu-io: Move qemu_strsep() to cutils.c Stefan Hajnoczi
` (16 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
This one only makes sense in the context of the qemu-io tool, so move it
to qemu-io.c. Adapt coding style and register it like other commands.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 29 -----------------------------
cmd.h | 2 --
qemu-io.c | 17 ++++++++++++++++-
3 files changed, 16 insertions(+), 32 deletions(-)
diff --git a/cmd.c b/cmd.c
index 2941ad3..8496e74 100644
--- a/cmd.c
+++ b/cmd.c
@@ -410,32 +410,3 @@ timestr(
snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
}
}
-
-
-/* from libxcmd/quit.c */
-
-static cmdinfo_t quit_cmd;
-
-/* ARGSUSED */
-static int
-quit_f(
- BlockDriverState *bs,
- int argc,
- char **argv)
-{
- return 1;
-}
-
-void
-quit_init(void)
-{
- quit_cmd.name = _("quit");
- quit_cmd.altname = _("q");
- quit_cmd.cfunc = quit_f;
- quit_cmd.argmin = -1;
- quit_cmd.argmax = -1;
- quit_cmd.flags = CMD_FLAG_GLOBAL;
- quit_cmd.oneline = _("exit the program");
-
- add_command(&quit_cmd);
-}
diff --git a/cmd.h b/cmd.h
index 89e7c6e..5b6f61b 100644
--- a/cmd.h
+++ b/cmd.h
@@ -42,8 +42,6 @@ typedef struct cmdinfo {
extern cmdinfo_t *cmdtab;
extern int ncmds;
-void quit_init(void);
-
typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci);
void add_command(const cmdinfo_t *ci);
diff --git a/qemu-io.c b/qemu-io.c
index 14eef2c..8f6c57e 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -137,6 +137,21 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
return openfile(argv[optind], flags, growable);
}
+static int quit_f(BlockDriverState *bs, int argc, char **argv)
+{
+ return 1;
+}
+
+static const cmdinfo_t quit_cmd = {
+ .name = "quit",
+ .altname = "q",
+ .cfunc = quit_f,
+ .argmin = -1,
+ .argmax = -1,
+ .flags = CMD_FLAG_GLOBAL,
+ .oneline = "exit the program",
+};
+
static void usage(const char *name)
{
printf(
@@ -247,7 +262,7 @@ int main(int argc, char **argv)
bdrv_init();
/* initialize commands */
- quit_init();
+ add_command(&quit_cmd);
add_command(&open_cmd);
add_command(&close_cmd);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 11/26] qemu-io: Move qemu_strsep() to cutils.c
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (9 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 10/26] qemu-io: Move 'quit' function Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 12/26] qemu-io: Move functions for registering and running commands Stefan Hajnoczi
` (15 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 21 ---------------------
include/qemu-common.h | 1 +
util/cutils.c | 21 +++++++++++++++++++++
3 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/cmd.c b/cmd.c
index 8496e74..f6bf2c5 100644
--- a/cmd.c
+++ b/cmd.c
@@ -255,27 +255,6 @@ fetchline(void)
}
#endif
-static char *qemu_strsep(char **input, const char *delim)
-{
- char *result = *input;
- if (result != NULL) {
- char *p;
-
- for (p = result; *p != '\0'; p++) {
- if (strchr(delim, *p)) {
- break;
- }
- }
- if (*p == '\0') {
- *input = NULL;
- } else {
- *p = '\0';
- *input = p + 1;
- }
- }
- return result;
-}
-
char **breakline(char *input, int *count)
{
int c = 0;
diff --git a/include/qemu-common.h b/include/qemu-common.h
index d95ea1e..ed8b6e2 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -174,6 +174,7 @@ char *pstrcat(char *buf, int buf_size, const char *s);
int strstart(const char *str, const char *val, const char **ptr);
int stristart(const char *str, const char *val, const char **ptr);
int qemu_strnlen(const char *s, int max_len);
+char *qemu_strsep(char **input, const char *delim);
time_t mktimegm(struct tm *tm);
int qemu_fls(int i);
int qemu_fdatasync(int fd);
diff --git a/util/cutils.c b/util/cutils.c
index 8f28896..0116fcd 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -107,6 +107,27 @@ int qemu_strnlen(const char *s, int max_len)
return i;
}
+char *qemu_strsep(char **input, const char *delim)
+{
+ char *result = *input;
+ if (result != NULL) {
+ char *p;
+
+ for (p = result; *p != '\0'; p++) {
+ if (strchr(delim, *p)) {
+ break;
+ }
+ }
+ if (*p == '\0') {
+ *input = NULL;
+ } else {
+ *p = '\0';
+ *input = p + 1;
+ }
+ }
+ return result;
+}
+
time_t mktimegm(struct tm *tm)
{
time_t t;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 12/26] qemu-io: Move functions for registering and running commands
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (10 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 11/26] qemu-io: Move qemu_strsep() to cutils.c Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 13/26] qemu-io: Move command_loop() and friends Stefan Hajnoczi
` (14 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 113 ---------------------------------
cmd.h | 11 +---
qemu-io-cmds.c | 192 ++++++++++++++++++++++++++++++++++++++++++---------------
qemu-io.c | 10 +--
4 files changed, 148 insertions(+), 178 deletions(-)
diff --git a/cmd.c b/cmd.c
index f6bf2c5..6616d61 100644
--- a/cmd.c
+++ b/cmd.c
@@ -31,94 +31,9 @@
/* from libxcmd/command.c */
-cmdinfo_t *cmdtab;
-int ncmds;
-
-static checkfunc_t check_func;
static int ncmdline;
static char **cmdline;
-static int
-compare(const void *a, const void *b)
-{
- return strcmp(((const cmdinfo_t *)a)->name,
- ((const cmdinfo_t *)b)->name);
-}
-
-void add_command(const cmdinfo_t *ci)
-{
- cmdtab = g_realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
- cmdtab[ncmds - 1] = *ci;
- qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
-}
-
-static int
-check_command(
- const cmdinfo_t *ci)
-{
- if (check_func)
- return check_func(qemuio_bs, ci);
- return 1;
-}
-
-void
-add_check_command(
- checkfunc_t cf)
-{
- check_func = cf;
-}
-
-int
-command_usage(
- const cmdinfo_t *ci)
-{
- printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
- return 0;
-}
-
-int
-command(
- const cmdinfo_t *ct,
- int argc,
- char **argv)
-{
- char *cmd = argv[0];
-
- if (!check_command(ct))
- return 0;
-
- if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) {
- if (ct->argmax == -1)
- fprintf(stderr,
- _("bad argument count %d to %s, expected at least %d arguments\n"),
- argc-1, cmd, ct->argmin);
- else if (ct->argmin == ct->argmax)
- fprintf(stderr,
- _("bad argument count %d to %s, expected %d arguments\n"),
- argc-1, cmd, ct->argmin);
- else
- fprintf(stderr,
- _("bad argument count %d to %s, expected between %d and %d arguments\n"),
- argc-1, cmd, ct->argmin, ct->argmax);
- return 0;
- }
- optind = 0;
- return ct->cfunc(qemuio_bs, argc, argv);
-}
-
-const cmdinfo_t *
-find_command(
- const char *cmd)
-{
- cmdinfo_t *ct;
-
- for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
- if (strcmp(ct->name, cmd) == 0 ||
- (ct->altname && strcmp(ct->altname, cmd) == 0))
- return (const cmdinfo_t *)ct;
- }
- return NULL;
-}
void add_user_command(char *optarg)
{
@@ -255,34 +170,6 @@ fetchline(void)
}
#endif
-char **breakline(char *input, int *count)
-{
- int c = 0;
- char *p;
- char **rval = calloc(sizeof(char *), 1);
- char **tmp;
-
- while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
- if (!*p) {
- continue;
- }
- c++;
- tmp = realloc(rval, sizeof(*rval) * (c + 1));
- if (!tmp) {
- free(rval);
- rval = NULL;
- c = 0;
- break;
- } else {
- rval = tmp;
- }
- rval[c - 1] = p;
- rval[c] = NULL;
- }
- *count = c;
- return rval;
-}
-
#define EXABYTES(x) ((long long)(x) << 60)
#define PETABYTES(x) ((long long)(x) << 50)
#define TERABYTES(x) ((long long)(x) << 40)
diff --git a/cmd.h b/cmd.h
index 5b6f61b..0d01a33 100644
--- a/cmd.h
+++ b/cmd.h
@@ -39,23 +39,16 @@ typedef struct cmdinfo {
helpfunc_t help;
} cmdinfo_t;
-extern cmdinfo_t *cmdtab;
-extern int ncmds;
-
typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci);
-void add_command(const cmdinfo_t *ci);
+void qemuio_add_command(const cmdinfo_t *ci);
void add_user_command(char *optarg);
void add_check_command(checkfunc_t cf);
-const cmdinfo_t *find_command(const char *cmd);
-
void command_loop(void);
-int command_usage(const cmdinfo_t *ci);
-int command(const cmdinfo_t *ci, int argc, char **argv);
+int qemuio_command_usage(const cmdinfo_t *ci);
/* from input.h */
-char **breakline(char *input, int *count);
char *fetchline(void);
void cvtstr(double value, char *str, size_t sz);
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index fa8d9a0..8acc866 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -16,6 +16,110 @@
int qemuio_misalign;
+static cmdinfo_t *cmdtab;
+static int ncmds;
+
+static int compare_cmdname(const void *a, const void *b)
+{
+ return strcmp(((const cmdinfo_t *)a)->name,
+ ((const cmdinfo_t *)b)->name);
+}
+
+void qemuio_add_command(const cmdinfo_t *ci)
+{
+ cmdtab = g_realloc(cmdtab, ++ncmds * sizeof(*cmdtab));
+ cmdtab[ncmds - 1] = *ci;
+ qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname);
+}
+
+int qemuio_command_usage(const cmdinfo_t *ci)
+{
+ printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
+ return 0;
+}
+
+static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
+{
+ if (ct->flags & CMD_FLAG_GLOBAL) {
+ return 1;
+ }
+ if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+ fprintf(stderr, "no file open, try 'help open'\n");
+ return 0;
+ }
+ return 1;
+}
+
+static int command(const cmdinfo_t *ct, int argc, char **argv)
+{
+ char *cmd = argv[0];
+
+ if (!init_check_command(qemuio_bs, ct)) {
+ return 0;
+ }
+
+ if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) {
+ if (ct->argmax == -1) {
+ fprintf(stderr,
+ "bad argument count %d to %s, expected at least %d arguments\n",
+ argc-1, cmd, ct->argmin);
+ } else if (ct->argmin == ct->argmax) {
+ fprintf(stderr,
+ "bad argument count %d to %s, expected %d arguments\n",
+ argc-1, cmd, ct->argmin);
+ } else {
+ fprintf(stderr,
+ "bad argument count %d to %s, expected between %d and %d arguments\n",
+ argc-1, cmd, ct->argmin, ct->argmax);
+ }
+ return 0;
+ }
+ optind = 0;
+ return ct->cfunc(qemuio_bs, argc, argv);
+}
+
+static const cmdinfo_t *find_command(const char *cmd)
+{
+ cmdinfo_t *ct;
+
+ for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
+ if (strcmp(ct->name, cmd) == 0 ||
+ (ct->altname && strcmp(ct->altname, cmd) == 0))
+ {
+ return (const cmdinfo_t *)ct;
+ }
+ }
+ return NULL;
+}
+
+static char **breakline(char *input, int *count)
+{
+ int c = 0;
+ char *p;
+ char **rval = g_malloc0(sizeof(char *));
+ char **tmp;
+
+ while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
+ if (!*p) {
+ continue;
+ }
+ c++;
+ tmp = g_realloc(rval, sizeof(*rval) * (c + 1));
+ if (!tmp) {
+ g_free(rval);
+ rval = NULL;
+ c = 0;
+ break;
+ } else {
+ rval = tmp;
+ }
+ rval[c - 1] = p;
+ rval[c] = NULL;
+ }
+ *count = c;
+ return rval;
+}
+
static int64_t cvtnum(const char *s)
{
char *end;
@@ -467,12 +571,12 @@ static int read_f(BlockDriverState *bs, int argc, char **argv)
vflag = 1;
break;
default:
- return command_usage(&read_cmd);
+ return qemuio_command_usage(&read_cmd);
}
}
if (optind != argc - 2) {
- return command_usage(&read_cmd);
+ return qemuio_command_usage(&read_cmd);
}
if (bflag && pflag) {
@@ -494,7 +598,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv)
}
if (!Pflag && (lflag || sflag)) {
- return command_usage(&read_cmd);
+ return qemuio_command_usage(&read_cmd);
}
if (!lflag) {
@@ -629,12 +733,12 @@ static int readv_f(BlockDriverState *bs, int argc, char **argv)
vflag = 1;
break;
default:
- return command_usage(&readv_cmd);
+ return qemuio_command_usage(&readv_cmd);
}
}
if (optind > argc - 2) {
- return command_usage(&readv_cmd);
+ return qemuio_command_usage(&readv_cmd);
}
@@ -769,12 +873,12 @@ static int write_f(BlockDriverState *bs, int argc, char **argv)
zflag = 1;
break;
default:
- return command_usage(&write_cmd);
+ return qemuio_command_usage(&write_cmd);
}
}
if (optind != argc - 2) {
- return command_usage(&write_cmd);
+ return qemuio_command_usage(&write_cmd);
}
if (bflag + pflag + zflag > 1) {
@@ -911,12 +1015,12 @@ static int writev_f(BlockDriverState *bs, int argc, char **argv)
}
break;
default:
- return command_usage(&writev_cmd);
+ return qemuio_command_usage(&writev_cmd);
}
}
if (optind > argc - 2) {
- return command_usage(&writev_cmd);
+ return qemuio_command_usage(&writev_cmd);
}
offset = cvtnum(argv[optind]);
@@ -1023,12 +1127,12 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv)
}
break;
default:
- return command_usage(&writev_cmd);
+ return qemuio_command_usage(&writev_cmd);
}
}
if (optind > argc - 2) {
- return command_usage(&writev_cmd);
+ return qemuio_command_usage(&writev_cmd);
}
nr_reqs = 1;
@@ -1257,13 +1361,13 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
break;
default:
g_free(ctx);
- return command_usage(&aio_read_cmd);
+ return qemuio_command_usage(&aio_read_cmd);
}
}
if (optind > argc - 2) {
g_free(ctx);
- return command_usage(&aio_read_cmd);
+ return qemuio_command_usage(&aio_read_cmd);
}
ctx->offset = cvtnum(argv[optind]);
@@ -1349,13 +1453,13 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
break;
default:
g_free(ctx);
- return command_usage(&aio_write_cmd);
+ return qemuio_command_usage(&aio_write_cmd);
}
}
if (optind > argc - 2) {
g_free(ctx);
- return command_usage(&aio_write_cmd);
+ return qemuio_command_usage(&aio_write_cmd);
}
ctx->offset = cvtnum(argv[optind]);
@@ -1547,12 +1651,12 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv)
qflag = 1;
break;
default:
- return command_usage(&discard_cmd);
+ return qemuio_command_usage(&discard_cmd);
}
}
if (optind != argc - 2) {
- return command_usage(&discard_cmd);
+ return qemuio_command_usage(&discard_cmd);
}
offset = cvtnum(argv[optind]);
@@ -1860,18 +1964,6 @@ static const cmdinfo_t help_cmd = {
.oneline = "help for one or all commands",
};
-static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
-{
- if (ct->flags & CMD_FLAG_GLOBAL) {
- return 1;
- }
- if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
- fprintf(stderr, "no file open, try 'help open'\n");
- return 0;
- }
- return 1;
-}
-
bool qemuio_command(const char *cmd)
{
char *input;
@@ -1899,26 +1991,24 @@ bool qemuio_command(const char *cmd)
static void __attribute((constructor)) init_qemuio_commands(void)
{
/* initialize commands */
- add_command(&help_cmd);
- add_command(&read_cmd);
- add_command(&readv_cmd);
- add_command(&write_cmd);
- add_command(&writev_cmd);
- add_command(&multiwrite_cmd);
- add_command(&aio_read_cmd);
- add_command(&aio_write_cmd);
- add_command(&aio_flush_cmd);
- add_command(&flush_cmd);
- add_command(&truncate_cmd);
- add_command(&length_cmd);
- add_command(&info_cmd);
- add_command(&discard_cmd);
- add_command(&alloc_cmd);
- add_command(&map_cmd);
- add_command(&break_cmd);
- add_command(&resume_cmd);
- add_command(&wait_break_cmd);
- add_command(&abort_cmd);
-
- add_check_command(init_check_command);
+ qemuio_add_command(&help_cmd);
+ qemuio_add_command(&read_cmd);
+ qemuio_add_command(&readv_cmd);
+ qemuio_add_command(&write_cmd);
+ qemuio_add_command(&writev_cmd);
+ qemuio_add_command(&multiwrite_cmd);
+ qemuio_add_command(&aio_read_cmd);
+ qemuio_add_command(&aio_write_cmd);
+ qemuio_add_command(&aio_flush_cmd);
+ qemuio_add_command(&flush_cmd);
+ qemuio_add_command(&truncate_cmd);
+ qemuio_add_command(&length_cmd);
+ qemuio_add_command(&info_cmd);
+ qemuio_add_command(&discard_cmd);
+ qemuio_add_command(&alloc_cmd);
+ qemuio_add_command(&map_cmd);
+ qemuio_add_command(&break_cmd);
+ qemuio_add_command(&resume_cmd);
+ qemuio_add_command(&wait_break_cmd);
+ qemuio_add_command(&abort_cmd);
}
diff --git a/qemu-io.c b/qemu-io.c
index 8f6c57e..3bf5aec 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -122,7 +122,7 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
growable = 1;
break;
default:
- return command_usage(&open_cmd);
+ return qemuio_command_usage(&open_cmd);
}
}
@@ -131,7 +131,7 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
}
if (optind != argc - 1) {
- return command_usage(&open_cmd);
+ return qemuio_command_usage(&open_cmd);
}
return openfile(argv[optind], flags, growable);
@@ -262,9 +262,9 @@ int main(int argc, char **argv)
bdrv_init();
/* initialize commands */
- add_command(&quit_cmd);
- add_command(&open_cmd);
- add_command(&close_cmd);
+ qemuio_add_command(&quit_cmd);
+ qemuio_add_command(&open_cmd);
+ qemuio_add_command(&close_cmd);
/* open the device */
if (!readonly) {
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 13/26] qemu-io: Move command_loop() and friends
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (11 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 12/26] qemu-io: Move functions for registering and running commands Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 14/26] qemu-io: Move remaining helpers from cmd.c Stefan Hajnoczi
` (13 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.c | 139 --------------------------------------------------------------
cmd.h | 9 ----
qemu-io.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 139 insertions(+), 148 deletions(-)
diff --git a/cmd.c b/cmd.c
index 6616d61..26d38a8 100644
--- a/cmd.c
+++ b/cmd.c
@@ -31,145 +31,6 @@
/* from libxcmd/command.c */
-static int ncmdline;
-static char **cmdline;
-
-
-void add_user_command(char *optarg)
-{
- cmdline = g_realloc(cmdline, ++ncmdline * sizeof(char *));
- cmdline[ncmdline-1] = optarg;
-}
-
-static void prep_fetchline(void *opaque)
-{
- int *fetchable = opaque;
-
- qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
- *fetchable= 1;
-}
-
-static char *get_prompt(void);
-
-void command_loop(void)
-{
- int i, done = 0, fetchable = 0, prompted = 0;
- char *input;
-
- for (i = 0; !done && i < ncmdline; i++) {
- done = qemuio_command(cmdline[i]);
- }
- if (cmdline) {
- g_free(cmdline);
- return;
- }
-
- while (!done) {
- if (!prompted) {
- printf("%s", get_prompt());
- fflush(stdout);
- qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
- prompted = 1;
- }
-
- main_loop_wait(false);
-
- if (!fetchable) {
- continue;
- }
-
- input = fetchline();
- if (input == NULL) {
- break;
- }
- done = qemuio_command(input);
- free(input);
-
- prompted = 0;
- fetchable = 0;
- }
- qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
-}
-
-/* from libxcmd/input.c */
-
-#if defined(ENABLE_READLINE)
-# include <readline/history.h>
-# include <readline/readline.h>
-#elif defined(ENABLE_EDITLINE)
-# include <histedit.h>
-#endif
-
-static char *
-get_prompt(void)
-{
- static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
-
- if (!prompt[0])
- snprintf(prompt, sizeof(prompt), "%s> ", progname);
- return prompt;
-}
-
-#if defined(ENABLE_READLINE)
-char *
-fetchline(void)
-{
- char *line;
-
- line = readline(get_prompt());
- if (line && *line)
- add_history(line);
- return line;
-}
-#elif defined(ENABLE_EDITLINE)
-static char *el_get_prompt(EditLine *e) { return get_prompt(); }
-char *
-fetchline(void)
-{
- static EditLine *el;
- static History *hist;
- HistEvent hevent;
- char *line;
- int count;
-
- if (!el) {
- hist = history_init();
- history(hist, &hevent, H_SETSIZE, 100);
- el = el_init(progname, stdin, stdout, stderr);
- el_source(el, NULL);
- el_set(el, EL_SIGNAL, 1);
- el_set(el, EL_PROMPT, el_get_prompt);
- el_set(el, EL_HIST, history, (const char *)hist);
- }
- line = strdup(el_gets(el, &count));
- if (line) {
- if (count > 0)
- line[count-1] = '\0';
- if (*line)
- history(hist, &hevent, H_ENTER, line);
- }
- return line;
-}
-#else
-# define MAXREADLINESZ 1024
-char *
-fetchline(void)
-{
- char *p, *line = malloc(MAXREADLINESZ);
-
- if (!line)
- return NULL;
- if (!fgets(line, MAXREADLINESZ, stdin)) {
- free(line);
- return NULL;
- }
- p = line + strlen(line);
- if (p != line && p[-1] == '\n')
- p[-1] = '\0';
- return line;
-}
-#endif
-
#define EXABYTES(x) ((long long)(x) << 60)
#define PETABYTES(x) ((long long)(x) << 50)
#define TERABYTES(x) ((long long)(x) << 40)
diff --git a/cmd.h b/cmd.h
index 0d01a33..da0c7cf 100644
--- a/cmd.h
+++ b/cmd.h
@@ -39,18 +39,11 @@ typedef struct cmdinfo {
helpfunc_t help;
} cmdinfo_t;
-typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci);
-
void qemuio_add_command(const cmdinfo_t *ci);
-void add_user_command(char *optarg);
-void add_check_command(checkfunc_t cf);
-void command_loop(void);
int qemuio_command_usage(const cmdinfo_t *ci);
/* from input.h */
-char *fetchline(void);
-
void cvtstr(double value, char *str, size_t sz);
struct timeval tsub(struct timeval t1, struct timeval t2);
@@ -64,8 +57,6 @@ enum {
void timestr(struct timeval *tv, char *str, size_t sz, int flags);
-extern char *progname;
-
bool qemuio_command(const char *cmd);
#endif /* __COMMAND_H__ */
diff --git a/qemu-io.c b/qemu-io.c
index 3bf5aec..eec8cbc 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -29,6 +29,10 @@ char *progname;
BlockDriverState *qemuio_bs;
extern int qemuio_misalign;
+/* qemu-io commands passed using -c */
+static int ncmdline;
+static char **cmdline;
+
static int close_f(BlockDriverState *bs, int argc, char **argv)
{
bdrv_delete(bs);
@@ -174,6 +178,141 @@ static void usage(const char *name)
}
+#if defined(ENABLE_READLINE)
+# include <readline/history.h>
+# include <readline/readline.h>
+#elif defined(ENABLE_EDITLINE)
+# include <histedit.h>
+#endif
+
+static char *get_prompt(void)
+{
+ static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
+
+ if (!prompt[0]) {
+ snprintf(prompt, sizeof(prompt), "%s> ", progname);
+ }
+
+ return prompt;
+}
+
+#if defined(ENABLE_READLINE)
+static char *fetchline(void)
+{
+ char *line = readline(get_prompt());
+ if (line && *line) {
+ add_history(line);
+ }
+ return line;
+}
+#elif defined(ENABLE_EDITLINE)
+static char *el_get_prompt(EditLine *e)
+{
+ return get_prompt();
+}
+
+static char *fetchline(void)
+{
+ static EditLine *el;
+ static History *hist;
+ HistEvent hevent;
+ char *line;
+ int count;
+
+ if (!el) {
+ hist = history_init();
+ history(hist, &hevent, H_SETSIZE, 100);
+ el = el_init(progname, stdin, stdout, stderr);
+ el_source(el, NULL);
+ el_set(el, EL_SIGNAL, 1);
+ el_set(el, EL_PROMPT, el_get_prompt);
+ el_set(el, EL_HIST, history, (const char *)hist);
+ }
+ line = strdup(el_gets(el, &count));
+ if (line) {
+ if (count > 0) {
+ line[count-1] = '\0';
+ }
+ if (*line) {
+ history(hist, &hevent, H_ENTER, line);
+ }
+ }
+ return line;
+}
+#else
+# define MAXREADLINESZ 1024
+static char *fetchline(void)
+{
+ char *p, *line = g_malloc(MAXREADLINESZ);
+
+ if (!fgets(line, MAXREADLINESZ, stdin)) {
+ g_free(line);
+ return NULL;
+ }
+
+ p = line + strlen(line);
+ if (p != line && p[-1] == '\n') {
+ p[-1] = '\0';
+ }
+
+ return line;
+}
+#endif
+
+static void prep_fetchline(void *opaque)
+{
+ int *fetchable = opaque;
+
+ qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
+ *fetchable= 1;
+}
+
+static void command_loop(void)
+{
+ int i, done = 0, fetchable = 0, prompted = 0;
+ char *input;
+
+ for (i = 0; !done && i < ncmdline; i++) {
+ done = qemuio_command(cmdline[i]);
+ }
+ if (cmdline) {
+ g_free(cmdline);
+ return;
+ }
+
+ while (!done) {
+ if (!prompted) {
+ printf("%s", get_prompt());
+ fflush(stdout);
+ qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
+ prompted = 1;
+ }
+
+ main_loop_wait(false);
+
+ if (!fetchable) {
+ continue;
+ }
+
+ input = fetchline();
+ if (input == NULL) {
+ break;
+ }
+ done = qemuio_command(input);
+ g_free(input);
+
+ prompted = 0;
+ fetchable = 0;
+ }
+ qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
+}
+
+static void add_user_command(char *optarg)
+{
+ cmdline = g_realloc(cmdline, ++ncmdline * sizeof(char *));
+ cmdline[ncmdline-1] = optarg;
+}
+
int main(int argc, char **argv)
{
int readonly = 0;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 14/26] qemu-io: Move remaining helpers from cmd.c
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (12 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 13/26] qemu-io: Move command_loop() and friends Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 15/26] qemu-io: Interface cleanup Stefan Hajnoczi
` (12 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
Makefile | 2 +-
cmd.c | 139 ---------------------------------------------------------
cmd.h | 14 ------
qemu-io-cmds.c | 104 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 105 insertions(+), 154 deletions(-)
delete mode 100644 cmd.c
diff --git a/Makefile b/Makefile
index cf932eb..87298e5 100644
--- a/Makefile
+++ b/Makefile
@@ -186,7 +186,7 @@ qemu-img.o: qemu-img-cmds.h
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
-qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a
+qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
diff --git a/cmd.c b/cmd.c
deleted file mode 100644
index 26d38a8..0000000
--- a/cmd.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2003-2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <getopt.h>
-
-#include "cmd.h"
-#include "block/aio.h"
-#include "qemu/main-loop.h"
-
-#define _(x) x /* not gettext support yet */
-
-/* from libxcmd/command.c */
-
-#define EXABYTES(x) ((long long)(x) << 60)
-#define PETABYTES(x) ((long long)(x) << 50)
-#define TERABYTES(x) ((long long)(x) << 40)
-#define GIGABYTES(x) ((long long)(x) << 30)
-#define MEGABYTES(x) ((long long)(x) << 20)
-#define KILOBYTES(x) ((long long)(x) << 10)
-
-#define TO_EXABYTES(x) ((x) / EXABYTES(1))
-#define TO_PETABYTES(x) ((x) / PETABYTES(1))
-#define TO_TERABYTES(x) ((x) / TERABYTES(1))
-#define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
-#define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
-#define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
-
-void
-cvtstr(
- double value,
- char *str,
- size_t size)
-{
- char *trim;
- const char *suffix;
-
- if (value >= EXABYTES(1)) {
- suffix = " EiB";
- snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
- } else if (value >= PETABYTES(1)) {
- suffix = " PiB";
- snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
- } else if (value >= TERABYTES(1)) {
- suffix = " TiB";
- snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
- } else if (value >= GIGABYTES(1)) {
- suffix = " GiB";
- snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
- } else if (value >= MEGABYTES(1)) {
- suffix = " MiB";
- snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
- } else if (value >= KILOBYTES(1)) {
- suffix = " KiB";
- snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
- } else {
- suffix = " bytes";
- snprintf(str, size - 6, "%f", value);
- }
-
- trim = strstr(str, ".000");
- if (trim) {
- strcpy(trim, suffix);
- } else {
- strcat(str, suffix);
- }
-}
-
-struct timeval
-tsub(struct timeval t1, struct timeval t2)
-{
- t1.tv_usec -= t2.tv_usec;
- if (t1.tv_usec < 0) {
- t1.tv_usec += 1000000;
- t1.tv_sec--;
- }
- t1.tv_sec -= t2.tv_sec;
- return t1;
-}
-
-double
-tdiv(double value, struct timeval tv)
-{
- return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
-}
-
-#define HOURS(sec) ((sec) / (60 * 60))
-#define MINUTES(sec) (((sec) % (60 * 60)) / 60)
-#define SECONDS(sec) ((sec) % 60)
-
-void
-timestr(
- struct timeval *tv,
- char *ts,
- size_t size,
- int format)
-{
- double usec = (double)tv->tv_usec / 1000000.0;
-
- if (format & TERSE_FIXED_TIME) {
- if (!HOURS(tv->tv_sec)) {
- snprintf(ts, size, "%u:%02u.%02u",
- (unsigned int) MINUTES(tv->tv_sec),
- (unsigned int) SECONDS(tv->tv_sec),
- (unsigned int) (usec * 100));
- return;
- }
- format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
- }
-
- if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
- snprintf(ts, size, "%u:%02u:%02u.%02u",
- (unsigned int) HOURS(tv->tv_sec),
- (unsigned int) MINUTES(tv->tv_sec),
- (unsigned int) SECONDS(tv->tv_sec),
- (unsigned int) (usec * 100));
- } else {
- snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
- }
-}
diff --git a/cmd.h b/cmd.h
index da0c7cf..9907795 100644
--- a/cmd.h
+++ b/cmd.h
@@ -43,20 +43,6 @@ void qemuio_add_command(const cmdinfo_t *ci);
int qemuio_command_usage(const cmdinfo_t *ci);
-/* from input.h */
-void cvtstr(double value, char *str, size_t sz);
-
-struct timeval tsub(struct timeval t1, struct timeval t2);
-double tdiv(double value, struct timeval tv);
-
-enum {
- DEFAULT_TIME = 0x0,
- TERSE_FIXED_TIME = 0x1,
- VERBOSE_FIXED_TIME = 0x2
-};
-
-void timestr(struct timeval *tv, char *str, size_t sz, int flags);
-
bool qemuio_command(const char *cmd);
#endif /* __COMMAND_H__ */
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 8acc866..05ce342 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -126,6 +126,110 @@ static int64_t cvtnum(const char *s)
return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B);
}
+#define EXABYTES(x) ((long long)(x) << 60)
+#define PETABYTES(x) ((long long)(x) << 50)
+#define TERABYTES(x) ((long long)(x) << 40)
+#define GIGABYTES(x) ((long long)(x) << 30)
+#define MEGABYTES(x) ((long long)(x) << 20)
+#define KILOBYTES(x) ((long long)(x) << 10)
+
+#define TO_EXABYTES(x) ((x) / EXABYTES(1))
+#define TO_PETABYTES(x) ((x) / PETABYTES(1))
+#define TO_TERABYTES(x) ((x) / TERABYTES(1))
+#define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
+#define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
+#define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
+
+static void cvtstr(double value, char *str, size_t size)
+{
+ char *trim;
+ const char *suffix;
+
+ if (value >= EXABYTES(1)) {
+ suffix = " EiB";
+ snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
+ } else if (value >= PETABYTES(1)) {
+ suffix = " PiB";
+ snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
+ } else if (value >= TERABYTES(1)) {
+ suffix = " TiB";
+ snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
+ } else if (value >= GIGABYTES(1)) {
+ suffix = " GiB";
+ snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
+ } else if (value >= MEGABYTES(1)) {
+ suffix = " MiB";
+ snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
+ } else if (value >= KILOBYTES(1)) {
+ suffix = " KiB";
+ snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
+ } else {
+ suffix = " bytes";
+ snprintf(str, size - 6, "%f", value);
+ }
+
+ trim = strstr(str, ".000");
+ if (trim) {
+ strcpy(trim, suffix);
+ } else {
+ strcat(str, suffix);
+ }
+}
+
+
+
+static struct timeval tsub(struct timeval t1, struct timeval t2)
+{
+ t1.tv_usec -= t2.tv_usec;
+ if (t1.tv_usec < 0) {
+ t1.tv_usec += 1000000;
+ t1.tv_sec--;
+ }
+ t1.tv_sec -= t2.tv_sec;
+ return t1;
+}
+
+static double tdiv(double value, struct timeval tv)
+{
+ return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
+}
+
+#define HOURS(sec) ((sec) / (60 * 60))
+#define MINUTES(sec) (((sec) % (60 * 60)) / 60)
+#define SECONDS(sec) ((sec) % 60)
+
+enum {
+ DEFAULT_TIME = 0x0,
+ TERSE_FIXED_TIME = 0x1,
+ VERBOSE_FIXED_TIME = 0x2,
+};
+
+static void timestr(struct timeval *tv, char *ts, size_t size, int format)
+{
+ double usec = (double)tv->tv_usec / 1000000.0;
+
+ if (format & TERSE_FIXED_TIME) {
+ if (!HOURS(tv->tv_sec)) {
+ snprintf(ts, size, "%u:%02u.%02u",
+ (unsigned int) MINUTES(tv->tv_sec),
+ (unsigned int) SECONDS(tv->tv_sec),
+ (unsigned int) (usec * 100));
+ return;
+ }
+ format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
+ }
+
+ if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
+ snprintf(ts, size, "%u:%02u:%02u.%02u",
+ (unsigned int) HOURS(tv->tv_sec),
+ (unsigned int) MINUTES(tv->tv_sec),
+ (unsigned int) SECONDS(tv->tv_sec),
+ (unsigned int) (usec * 100));
+ } else {
+ snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
+ }
+}
+
/*
* Parse the pattern argument to various sub-commands.
*
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 15/26] qemu-io: Interface cleanup
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (13 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 14/26] qemu-io: Move remaining helpers from cmd.c Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 16/26] qemu-io: Use the qemu version for -V Stefan Hajnoczi
` (11 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
cmd.h | 48 ------------------------------------------------
include/qemu-io.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
qemu-io-cmds.c | 14 +++++++-------
qemu-io.c | 7 +++----
4 files changed, 56 insertions(+), 59 deletions(-)
delete mode 100644 cmd.h
create mode 100644 include/qemu-io.h
diff --git a/cmd.h b/cmd.h
deleted file mode 100644
index 9907795..0000000
--- a/cmd.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __COMMAND_H__
-#define __COMMAND_H__
-
-#include "qemu-common.h"
-
-#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */
-
-extern BlockDriverState *qemuio_bs;
-
-typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv);
-typedef void (*helpfunc_t)(void);
-
-typedef struct cmdinfo {
- const char *name;
- const char *altname;
- cfunc_t cfunc;
- int argmin;
- int argmax;
- int canpush;
- int flags;
- const char *args;
- const char *oneline;
- helpfunc_t help;
-} cmdinfo_t;
-
-void qemuio_add_command(const cmdinfo_t *ci);
-
-int qemuio_command_usage(const cmdinfo_t *ci);
-
-bool qemuio_command(const char *cmd);
-
-#endif /* __COMMAND_H__ */
diff --git a/include/qemu-io.h b/include/qemu-io.h
new file mode 100644
index 0000000..a418b46
--- /dev/null
+++ b/include/qemu-io.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_IO_H
+#define QEMU_IO_H
+
+#include "qemu-common.h"
+
+#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */
+
+typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv);
+typedef void (*helpfunc_t)(void);
+
+typedef struct cmdinfo {
+ const char* name;
+ const char* altname;
+ cfunc_t cfunc;
+ int argmin;
+ int argmax;
+ int canpush;
+ int flags;
+ const char *args;
+ const char *oneline;
+ helpfunc_t help;
+} cmdinfo_t;
+
+bool qemuio_command(BlockDriverState *bs, const char *cmd);
+
+void qemuio_add_command(const cmdinfo_t *ci);
+int qemuio_command_usage(const cmdinfo_t *ci);
+
+#endif /* QEMU_IO_H */
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 05ce342..ffbcf31 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -8,9 +8,8 @@
* See the COPYING file in the top-level directory.
*/
-#include "qemu-common.h"
+#include "qemu-io.h"
#include "block/block_int.h"
-#include "cmd.h"
#define CMD_NOFILE_OK 0x01
@@ -50,11 +49,12 @@ static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
return 1;
}
-static int command(const cmdinfo_t *ct, int argc, char **argv)
+static int command(BlockDriverState *bs, const cmdinfo_t *ct, int argc,
+ char **argv)
{
char *cmd = argv[0];
- if (!init_check_command(qemuio_bs, ct)) {
+ if (!init_check_command(bs, ct)) {
return 0;
}
@@ -75,7 +75,7 @@ static int command(const cmdinfo_t *ct, int argc, char **argv)
return 0;
}
optind = 0;
- return ct->cfunc(qemuio_bs, argc, argv);
+ return ct->cfunc(bs, argc, argv);
}
static const cmdinfo_t *find_command(const char *cmd)
@@ -2068,7 +2068,7 @@ static const cmdinfo_t help_cmd = {
.oneline = "help for one or all commands",
};
-bool qemuio_command(const char *cmd)
+bool qemuio_command(BlockDriverState *bs, const char *cmd)
{
char *input;
const cmdinfo_t *ct;
@@ -2081,7 +2081,7 @@ bool qemuio_command(const char *cmd)
if (c) {
ct = find_command(v[0]);
if (ct) {
- done = command(ct, c, v);
+ done = command(bs, ct, c, v);
} else {
fprintf(stderr, "command \"%s\" not found\n", v[0]);
}
diff --git a/qemu-io.c b/qemu-io.c
index eec8cbc..514edcb 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -14,10 +14,9 @@
#include <getopt.h>
#include <libgen.h>
-#include "qemu-common.h"
+#include "qemu-io.h"
#include "qemu/main-loop.h"
#include "block/block_int.h"
-#include "cmd.h"
#include "trace/control.h"
#define VERSION "0.0.1"
@@ -273,7 +272,7 @@ static void command_loop(void)
char *input;
for (i = 0; !done && i < ncmdline; i++) {
- done = qemuio_command(cmdline[i]);
+ done = qemuio_command(qemuio_bs, cmdline[i]);
}
if (cmdline) {
g_free(cmdline);
@@ -298,7 +297,7 @@ static void command_loop(void)
if (input == NULL) {
break;
}
- done = qemuio_command(input);
+ done = qemuio_command(qemuio_bs, input);
g_free(input);
prompted = 0;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 16/26] qemu-io: Use the qemu version for -V
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (14 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 15/26] qemu-io: Interface cleanup Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 17/26] Make qemu-io commands available in HMP Stefan Hajnoczi
` (10 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Always printing 0.0.1 and never updating the version number wasn't very
useful. qemu-io is released with qemu, so using the same version number
makes most sense.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
qemu-io.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/qemu-io.c b/qemu-io.c
index 514edcb..cb9def5 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -19,8 +19,6 @@
#include "block/block_int.h"
#include "trace/control.h"
-#define VERSION "0.0.1"
-
#define CMD_NOFILE_OK 0x01
char *progname;
@@ -380,7 +378,7 @@ int main(int argc, char **argv)
}
break;
case 'V':
- printf("%s version %s\n", progname, VERSION);
+ printf("%s version %s\n", progname, QEMU_VERSION);
exit(0);
case 'h':
usage(progname);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 17/26] Make qemu-io commands available in HMP
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (15 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 16/26] qemu-io: Use the qemu version for -V Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 18/26] blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events Stefan Hajnoczi
` (9 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
It was decided to not make this command available in QMP in order to
make clear that this is not supposed to be a stable API and should be
used only for testing and debugging purposes.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
Makefile | 2 +-
Makefile.objs | 1 +
hmp-commands.hx | 16 ++++++++++++++++
hmp.c | 18 ++++++++++++++++++
hmp.h | 1 +
5 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 87298e5..9a77ae0 100644
--- a/Makefile
+++ b/Makefile
@@ -186,7 +186,7 @@ qemu-img.o: qemu-img-cmds.h
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
-qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o $(block-obj-y) libqemuutil.a libqemustub.a
+qemu-io$(EXESUF): qemu-io.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
diff --git a/Makefile.objs b/Makefile.objs
index 286ce06..5b288ba 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -13,6 +13,7 @@ block-obj-$(CONFIG_POSIX) += aio-posix.o
block-obj-$(CONFIG_WIN32) += aio-win32.o
block-obj-y += block/
block-obj-y += qapi-types.o qapi-visit.o
+block-obj-y += qemu-io-cmds.o
block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
block-obj-y += qemu-coroutine-sleep.o
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 4f5a3fd..396691a 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1553,6 +1553,22 @@ Removes the chardev @var{id}.
ETEXI
{
+ .name = "qemu-io",
+ .args_type = "device:B,command:s",
+ .params = "[device] \"[command]\"",
+ .help = "run a qemu-io command on a block device",
+ .mhandler.cmd = hmp_qemu_io,
+ },
+
+STEXI
+@item qemu-io @var{device} @var{command}
+@findex qemu-io
+
+Executes a qemu-io command on the given block device.
+
+ETEXI
+
+ {
.name = "info",
.args_type = "item:s?",
.params = "[subcommand]",
diff --git a/hmp.c b/hmp.c
index 4fb76ec..64e0baa 100644
--- a/hmp.c
+++ b/hmp.c
@@ -22,6 +22,7 @@
#include "qemu/sockets.h"
#include "monitor/monitor.h"
#include "ui/console.h"
+#include "qemu-io.h"
static void hmp_handle_error(Monitor *mon, Error **errp)
{
@@ -1425,3 +1426,20 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
hmp_handle_error(mon, &local_err);
}
+
+void hmp_qemu_io(Monitor *mon, const QDict *qdict)
+{
+ BlockDriverState *bs;
+ const char* device = qdict_get_str(qdict, "device");
+ const char* command = qdict_get_str(qdict, "command");
+ Error *err = NULL;
+
+ bs = bdrv_find(device);
+ if (bs) {
+ qemuio_command(bs, command);
+ } else {
+ error_set(&err, QERR_DEVICE_NOT_FOUND, device);
+ }
+
+ hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 95fe76e..56d2e92 100644
--- a/hmp.h
+++ b/hmp.h
@@ -85,5 +85,6 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
void hmp_chardev_add(Monitor *mon, const QDict *qdict);
void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
+void hmp_qemu_io(Monitor *mon, const QDict *qdict);
#endif
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 18/26] blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (16 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 17/26] Make qemu-io commands available in HMP Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 19/26] ide-test: Add enum value for DEV Stefan Hajnoczi
` (8 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
block.c | 8 ++++----
block/blkdebug.c | 3 +++
include/block/block.h | 3 +++
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/block.c b/block.c
index 3f616de..79ad33d 100644
--- a/block.c
+++ b/block.c
@@ -3186,13 +3186,11 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
{
- BlockDriver *drv = bs->drv;
-
- if (!drv || !drv->bdrv_debug_event) {
+ if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) {
return;
}
- drv->bdrv_debug_event(bs, event);
+ bs->drv->bdrv_debug_event(bs, event);
}
int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
@@ -4024,6 +4022,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
}
/* Write back cached data to the OS even with cache=unsafe */
+ BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_OS);
if (bs->drv->bdrv_co_flush_to_os) {
ret = bs->drv->bdrv_co_flush_to_os(bs);
if (ret < 0) {
@@ -4036,6 +4035,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
goto flush_parent;
}
+ BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_DISK);
if (bs->drv->bdrv_co_flush_to_disk) {
ret = bs->drv->bdrv_co_flush_to_disk(bs);
} else if (bs->drv->bdrv_aio_flush) {
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 71f99e4..ccb627a 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -182,6 +182,9 @@ static const char *event_names[BLKDBG_EVENT_MAX] = {
[BLKDBG_CLUSTER_ALLOC] = "cluster_alloc",
[BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes",
[BLKDBG_CLUSTER_FREE] = "cluster_free",
+
+ [BLKDBG_FLUSH_TO_OS] = "flush_to_os",
+ [BLKDBG_FLUSH_TO_DISK] = "flush_to_disk",
};
static int get_event_by_name(const char *name, BlkDebugEvent *event)
diff --git a/include/block/block.h b/include/block/block.h
index dc5b388..2307f67 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -424,6 +424,9 @@ typedef enum {
BLKDBG_CLUSTER_ALLOC_BYTES,
BLKDBG_CLUSTER_FREE,
+ BLKDBG_FLUSH_TO_OS,
+ BLKDBG_FLUSH_TO_DISK,
+
BLKDBG_EVENT_MAX,
} BlkDebugEvent;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 19/26] ide-test: Add enum value for DEV
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (17 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 18/26] blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 20/26] ide: Set BSY bit during FLUSH Stefan Hajnoczi
` (7 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
Get rid of the magic number.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
tests/ide-test.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 365e995..1c31a2e 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -64,6 +64,7 @@ enum {
};
enum {
+ DEV = 0x10,
LBA = 0x40,
};
@@ -394,7 +395,7 @@ static void test_identify(void)
/* Read in the IDENTIFY buffer and check registers */
data = inb(IDE_BASE + reg_device);
- g_assert_cmpint(data & 0x10, ==, 0);
+ g_assert_cmpint(data & DEV, ==, 0);
for (i = 0; i < 256; i++) {
data = inb(IDE_BASE + reg_status);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 20/26] ide: Set BSY bit during FLUSH
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (18 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 19/26] ide-test: Add enum value for DEV Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 12:10 ` Paolo Bonzini
2013-06-07 11:58 ` [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case Stefan Hajnoczi
` (6 subsequent siblings)
26 siblings, 1 reply; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel
Cc: Kevin Wolf, Anthony Liguori, Andreas Färber, Stefan Hajnoczi
From: Andreas Färber <afaerber@suse.de>
The implementation of the ATA FLUSH command invokes a flush at the block
layer, which may on raw files on POSIX entail a synchronous fdatasync().
This may in some cases take so long that the SLES 11 SP1 guest driver
reports I/O errors and filesystems get corrupted or remounted read-only.
Avoid this by setting BUSY_STAT, so that the guest is made aware we are
in the middle of an operation and no ATA commands are attempted to be
processed concurrently.
Addresses BNC#637297.
Suggested-by: Gonglei (Arei) <arei.gonglei@huawei.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hw/ide/core.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index c7a8041..9926d92 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -814,6 +814,7 @@ void ide_flush_cache(IDEState *s)
return;
}
+ s->status |= BUSY_STAT;
bdrv_acct_start(s->bs, &s->acct, 0, BDRV_ACCT_FLUSH);
bdrv_aio_flush(s->bs, ide_flush_cb, s);
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (19 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 20/26] ide: Set BSY bit during FLUSH Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-14 17:54 ` Peter Maydell
2013-06-07 11:58 ` [Qemu-devel] [PULL 22/26] block: add snapshot info query function bdrv_query_snapshot_info_list() Stefan Hajnoczi
` (5 subsequent siblings)
26 siblings, 1 reply; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi
From: Kevin Wolf <kwolf@redhat.com>
This checks in particular that BSY is set while the flush request is in
flight.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
tests/ide-test.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 1c31a2e..828e71a 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -77,6 +77,7 @@ enum {
enum {
CMD_READ_DMA = 0xc8,
CMD_WRITE_DMA = 0xca,
+ CMD_FLUSH_CACHE = 0xe7,
CMD_IDENTIFY = 0xec,
CMDF_ABORT = 0x100,
@@ -424,6 +425,43 @@ static void test_identify(void)
ide_test_quit();
}
+static void test_flush(void)
+{
+ uint8_t data;
+
+ ide_test_start(
+ "-vnc none "
+ "-drive file=blkdebug::%s,if=ide,cache=writeback",
+ tmp_path);
+
+ /* Delay the completion of the flush request until we explicitly do it */
+ qmp("{'execute':'human-monitor-command', 'arguments': { "
+ "'command-line': 'qemu-io ide0-hd0 \"break flush_to_os A\"'} }");
+
+ /* FLUSH CACHE command on device 0*/
+ outb(IDE_BASE + reg_device, 0);
+ outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
+
+ /* Check status while request is in flight*/
+ data = inb(IDE_BASE + reg_status);
+ assert_bit_set(data, BSY | DRDY);
+ assert_bit_clear(data, DF | ERR | DRQ);
+
+ /* Complete the command */
+ qmp("{'execute':'human-monitor-command', 'arguments': { "
+ "'command-line': 'qemu-io ide0-hd0 \"resume A\"'} }");
+
+ /* Check registers */
+ data = inb(IDE_BASE + reg_device);
+ g_assert_cmpint(data & DEV, ==, 0);
+
+ data = inb(IDE_BASE + reg_status);
+ assert_bit_set(data, DRDY);
+ assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+ ide_test_quit();
+}
+
int main(int argc, char **argv)
{
const char *arch = qtest_get_arch();
@@ -454,6 +492,8 @@ int main(int argc, char **argv)
qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
+ qtest_add_func("/ide/flush", test_flush);
+
ret = g_test_run();
/* Cleanup */
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 22/26] block: add snapshot info query function bdrv_query_snapshot_info_list()
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (20 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 23/26] block: add image info query function bdrv_query_image_info() Stefan Hajnoczi
` (4 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori, Wenchao Xia, Stefan Hajnoczi
From: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
This patch adds function bdrv_query_snapshot_info_list(), which will
retrieve snapshot info of an image in qmp object format. The implementation
is based on the code moved from qemu-img.c with modification to fit more
for qmp based block layer API.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
block/qapi.c | 55 +++++++++++++++++++++++++++++++++++++++-------------
include/block/qapi.h | 4 +++-
qemu-img.c | 5 ++++-
3 files changed, 49 insertions(+), 15 deletions(-)
diff --git a/block/qapi.c b/block/qapi.c
index 794dbf8..1ed56da 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -26,29 +26,56 @@
#include "block/block_int.h"
#include "qmp-commands.h"
-void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info)
+/*
+ * Returns 0 on success, with *p_list either set to describe snapshot
+ * information, or NULL because there are no snapshots. Returns -errno on
+ * error, with *p_list untouched.
+ */
+int bdrv_query_snapshot_info_list(BlockDriverState *bs,
+ SnapshotInfoList **p_list,
+ Error **errp)
{
int i, sn_count;
QEMUSnapshotInfo *sn_tab = NULL;
- SnapshotInfoList *info_list, *cur_item = NULL;
+ SnapshotInfoList *info_list, *cur_item = NULL, *head = NULL;
+ SnapshotInfo *info;
+
sn_count = bdrv_snapshot_list(bs, &sn_tab);
+ if (sn_count < 0) {
+ const char *dev = bdrv_get_device_name(bs);
+ switch (sn_count) {
+ case -ENOMEDIUM:
+ error_setg(errp, "Device '%s' is not inserted", dev);
+ break;
+ case -ENOTSUP:
+ error_setg(errp,
+ "Device '%s' does not support internal snapshots",
+ dev);
+ break;
+ default:
+ error_setg_errno(errp, -sn_count,
+ "Can't list snapshots of device '%s'", dev);
+ break;
+ }
+ return sn_count;
+ }
for (i = 0; i < sn_count; i++) {
- info->has_snapshots = true;
- info_list = g_new0(SnapshotInfoList, 1);
+ info = g_new0(SnapshotInfo, 1);
+ info->id = g_strdup(sn_tab[i].id_str);
+ info->name = g_strdup(sn_tab[i].name);
+ info->vm_state_size = sn_tab[i].vm_state_size;
+ info->date_sec = sn_tab[i].date_sec;
+ info->date_nsec = sn_tab[i].date_nsec;
+ info->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000;
+ info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000;
- info_list->value = g_new0(SnapshotInfo, 1);
- info_list->value->id = g_strdup(sn_tab[i].id_str);
- info_list->value->name = g_strdup(sn_tab[i].name);
- info_list->value->vm_state_size = sn_tab[i].vm_state_size;
- info_list->value->date_sec = sn_tab[i].date_sec;
- info_list->value->date_nsec = sn_tab[i].date_nsec;
- info_list->value->vm_clock_sec = sn_tab[i].vm_clock_nsec / 1000000000;
- info_list->value->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000;
+ info_list = g_new0(SnapshotInfoList, 1);
+ info_list->value = info;
/* XXX: waiting for the qapi to support qemu-queue.h types */
if (!cur_item) {
- info->snapshots = cur_item = info_list;
+ head = cur_item = info_list;
} else {
cur_item->next = info_list;
cur_item = info_list;
@@ -57,6 +84,8 @@ void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info)
}
g_free(sn_tab);
+ *p_list = head;
+ return 0;
}
void bdrv_collect_image_info(BlockDriverState *bs,
diff --git a/include/block/qapi.h b/include/block/qapi.h
index e6e568d..4f223d1 100644
--- a/include/block/qapi.h
+++ b/include/block/qapi.h
@@ -29,7 +29,9 @@
#include "block/block.h"
#include "block/snapshot.h"
-void bdrv_collect_snapshots(BlockDriverState *bs , ImageInfo *info);
+int bdrv_query_snapshot_info_list(BlockDriverState *bs,
+ SnapshotInfoList **p_list,
+ Error **errp);
void bdrv_collect_image_info(BlockDriverState *bs,
ImageInfo *info,
const char *filename);
diff --git a/qemu-img.c b/qemu-img.c
index e089c78..e3d8fe3 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1667,7 +1667,10 @@ static ImageInfoList *collect_image_info_list(const char *filename,
info = g_new0(ImageInfo, 1);
bdrv_collect_image_info(bs, info, filename);
- bdrv_collect_snapshots(bs, info);
+ bdrv_query_snapshot_info_list(bs, &info->snapshots, NULL);
+ if (info->snapshots) {
+ info->has_snapshots = true;
+ }
elem = g_new0(ImageInfoList, 1);
elem->value = info;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 23/26] block: add image info query function bdrv_query_image_info()
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (21 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 22/26] block: add snapshot info query function bdrv_query_snapshot_info_list() Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 24/26] qmp: add ImageInfo in BlockDeviceInfo used by query-block Stefan Hajnoczi
` (3 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori, Wenchao Xia, Stefan Hajnoczi
From: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
This patch adds function bdrv_query_image_info(), which will
retrieve image info in qmp object format. The implementation is
based on the code moved from qemu-img.c, but uses block layer
function to get snapshot info.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
block/qapi.c | 43 +++++++++++++++++++++++++++++++++++++------
include/block/qapi.h | 6 +++---
qemu-img.c | 11 ++++++-----
3 files changed, 46 insertions(+), 14 deletions(-)
diff --git a/block/qapi.c b/block/qapi.c
index 1ed56da..e9d8b74 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -88,18 +88,29 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
return 0;
}
-void bdrv_collect_image_info(BlockDriverState *bs,
- ImageInfo *info,
- const char *filename)
+/**
+ * bdrv_query_image_info:
+ * @bs: block device to examine
+ * @p_info: location to store image information
+ * @errp: location to store error information
+ *
+ * @p_info will be set only on success. On error, store error in @errp.
+ */
+void bdrv_query_image_info(BlockDriverState *bs,
+ ImageInfo **p_info,
+ Error **errp)
{
uint64_t total_sectors;
- char backing_filename[1024];
+ const char *backing_filename;
char backing_filename2[1024];
BlockDriverInfo bdi;
+ int ret;
+ Error *err = NULL;
+ ImageInfo *info = g_new0(ImageInfo, 1);
bdrv_get_geometry(bs, &total_sectors);
- info->filename = g_strdup(filename);
+ info->filename = g_strdup(bs->filename);
info->format = g_strdup(bdrv_get_format_name(bs));
info->virtual_size = total_sectors * 512;
info->actual_size = bdrv_get_allocated_file_size(bs);
@@ -116,7 +127,7 @@ void bdrv_collect_image_info(BlockDriverState *bs,
info->dirty_flag = bdi.is_dirty;
info->has_dirty_flag = true;
}
- bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
+ backing_filename = bs->backing_file;
if (backing_filename[0] != '\0') {
info->backing_filename = g_strdup(backing_filename);
info->has_backing_filename = true;
@@ -134,6 +145,26 @@ void bdrv_collect_image_info(BlockDriverState *bs,
info->has_backing_filename_format = true;
}
}
+
+ ret = bdrv_query_snapshot_info_list(bs, &info->snapshots, &err);
+ switch (ret) {
+ case 0:
+ if (info->snapshots) {
+ info->has_snapshots = true;
+ }
+ break;
+ /* recoverable error */
+ case -ENOMEDIUM:
+ case -ENOTSUP:
+ error_free(err);
+ break;
+ default:
+ error_propagate(errp, err);
+ qapi_free_ImageInfo(info);
+ return;
+ }
+
+ *p_info = info;
}
BlockInfo *bdrv_query_info(BlockDriverState *bs)
diff --git a/include/block/qapi.h b/include/block/qapi.h
index 4f223d1..ab1f48f 100644
--- a/include/block/qapi.h
+++ b/include/block/qapi.h
@@ -32,9 +32,9 @@
int bdrv_query_snapshot_info_list(BlockDriverState *bs,
SnapshotInfoList **p_list,
Error **errp);
-void bdrv_collect_image_info(BlockDriverState *bs,
- ImageInfo *info,
- const char *filename);
+void bdrv_query_image_info(BlockDriverState *bs,
+ ImageInfo **p_info,
+ Error **errp);
BlockInfo *bdrv_query_info(BlockDriverState *s);
BlockStats *bdrv_query_stats(const BlockDriverState *bs);
diff --git a/qemu-img.c b/qemu-img.c
index e3d8fe3..809b4f1 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1644,6 +1644,7 @@ static ImageInfoList *collect_image_info_list(const char *filename,
ImageInfoList *head = NULL;
ImageInfoList **last = &head;
GHashTable *filenames;
+ Error *err = NULL;
filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL);
@@ -1665,11 +1666,11 @@ static ImageInfoList *collect_image_info_list(const char *filename,
goto err;
}
- info = g_new0(ImageInfo, 1);
- bdrv_collect_image_info(bs, info, filename);
- bdrv_query_snapshot_info_list(bs, &info->snapshots, NULL);
- if (info->snapshots) {
- info->has_snapshots = true;
+ bdrv_query_image_info(bs, &info, &err);
+ if (error_is_set(&err)) {
+ error_report("%s", error_get_pretty(err));
+ error_free(err);
+ goto err;
}
elem = g_new0(ImageInfoList, 1);
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 24/26] qmp: add ImageInfo in BlockDeviceInfo used by query-block
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (22 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 23/26] block: add image info query function bdrv_query_image_info() Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 25/26] hmp: show ImageInfo in 'info block' Stefan Hajnoczi
` (2 subsequent siblings)
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori, Wenchao Xia, Stefan Hajnoczi
From: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Now image info will be retrieved as an embbed json object inside
BlockDeviceInfo, backing chain info and all related internal snapshot
info can be got in the enhanced recursive structure of ImageInfo. New
recursive member *backing-image is added to reflect the backing chain
status.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
block/qapi.c | 50 ++++++++++++++++++++++++++++++++++---
include/block/qapi.h | 4 ++-
qapi-schema.json | 10 ++++++--
qmp-commands.hx | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 125 insertions(+), 8 deletions(-)
diff --git a/block/qapi.c b/block/qapi.c
index e9d8b74..a4bc411 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -94,6 +94,13 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
* @p_info: location to store image information
* @errp: location to store error information
*
+ * Store "flat" image information in @p_info.
+ *
+ * "Flat" means it does *not* query backing image information,
+ * i.e. (*pinfo)->has_backing_image will be set to false and
+ * (*pinfo)->backing_image to NULL even when the image does in fact have
+ * a backing image.
+ *
* @p_info will be set only on success. On error, store error in @errp.
*/
void bdrv_query_image_info(BlockDriverState *bs,
@@ -167,9 +174,15 @@ void bdrv_query_image_info(BlockDriverState *bs,
*p_info = info;
}
-BlockInfo *bdrv_query_info(BlockDriverState *bs)
+/* @p_info will be set only on success. */
+void bdrv_query_info(BlockDriverState *bs,
+ BlockInfo **p_info,
+ Error **errp)
{
BlockInfo *info = g_malloc0(sizeof(*info));
+ BlockDriverState *bs0;
+ ImageInfo **p_image_info;
+ Error *local_err = NULL;
info->device = g_strdup(bs->device_name);
info->type = g_strdup("unknown");
info->locked = bdrv_dev_is_medium_locked(bs);
@@ -223,8 +236,30 @@ BlockInfo *bdrv_query_info(BlockDriverState *bs)
info->inserted->iops_wr =
bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE];
}
+
+ bs0 = bs;
+ p_image_info = &info->inserted->image;
+ while (1) {
+ bdrv_query_image_info(bs0, p_image_info, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ goto err;
+ }
+ if (bs0->drv && bs0->backing_hd) {
+ bs0 = bs0->backing_hd;
+ (*p_image_info)->has_backing_image = true;
+ p_image_info = &((*p_image_info)->backing_image);
+ } else {
+ break;
+ }
+ }
}
- return info;
+
+ *p_info = info;
+ return;
+
+ err:
+ qapi_free_BlockInfo(info);
}
BlockStats *bdrv_query_stats(const BlockDriverState *bs)
@@ -261,16 +296,25 @@ BlockInfoList *qmp_query_block(Error **errp)
{
BlockInfoList *head = NULL, **p_next = &head;
BlockDriverState *bs = NULL;
+ Error *local_err = NULL;
while ((bs = bdrv_next(bs))) {
BlockInfoList *info = g_malloc0(sizeof(*info));
- info->value = bdrv_query_info(bs);
+ bdrv_query_info(bs, &info->value, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ goto err;
+ }
*p_next = info;
p_next = &info->next;
}
return head;
+
+ err:
+ qapi_free_BlockInfoList(head);
+ return NULL;
}
BlockStatsList *qmp_query_blockstats(Error **errp)
diff --git a/include/block/qapi.h b/include/block/qapi.h
index ab1f48f..0496cc9 100644
--- a/include/block/qapi.h
+++ b/include/block/qapi.h
@@ -35,7 +35,9 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
void bdrv_query_image_info(BlockDriverState *bs,
ImageInfo **p_info,
Error **errp);
-BlockInfo *bdrv_query_info(BlockDriverState *s);
+void bdrv_query_info(BlockDriverState *bs,
+ BlockInfo **p_info,
+ Error **errp);
BlockStats *bdrv_query_stats(const BlockDriverState *bs);
void bdrv_snapshot_dump(fprintf_function func_fprintf, void *f,
diff --git a/qapi-schema.json b/qapi-schema.json
index ef1f657..5ad6894 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -236,6 +236,8 @@
#
# @snapshots: #optional list of VM snapshots
#
+# @backing-image: #optional info of the backing image (since 1.6)
+#
# Since: 1.3
#
##
@@ -245,7 +247,8 @@
'*actual-size': 'int', 'virtual-size': 'int',
'*cluster-size': 'int', '*encrypted': 'bool',
'*backing-filename': 'str', '*full-backing-filename': 'str',
- '*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'] } }
+ '*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'],
+ '*backing-image': 'ImageInfo' } }
##
# @ImageCheck:
@@ -756,6 +759,8 @@
#
# @iops_wr: write I/O operations per second is specified
#
+# @image: the info of image used (since: 1.6)
+#
# Since: 0.14.0
#
# Notes: This interface is only found in @BlockInfo.
@@ -765,7 +770,8 @@
'*backing_file': 'str', 'backing_file_depth': 'int',
'encrypted': 'bool', 'encryption_key_missing': 'bool',
'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
- 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
+ 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
+ 'image': 'ImageInfo' } }
##
# @BlockDeviceIoStatus:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ffd130e..8cea5e5 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1704,6 +1704,47 @@ Each json-object contain the following:
- "iops": limit total I/O operations per second (json-int)
- "iops_rd": limit read operations per second (json-int)
- "iops_wr": limit write operations per second (json-int)
+ - "image": the detail of the image, it is a json-object containing
+ the following:
+ - "filename": image file name (json-string)
+ - "format": image format (json-string)
+ - "virtual-size": image capacity in bytes (json-int)
+ - "dirty-flag": true if image is not cleanly closed, not present
+ means clean (json-bool, optional)
+ - "actual-size": actual size on disk in bytes of the image, not
+ present when image does not support thin
+ provision (json-int, optional)
+ - "cluster-size": size of a cluster in bytes, not present if image
+ format does not support it (json-int, optional)
+ - "encrypted": true if the image is encrypted, not present means
+ false or the image format does not support
+ encryption (json-bool, optional)
+ - "backing_file": backing file name, not present means no backing
+ file is used or the image format does not
+ support backing file chain
+ (json-string, optional)
+ - "full-backing-filename": full path of the backing file, not
+ present if it equals backing_file or no
+ backing file is used
+ (json-string, optional)
+ - "backing-filename-format": the format of the backing file, not
+ present means unknown or no backing
+ file (json-string, optional)
+ - "snapshots": the internal snapshot info, it is an optional list
+ of json-object containing the following:
+ - "id": unique snapshot id (json-string)
+ - "name": snapshot name (json-string)
+ - "vm-state-size": size of the VM state in bytes (json-int)
+ - "date-sec": UTC date of the snapshot in seconds (json-int)
+ - "date-nsec": fractional part in nanoseconds to be used with
+ date-sec(json-int)
+ - "vm-clock-sec": VM clock relative to boot in seconds
+ (json-int)
+ - "vm-clock-nsec": fractional part in nanoseconds to be used
+ with vm-clock-sec (json-int)
+ - "backing-image": the detail of the backing image, it is an
+ optional json-object only present when a
+ backing image present for this image
- "io-status": I/O operation status, only present if the device supports it
and the VM is configured to stop on errors. It's always reset
@@ -1724,14 +1765,38 @@ Example:
"ro":false,
"drv":"qcow2",
"encrypted":false,
- "file":"disks/test.img",
- "backing_file_depth":0,
+ "file":"disks/test.qcow2",
+ "backing_file_depth":1,
"bps":1000000,
"bps_rd":0,
"bps_wr":0,
"iops":1000000,
"iops_rd":0,
"iops_wr":0,
+ "image":{
+ "filename":"disks/test.qcow2",
+ "format":"qcow2",
+ "virtual-size":2048000,
+ "backing_file":"base.qcow2",
+ "full-backing-filename":"disks/base.qcow2",
+ "backing-filename-format:"qcow2",
+ "snapshots":[
+ {
+ "id": "1",
+ "name": "snapshot1",
+ "vm-state-size": 0,
+ "date-sec": 10000200,
+ "date-nsec": 12,
+ "vm-clock-sec": 206,
+ "vm-clock-nsec": 30
+ }
+ ],
+ "backing-image":{
+ "filename":"disks/base.qcow2",
+ "format":"qcow2",
+ "virtual-size":2048000
+ }
+ }
},
"type":"unknown"
},
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 25/26] hmp: show ImageInfo in 'info block'
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (23 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 24/26] qmp: add ImageInfo in BlockDeviceInfo used by query-block Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 26/26] hmp: add parameters device and -v for info block Stefan Hajnoczi
2013-06-17 21:17 ` [Qemu-devel] [PULL 00/26] Block patches Anthony Liguori
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori, Wenchao Xia, Stefan Hajnoczi
From: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Now human monitor can show image details, include internal
snapshot and backing chain info for every block device.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hmp.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/hmp.c b/hmp.c
index 64e0baa..4fc3bfe 100644
--- a/hmp.c
+++ b/hmp.c
@@ -22,6 +22,7 @@
#include "qemu/sockets.h"
#include "monitor/monitor.h"
#include "ui/console.h"
+#include "block/qapi.h"
#include "qemu-io.h"
static void hmp_handle_error(Monitor *mon, Error **errp)
@@ -278,6 +279,7 @@ void hmp_info_cpus(Monitor *mon, const QDict *qdict)
void hmp_info_block(Monitor *mon, const QDict *qdict)
{
BlockInfoList *block_list, *info;
+ ImageInfo *image_info;
block_list = qmp_query_block(NULL);
@@ -319,6 +321,18 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
info->value->inserted->iops,
info->value->inserted->iops_rd,
info->value->inserted->iops_wr);
+
+ monitor_printf(mon, " images:\n");
+ image_info = info->value->inserted->image;
+ while (1) {
+ bdrv_image_info_dump((fprintf_function)monitor_printf, mon,
+ image_info);
+ if (image_info->has_backing_image) {
+ image_info = image_info->backing_image;
+ } else {
+ break;
+ }
+ }
} else {
monitor_printf(mon, " [not inserted]");
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [Qemu-devel] [PULL 26/26] hmp: add parameters device and -v for info block
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (24 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 25/26] hmp: show ImageInfo in 'info block' Stefan Hajnoczi
@ 2013-06-07 11:58 ` Stefan Hajnoczi
2013-06-17 21:17 ` [Qemu-devel] [PULL 00/26] Block patches Anthony Liguori
26 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-07 11:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Anthony Liguori, Wenchao Xia, Stefan Hajnoczi
From: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
With these parameters, user can choose the information to be showed,
to avoid message flood in the monitor.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hmp.c | 25 ++++++++++++++++---------
monitor.c | 7 ++++---
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/hmp.c b/hmp.c
index 4fc3bfe..494a9aa 100644
--- a/hmp.c
+++ b/hmp.c
@@ -280,10 +280,15 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
{
BlockInfoList *block_list, *info;
ImageInfo *image_info;
+ const char *device = qdict_get_try_str(qdict, "device");
+ bool verbose = qdict_get_try_bool(qdict, "verbose", 0);
block_list = qmp_query_block(NULL);
for (info = block_list; info; info = info->next) {
+ if (device && strcmp(device, info->value->device)) {
+ continue;
+ }
monitor_printf(mon, "%s: removable=%d",
info->value->device, info->value->removable);
@@ -322,15 +327,17 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
info->value->inserted->iops_rd,
info->value->inserted->iops_wr);
- monitor_printf(mon, " images:\n");
- image_info = info->value->inserted->image;
- while (1) {
- bdrv_image_info_dump((fprintf_function)monitor_printf, mon,
- image_info);
- if (image_info->has_backing_image) {
- image_info = image_info->backing_image;
- } else {
- break;
+ if (verbose) {
+ monitor_printf(mon, " images:\n");
+ image_info = info->value->inserted->image;
+ while (1) {
+ bdrv_image_info_dump((fprintf_function)monitor_printf,
+ mon, image_info);
+ if (image_info->has_backing_image) {
+ image_info = image_info->backing_image;
+ } else {
+ break;
+ }
}
}
} else {
diff --git a/monitor.c b/monitor.c
index 9d279b8..017411f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2472,9 +2472,10 @@ static mon_cmd_t info_cmds[] = {
},
{
.name = "block",
- .args_type = "",
- .params = "",
- .help = "show the block devices",
+ .args_type = "verbose:-v,device:B?",
+ .params = "[-v] [device]",
+ .help = "show info of one block device or all block devices "
+ "(and details of images with -v option)",
.mhandler.cmd = hmp_info_block,
},
{
--
1.8.1.4
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [Qemu-devel] [PULL 20/26] ide: Set BSY bit during FLUSH
2013-06-07 11:58 ` [Qemu-devel] [PULL 20/26] ide: Set BSY bit during FLUSH Stefan Hajnoczi
@ 2013-06-07 12:10 ` Paolo Bonzini
0 siblings, 0 replies; 33+ messages in thread
From: Paolo Bonzini @ 2013-06-07 12:10 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: Kevin Wolf, Anthony Liguori, qemu-stable, qemu-devel,
Andreas Färber
Il 07/06/2013 07:58, Stefan Hajnoczi ha scritto:
> From: Andreas Färber <afaerber@suse.de>
>
> The implementation of the ATA FLUSH command invokes a flush at the block
> layer, which may on raw files on POSIX entail a synchronous fdatasync().
> This may in some cases take so long that the SLES 11 SP1 guest driver
> reports I/O errors and filesystems get corrupted or remounted read-only.
>
> Avoid this by setting BUSY_STAT, so that the guest is made aware we are
> in the middle of an operation and no ATA commands are attempted to be
> processed concurrently.
>
> Addresses BNC#637297.
>
> Suggested-by: Gonglei (Arei) <arei.gonglei@huawei.com>
> Signed-off-by: Andreas Färber <afaerber@suse.de>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
> hw/ide/core.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/hw/ide/core.c b/hw/ide/core.c
> index c7a8041..9926d92 100644
> --- a/hw/ide/core.c
> +++ b/hw/ide/core.c
> @@ -814,6 +814,7 @@ void ide_flush_cache(IDEState *s)
> return;
> }
>
> + s->status |= BUSY_STAT;
> bdrv_acct_start(s->bs, &s->acct, 0, BDRV_ACCT_FLUSH);
> bdrv_aio_flush(s->bs, ide_flush_cb, s);
> }
>
Cc: qemu-stable@nongnu.org
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case
2013-06-07 11:58 ` [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case Stefan Hajnoczi
@ 2013-06-14 17:54 ` Peter Maydell
2013-06-14 18:11 ` Peter Maydell
0 siblings, 1 reply; 33+ messages in thread
From: Peter Maydell @ 2013-06-14 17:54 UTC (permalink / raw)
To: Stefan Hajnoczi; +Cc: Kevin Wolf, Anthony Liguori, qemu-devel
On 7 June 2013 12:58, Stefan Hajnoczi <stefanha@redhat.com> wrote:
> From: Kevin Wolf <kwolf@redhat.com>
>
> This checks in particular that BSY is set while the flush request is in
> flight.
This test doesn't seem to pass. At commit bd07684aac
(where the test landed):
cam-vm-266:precise:qemu$ (cd build/x86;
QTEST_QEMU_BINARY=i386-softmmu/qemu-system-i386
MALLOC_PERTURB_=${MALLOC_PERTURB_:-$((RANDOM % 255 + 1))} gtester -k
--verbose -m=quick tests/ide-test)
TEST: tests/ide-test... (pid=25118)
/i386/ide/identify: OK
/i386/ide/bmdma/setup: OK
/i386/ide/bmdma/simple_rw: OK
/i386/ide/bmdma/short_prdt: OK
/i386/ide/bmdma/long_prdt: OK
/i386/ide/bmdma/teardown: OK
/i386/ide/flush:
blkdebug: Suspended request 'A'
blkdebug: Resuming request 'A'
**
ERROR:/home/petmay01/linaro/qemu-from-laptop/qemu/tests/ide-test.c:460:test_flush:
assertion failed ((data) & (BSY | DF | ERR | DRQ) == 0): (0x00000080
== 0x00000000)
FAIL
GTester: last random seed: R02S67ac87128346f4ba02226525fc3ecccf
(pid=25136)
FAIL: tests/ide-test
thanks
-- PMM
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case
2013-06-14 17:54 ` Peter Maydell
@ 2013-06-14 18:11 ` Peter Maydell
2013-06-14 18:18 ` Anthony Liguori
0 siblings, 1 reply; 33+ messages in thread
From: Peter Maydell @ 2013-06-14 18:11 UTC (permalink / raw)
To: Stefan Hajnoczi; +Cc: Kevin Wolf, Anthony Liguori, qemu-devel
On 14 June 2013 18:54, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 7 June 2013 12:58, Stefan Hajnoczi <stefanha@redhat.com> wrote:
>> From: Kevin Wolf <kwolf@redhat.com>
>>
>> This checks in particular that BSY is set while the flush request is in
>> flight.
>
> This test doesn't seem to pass.
> ERROR:/home/petmay01/linaro/qemu-from-laptop/qemu/tests/ide-test.c:460:test_flush:
> assertion failed ((data) & (BSY | DF | ERR | DRQ) == 0): (0x00000080
> == 0x00000000)
...fixed by http://patchwork.ozlabs.org/patch/250334/
thanks
-- PMM
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case
2013-06-14 18:11 ` Peter Maydell
@ 2013-06-14 18:18 ` Anthony Liguori
2013-06-17 12:45 ` Stefan Hajnoczi
0 siblings, 1 reply; 33+ messages in thread
From: Anthony Liguori @ 2013-06-14 18:18 UTC (permalink / raw)
To: Peter Maydell, Stefan Hajnoczi; +Cc: Kevin Wolf, qemu-devel
Peter Maydell <peter.maydell@linaro.org> writes:
> On 14 June 2013 18:54, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 7 June 2013 12:58, Stefan Hajnoczi <stefanha@redhat.com> wrote:
>>> From: Kevin Wolf <kwolf@redhat.com>
>>>
>>> This checks in particular that BSY is set while the flush request is in
>>> flight.
>>
>> This test doesn't seem to pass.
>
>> ERROR:/home/petmay01/linaro/qemu-from-laptop/qemu/tests/ide-test.c:460:test_flush:
>> assertion failed ((data) & (BSY | DF | ERR | DRQ) == 0): (0x00000080
>> == 0x00000000)
>
> ...fixed by http://patchwork.ozlabs.org/patch/250334/
I'm testing it myself now. Since it's already in the block tree, I'll
push it directly as it's blocking my queue.
Unless Kevin or Stefan are planning on sending a pull request today of
course.
Regards,
Anthony Liguori
>
> thanks
> -- PMM
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case
2013-06-14 18:18 ` Anthony Liguori
@ 2013-06-17 12:45 ` Stefan Hajnoczi
0 siblings, 0 replies; 33+ messages in thread
From: Stefan Hajnoczi @ 2013-06-17 12:45 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Kevin Wolf, Peter Maydell, qemu-devel, Stefan Hajnoczi
On Fri, Jun 14, 2013 at 01:18:44PM -0500, Anthony Liguori wrote:
> Peter Maydell <peter.maydell@linaro.org> writes:
>
> > On 14 June 2013 18:54, Peter Maydell <peter.maydell@linaro.org> wrote:
> >> On 7 June 2013 12:58, Stefan Hajnoczi <stefanha@redhat.com> wrote:
> >>> From: Kevin Wolf <kwolf@redhat.com>
> >>>
> >>> This checks in particular that BSY is set while the flush request is in
> >>> flight.
> >>
> >> This test doesn't seem to pass.
> >
> >> ERROR:/home/petmay01/linaro/qemu-from-laptop/qemu/tests/ide-test.c:460:test_flush:
> >> assertion failed ((data) & (BSY | DF | ERR | DRQ) == 0): (0x00000080
> >> == 0x00000000)
> >
> > ...fixed by http://patchwork.ozlabs.org/patch/250334/
>
> I'm testing it myself now. Since it's already in the block tree, I'll
> push it directly as it's blocking my queue.
>
> Unless Kevin or Stefan are planning on sending a pull request today of
> course.
Thanks for merging mdroth's fix!
Stefan
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [Qemu-devel] [PULL 00/26] Block patches
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
` (25 preceding siblings ...)
2013-06-07 11:58 ` [Qemu-devel] [PULL 26/26] hmp: add parameters device and -v for info block Stefan Hajnoczi
@ 2013-06-17 21:17 ` Anthony Liguori
26 siblings, 0 replies; 33+ messages in thread
From: Anthony Liguori @ 2013-06-17 21:17 UTC (permalink / raw)
To: Stefan Hajnoczi, qemu-devel; +Cc: Anthony Liguori
Pulled. Thanks.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2013-06-17 21:18 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-07 11:58 [Qemu-devel] [PULL 00/26] Block patches Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 01/26] blockdev: reset werror/rerror on drive_del Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 02/26] qemu-io: Remove unused args_command Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 03/26] cutils: Support 'P' and 'E' suffixes in strtosz() Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 04/26] qemu-io: Make cvtnum() a wrapper around strtosz_suffix() Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 05/26] qemu-io: Handle cvtnum() errors in 'alloc' Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 06/26] qemu-io: Don't use global bs in command implementations Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 07/26] qemu-io: Split off commands to qemu-io-cmds.c Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 08/26] qemu-io: Factor out qemuio_command Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 09/26] qemu-io: Move 'help' function Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 10/26] qemu-io: Move 'quit' function Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 11/26] qemu-io: Move qemu_strsep() to cutils.c Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 12/26] qemu-io: Move functions for registering and running commands Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 13/26] qemu-io: Move command_loop() and friends Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 14/26] qemu-io: Move remaining helpers from cmd.c Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 15/26] qemu-io: Interface cleanup Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 16/26] qemu-io: Use the qemu version for -V Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 17/26] Make qemu-io commands available in HMP Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 18/26] blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 19/26] ide-test: Add enum value for DEV Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 20/26] ide: Set BSY bit during FLUSH Stefan Hajnoczi
2013-06-07 12:10 ` Paolo Bonzini
2013-06-07 11:58 ` [Qemu-devel] [PULL 21/26] ide-test: Add FLUSH CACHE test case Stefan Hajnoczi
2013-06-14 17:54 ` Peter Maydell
2013-06-14 18:11 ` Peter Maydell
2013-06-14 18:18 ` Anthony Liguori
2013-06-17 12:45 ` Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 22/26] block: add snapshot info query function bdrv_query_snapshot_info_list() Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 23/26] block: add image info query function bdrv_query_image_info() Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 24/26] qmp: add ImageInfo in BlockDeviceInfo used by query-block Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 25/26] hmp: show ImageInfo in 'info block' Stefan Hajnoczi
2013-06-07 11:58 ` [Qemu-devel] [PULL 26/26] hmp: add parameters device and -v for info block Stefan Hajnoczi
2013-06-17 21:17 ` [Qemu-devel] [PULL 00/26] Block patches Anthony Liguori
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).