[libvirt] RFC (v4): Add virDomainBlockPull API family to libvirt
by Adam Litke
This round addresses all review comments from the last posting and should be
ready for inclusion. Thanks for the review.
Changes since V3:
- Don't check flags at the libvirt API level
- qemu: Check disk->type before looking up alias
- virsh: Merge blockpullall into blockpull
- event: Drop events for unknown disk paths
- Misc style fixes and comment updates
Changes since V2:
- Rebased
- Ensure error messages are consistent between JSON and Text interfaces
- Added additional tests to the sample test bucket
Changes since V1:
- Rebased to incorporate changes to generator and
removal of static driver structure initializers
- Other small fixups suggested by Matthias Bolte
To help speed the provisioning process for large domains, new QED disks are
created with backing to a template image. These disks are configured with copy
on read such that blocks that are read from the backing file are copied to the
new disk. This reduces I/O over a potentially costly path to the backing
image.
In such a configuration, there is a desire to remove the dependency on the
backing image as the domain runs. To accomplish this, qemu will provide an
interface to perform sequential copy on read operations during normal VM
operation. Once all data has been copied, the disk image's link to the backing
file is removed.
The virDomainBlockPull API family brings this functionality to libvirt.
virDomainBlockPullAll() instructs the hypervisor to stream the entire device in
the background. Progress of this operation can be checked with the function
virDomainBlockPullInfo(). An ongoing stream can be cancelled with
virDomainBlockPullAbort(). If a more controlled IO rate is desired,
virDomainBlockPull() can be used to perform a single increment of IO.
Subsequent calls to this function will automatically stream the appropriate
next increment until the disk has been fully populated.
An event (VIR_DOMAIN_EVENT_ID_BLOCK_PULL) will be emitted when a disk has been
fully populated or if a BlockPullAll() operation was terminated due to an
error. This event is useful to avoid polling on virDomainBlockPullInfo() for
completion and could also be used by the security driver to revoke access to
the backing file when it is no longer needed.
make check: PASS
make syntax-check: PASS
make -C tests valgrind: PASS
I am testing this API with Python Unittest (see the last patch).
[PATCH 1/8] Add new API virDomainBlockPull* to headers
[PATCH 2/8] virDomainBlockPull: Implement the main entry points
[PATCH 3/8] Add virDomainBlockPull support to the remote driver
[PATCH 4/8] Implement virDomainBlockPull for the qemu driver
[PATCH 5/8] Enable the virDomainBlockPull API in virsh
[PATCH 6/8] Enable virDomainBlockPull in the python API.
[PATCH 7/8] Asynchronous event for BlockPull completion
[PATCH 8/8] test: Python Unittests for DomainBlockPull API
13 years, 5 months
[libvirt] [PATCH] sendkey: use consistent API convention
by Eric Blake
Even though rpc uses 'unsigned int' for the _val parameter that
passes the length of item<length>, the public libvirt APIs all
use 'int' and filter out lengths < 0, except for virDomainSendKey.
* include/libvirt/libvirt.h.in (virDomainSendKey): All other APIs
use int for array length.
* src/libvirt.c (virDomainSendKey): Adjust.
* src/driver.h (virDrvDomainSendKey): Likewise.
* daemon/remote_generator.pl: Likewise.
---
One approach to a question first raised here.
https://www.redhat.com/archives/libvir-list/2011-June/msg00681.html
The other approach would be to change all libvirt API to use
unsigned int for array sizes, to match rpc conventions and to
simplify code to not have to worry about negative sizes, but
that is more invasive.
daemon/remote_generator.pl | 2 +-
include/libvirt/libvirt.h.in | 2 +-
src/driver.h | 2 +-
src/libvirt.c | 4 ++--
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl
index 351866b..afec66c 100755
--- a/daemon/remote_generator.pl
+++ b/daemon/remote_generator.pl
@@ -1007,7 +1007,7 @@ elsif ($opt_k) {
my $limit = $3;
push(@args_list, "${type_name} *$arg_name");
- push(@args_list, "unsigned int ${arg_name}len");
+ push(@args_list, "int ${arg_name}len");
push(@setters_list, "args.$arg_name.${arg_name}_val = $arg_name;");
push(@setters_list, "args.$arg_name.${arg_name}_len = ${arg_name}len;");
push(@args_check_list, { name => "\"$arg_name\"", arg => "${arg_name}len", limit => $limit });
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index ab22046..c684297 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1788,7 +1788,7 @@ int virDomainSendKey(virDomainPtr domain,
unsigned int codeset,
unsigned int holdtime,
unsigned int *keycodes,
- unsigned int nkeycodes,
+ int nkeycodes,
unsigned int flags);
/*
diff --git a/src/driver.h b/src/driver.h
index d45575a..c880222 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -568,7 +568,7 @@ typedef int
(*virDrvDomainSendKey)(virDomainPtr dom, unsigned int codeset,
unsigned int holdtime,
unsigned int *keycodes,
- unsigned int nkeycodes,
+ int nkeycodes,
unsigned int flags);
typedef char *
diff --git a/src/libvirt.c b/src/libvirt.c
index 36a90d1..b2e1d02 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -6653,7 +6653,7 @@ int virDomainSendKey(virDomainPtr domain,
unsigned int codeset,
unsigned int holdtime,
unsigned int *keycodes,
- unsigned int nkeycodes,
+ int nkeycodes,
unsigned int flags)
{
virConnectPtr conn;
@@ -6663,7 +6663,7 @@ int virDomainSendKey(virDomainPtr domain,
virResetLastError();
if (keycodes == NULL ||
- nkeycodes == 0 || nkeycodes > VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
+ nkeycodes <= 0 || nkeycodes > VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
virLibDomainError(VIR_ERR_OPERATION_INVALID, __FUNCTION__);
virDispatchError(NULL);
return -1;
--
1.7.4.4
13 years, 5 months
[libvirt] [PATCH] build: export correct function names
by Eric Blake
Detected by autobuild.sh, when targetting mingw.
* src/libvirt_private.syms: Fix typos.
---
Pushing under the trivial rule.
src/libvirt_private.syms | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ab110a3..5202da3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -274,8 +274,8 @@ virDomainGraphicsSpiceChannelModeTypeFromString;
virDomainGraphicsSpiceChannelModeTypeToString;
virDomainGraphicsSpiceChannelNameTypeFromString;
virDomainGraphicsSpiceChannelNameTypeToString;
-virDomainGraphicsSpiceClipboardCopypasteFromString;
-virDomainGraphicsSpiceClipboardCopypasteToString;
+virDomainGraphicsSpiceClipboardCopypasteTypeFromString;
+virDomainGraphicsSpiceClipboardCopypasteTypeToString;
virDomainGraphicsSpiceImageCompressionTypeFromString;
virDomainGraphicsSpiceImageCompressionTypeToString;
virDomainGraphicsSpiceJpegCompressionTypeFromString;
--
1.7.4.4
13 years, 5 months
[libvirt] [PATCH] build: avoid compiler warning on non-Linux
by Eric Blake
Detected by autobuild.sh when cross-building for mingw.
* src/nodeinfo.c (nodeGetCPUStats, nodeGetMemoryStats): Mark
parameters as potentially unused.
---
Pushing under the build-breaker rule.
src/nodeinfo.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index cb2f805..647cb1e 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -636,9 +636,9 @@ int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
}
int nodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
- int cpuNum,
- virCPUStatsPtr params,
- int *nparams,
+ int cpuNum ATTRIBUTE_UNUSED,
+ virCPUStatsPtr params ATTRIBUTE_UNUSED,
+ int *nparams ATTRIBUTE_UNUSED,
unsigned int flags)
{
virCheckFlags(0, -1);
@@ -665,9 +665,9 @@ int nodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
}
int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
- int cellNum,
- virMemoryStatsPtr params,
- int *nparams,
+ int cellNum ATTRIBUTE_UNUSED,
+ virMemoryStatsPtr params ATTRIBUTE_UNUSED,
+ int *nparams ATTRIBUTE_UNUSED,
unsigned int flags)
{
virCheckFlags(0, -1);
--
1.7.4.4
13 years, 5 months
[libvirt] [PATCH] remote generator: Handle struct returning functions better (part 2)
by Matthias Bolte
Commit 64000eabedf2 is part 1, that only covered the daemon side by
accident. Part 2 covers the client side too.
---
daemon/remote_generator.pl | 17 +++++------------
1 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl
index 351866b..bcf5fd4 100755
--- a/daemon/remote_generator.pl
+++ b/daemon/remote_generator.pl
@@ -1225,21 +1225,14 @@ elsif ($opt_k) {
# select struct type for multi-return-value functions
if ($multi_ret) {
- my $last_arg;
- my $struct_name = $call->{ProcName};
- $struct_name =~ s/Get//;
-
- if ($call->{ProcName} eq "DomainGetBlockInfo") {
- # SPECIAL: virDomainGetBlockInfo has flags parameter after
- # the struct parameter in its signature
- $last_arg = pop(@args_list);
+ if (!(defined $call->{ret_offset})) {
+ die "multi-return-value without insert@<offset> annotation: $call->{ret}";
}
- push(@args_list, "vir${struct_name}Ptr result");
+ my $struct_name = $call->{ProcName};
+ $struct_name =~ s/Get//;
- if (defined $last_arg) {
- push(@args_list, $last_arg);
- }
+ splice(@args_list, $call->{ret_offset}, 0, ("vir${struct_name}Ptr result"));
}
if ($call->{streamflag} ne "none") {
--
1.7.0.4
13 years, 5 months
[libvirt] [PATCH] Fix apibuild.py warnings about missing comment headers
by Matthias Bolte
Also improve wording of some comments.
---
include/libvirt/libvirt.h.in | 36 ++++++++++++++++++++++--------------
1 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 8ceafe5..cf1a682 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -318,33 +318,41 @@ struct _virNodeInfo {
/**
* VIR_CPU_STATS_KERNEL:
*
- * Macro for the cumulative CPU time which spends by kernel,
- * when the node booting up.(in nanoseconds).
+ * Macro for the cumulative CPU time which was spend by kernel,
+ * since the node booting up (in nanoseconds).
*/
#define VIR_CPU_STATS_KERNEL "kernel"
/**
- * The cumulative CPU time which spends by user processes,
- * when the node booting up.(in nanoseconds).
+ * VIR_CPU_STATS_USER:
+ *
+ * The cumulative CPU time which was spend by user processes,
+ * since the node booting up (in nanoseconds).
*/
#define VIR_CPU_STATS_USER "user"
/**
+ * VIR_CPU_STATS_IDLE:
+ *
* The cumulative idle CPU time,
- * when the node booting up.(in nanoseconds).
+ * since the node booting up (in nanoseconds).
*/
#define VIR_CPU_STATS_IDLE "idle"
/**
+ * VIR_CPU_STATS_IOWAIT:
+ *
* The cumulative I/O wait CPU time,
- * when the node booting up.(in nanoseconds).
+ * since the node booting up (in nanoseconds).
*/
#define VIR_CPU_STATS_IOWAIT "iowait"
/**
- * The CPU utilization.
- * The usage value is in percent and 100% represents all CPUs on
- * the server.
+ * VIR_CPU_STATS_UTILIZATION:
+ *
+ * The CPU utilization of a node.
+ * The usage value is in percent and 100% represents all CPUs of
+ * the node.
*/
#define VIR_CPU_STATS_UTILIZATION "utilization"
@@ -352,7 +360,7 @@ struct _virNodeInfo {
* virCPUStats:
*
* a virNodeCPUStats is a structure filled by virNodeGetCPUStats()
- * and providing the information for the cpu stats of the node.
+ * providing information about the CPU stats of the node.
*/
typedef struct _virCPUStats virCPUStats;
@@ -388,7 +396,7 @@ struct _virCPUStats {
* VIR_MEMORY_STATS_FREE:
*
* Macro for the free memory of specified cell:
- * On linux, it includes buffer and cached memory, in case of
+ * On Linux, it includes buffer and cached memory, in case of
* VIR_MEMORY_STATS_ALL_CELLS.
*/
@@ -397,7 +405,7 @@ struct _virCPUStats {
/**
* VIR_MEMORY_STATS_BUFFERS:
*
- * Macro for the buffer memory: On linux, it only returns in case of
+ * Macro for the buffer memory: On Linux, it is only returned in case of
* VIR_MEMORY_STATS_ALL_CELLS.
*/
@@ -406,7 +414,7 @@ struct _virCPUStats {
/**
* VIR_MEMORY_STATS_CACHED:
*
- * Macro for the cached memory: On linux, it only returns in case of
+ * Macro for the cached memory: On Linux, it is only returned in case of
* VIR_MEMORY_STATS_ALL_CELLS.
*/
@@ -416,7 +424,7 @@ struct _virCPUStats {
* virMemoryStats:
*
* a virMemoryStats is a structure filled by virNodeGetMemoryStats()
- * and providing the information of the memory of the Node.
+ * providing information about the memory of the node.
*/
typedef struct _virMemoryStats virMemoryStats;
--
1.7.0.4
13 years, 5 months
[libvirt] [PATCH] remote generator: Handle struct returning functions better
by Matthias Bolte
The position of the struct parameter in the function signature
differs. Instead of hardcoding the handling for this add an annotation
to the .x file to define the position.
---
daemon/remote_generator.pl | 42 ++++++++++++++++++++++++------------------
src/remote/remote_protocol.x | 23 ++++++++++++++---------
2 files changed, 38 insertions(+), 27 deletions(-)
diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl
index ce35ebe..351866b 100755
--- a/daemon/remote_generator.pl
+++ b/daemon/remote_generator.pl
@@ -95,8 +95,9 @@ while (<PROTOCOL>) {
$collect_args_members = 1;
$collect_ret_members = 0;
$last_name = $name;
- } elsif (/^struct ${structprefix}_(.*)_ret/) {
+ } elsif (/^struct ${structprefix}_(.*)_ret\s+{(.*)$/) {
$name = $1;
+ $flags = $2;
$ProcName = name_to_ProcName ($name);
if (exists $calls{$name}) {
@@ -112,6 +113,14 @@ while (<PROTOCOL>) {
}
}
+ if ($flags ne "" and ($opt_b or $opt_k)) {
+ if (!($flags =~ m/^\s*\/\*\s*insert@(\d+)\s*\*\/\s*$/)) {
+ die "invalid generator flags for $calls{$name}->{ret}";
+ }
+
+ $calls{$name}->{ret_offset} = int($1);
+ }
+
$collect_args_members = 0;
$collect_ret_members = 1;
$last_name = $name;
@@ -668,29 +677,26 @@ elsif ($opt_b) {
# select struct type for multi-return-value functions
if ($multi_ret) {
- if (! @args_list) {
+ if (!(defined $call->{ret_offset})) {
+ die "multi-return-value without insert@<offset> annotation: $call->{ret}";
+ }
+
+ if (!@args_list) {
push(@args_list, "conn");
}
my $struct_name = $call->{ProcName};
$struct_name =~ s/Get//;
- if ($call->{ProcName} eq "DomainGetBlockInfo") {
- # SPECIAL: virDomainGetBlockInfo has flags parameter after
- # the struct parameter in its signature
- my $flags = pop(@args_list);
- push(@args_list, "&tmp");
- push(@args_list, $flags);
- } elsif ($call->{ProcName} eq "DomainBlockStats" ||
- $call->{ProcName} eq "DomainInterfaceStats") {
+ splice(@args_list, $call->{ret_offset}, 0, ("&tmp"));
+
+ if ($call->{ProcName} eq "DomainBlockStats" ||
+ $call->{ProcName} eq "DomainInterfaceStats") {
# SPECIAL: virDomainBlockStats and virDomainInterfaceStats
# have a 'Struct' suffix on the actual struct name
# and take the struct size as additional argument
$struct_name .= "Struct";
- push(@args_list, "&tmp");
- push(@args_list, "sizeof tmp");
- } else {
- push(@args_list, "&tmp");
+ splice(@args_list, $call->{ret_offset} + 1, 0, ("sizeof tmp"));
}
push(@vars_list, "vir$struct_name tmp");
@@ -1012,14 +1018,14 @@ elsif ($opt_k) {
" xdr_free((xdrproc_t)xdr_$call->{args}, (char *)&args);\n" .
" goto done;\n" .
" }");
- } elsif ($args_member =~ m/^(unsigned )?int (\S+);\s*\/\*\s*call-by-reference\s*\*\//) {
- my $type_name = $1; $type_name .= "int *";
+ } elsif ($args_member =~ m/^((?:unsigned )?int) (\S+);\s*\/\*\s*call-by-reference\s*\*\//) {
+ my $type_name = "$1 *";
my $arg_name = $2;
push(@args_list, "$type_name $arg_name");
push(@setters_list, "args.$arg_name = *$arg_name;");
- } elsif ($args_member =~ m/^(unsigned )?int (\S+);/) {
- my $type_name = $1; $type_name .= "int";
+ } elsif ($args_member =~ m/^((?:unsigned )?int) (\S+);/) {
+ my $type_name = $1;
my $arg_name = $2;
push(@args_list, "$type_name $arg_name");
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 0dd8b09..2b9784b 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -352,7 +352,12 @@ struct remote_node_get_memory_stats {
*
* 'remote_CALL_ret' members that are filled via call-by-reference must be
* annotated with a insert@<offset> comment to indicate the offset in the
- * parameter list of the function to be called. */
+ * parameter list of the function to be called.
+ *
+ * If the 'remote_CALL_ret' maps to a struct in the public API then it is
+ * also filled via call-by-reference and must be annotated with a
+ * insert@<offset> comment to indicate the offset in the parameter list of
+ * the function to be called. */
struct remote_open_args {
/* NB. "name" might be NULL although in practice you can't
@@ -409,7 +414,7 @@ struct remote_get_max_vcpus_ret {
int max_vcpus;
};
-struct remote_node_get_info_ret {
+struct remote_node_get_info_ret { /* insert@1 */
char model[32];
unsigned hyper memory;
int cpus;
@@ -537,7 +542,7 @@ struct remote_domain_block_stats_args {
remote_nonnull_string path;
};
-struct remote_domain_block_stats_ret {
+struct remote_domain_block_stats_ret { /* insert@2 */
hyper rd_req;
hyper rd_bytes;
hyper wr_req;
@@ -550,7 +555,7 @@ struct remote_domain_interface_stats_args {
remote_nonnull_string path;
};
-struct remote_domain_interface_stats_ret {
+struct remote_domain_interface_stats_ret { /* insert@2 */
hyper rx_bytes;
hyper rx_packets;
hyper rx_errs;
@@ -605,7 +610,7 @@ struct remote_domain_get_block_info_args {
unsigned int flags;
};
-struct remote_domain_get_block_info_ret {
+struct remote_domain_get_block_info_ret { /* insert@2 */
unsigned hyper allocation;
unsigned hyper capacity;
unsigned hyper physical;
@@ -713,7 +718,7 @@ struct remote_domain_get_info_args {
remote_nonnull_domain dom;
};
-struct remote_domain_get_info_ret {
+struct remote_domain_get_info_ret { /* insert@1 */
unsigned char state;
unsigned hyper maxMem;
unsigned hyper memory;
@@ -1400,7 +1405,7 @@ struct remote_storage_pool_get_info_args {
remote_nonnull_storage_pool pool;
};
-struct remote_storage_pool_get_info_ret {
+struct remote_storage_pool_get_info_ret { /* insert@1 */
unsigned char state;
unsigned hyper capacity;
unsigned hyper allocation;
@@ -1510,7 +1515,7 @@ struct remote_storage_vol_get_info_args {
remote_nonnull_storage_vol vol;
};
-struct remote_storage_vol_get_info_ret {
+struct remote_storage_vol_get_info_ret { /* insert@1 */
char type;
unsigned hyper capacity;
unsigned hyper allocation;
@@ -1827,7 +1832,7 @@ struct remote_domain_get_job_info_args {
remote_nonnull_domain dom;
};
-struct remote_domain_get_job_info_ret {
+struct remote_domain_get_job_info_ret { /* insert@1 */
int type;
unsigned hyper timeElapsed;
--
1.7.0.4
13 years, 5 months
[libvirt] [PATCH] support for Xen HVM Viridian (Hyper-V) enlightenment interface
by Daniel Gollub
Introduce libvirt support for Xen HVM Viridian (Hyper-V) enlightenment
interface guest feature.
---
src/conf/domain_conf.c | 3 ++-
src/conf/domain_conf.h | 1 +
src/xen/xen_hypervisor.c | 11 +++++++++++
src/xenapi/xenapi_driver.c | 2 ++
src/xenapi/xenapi_utils.c | 2 ++
src/xenxs/xen_sxpr.c | 4 ++++
src/xenxs/xen_xm.c | 12 +++++++++++-
7 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 0d9fef4..a90f676 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -84,7 +84,8 @@ VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST,
"acpi",
"apic",
"pae",
- "hap")
+ "hap",
+ "viridian")
VIR_ENUM_IMPL(virDomainLifecycle, VIR_DOMAIN_LIFECYCLE_LAST,
"destroy",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 41c8136..e591268 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -890,6 +890,7 @@ enum virDomainFeature {
VIR_DOMAIN_FEATURE_APIC,
VIR_DOMAIN_FEATURE_PAE,
VIR_DOMAIN_FEATURE_HAP,
+ VIR_DOMAIN_FEATURE_VIRIDIAN,
VIR_DOMAIN_FEATURE_LAST
};
diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c
index 21e6645..ff9c8cb 100644
--- a/src/xen/xen_hypervisor.c
+++ b/src/xen/xen_hypervisor.c
@@ -2401,7 +2401,18 @@ xenHypervisorBuildCapabilities(virConnectPtr conn,
0,
1) == NULL)
goto no_memory;
+
+ /* Xen 3.4.x and beyond supports the Viridian (Hyper-V)
+ * enlightenment interface. Default is off.
+ */
+ if ((hv_major == 3 && hv_minor >= 4) || (hv_major > 3))
+ if (virCapabilitiesAddGuestFeature(guest,
+ "viridian",
+ 0,
+ 1) == NULL)
+ goto no_memory;
}
+
}
caps->defaultConsoleTargetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c
index 6f64208..58e762f 100644
--- a/src/xenapi/xenapi_driver.c
+++ b/src/xenapi/xenapi_driver.c
@@ -1414,6 +1414,8 @@ xenapiDomainGetXMLDesc(virDomainPtr dom, int flags ATTRIBUTE_UNUSED)
defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_PAE);
else if (STREQ(result->contents[i].key, "hap"))
defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_HAP);
+ else if (STREQ(result->contents[i].key, "viridian"))
+ defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_VIRIDIAN);
}
}
xen_string_string_map_free(result);
diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c
index 9362cf1..342ae5b 100644
--- a/src/xenapi/xenapi_utils.c
+++ b/src/xenapi/xenapi_utils.c
@@ -536,6 +536,8 @@ createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def,
allocStringMap(&strings, (char *)"pae", (char *)"true");
if (def->features & (1 << VIR_DOMAIN_FEATURE_HAP))
allocStringMap(&strings, (char *)"hap", (char *)"true");
+ if (def->features & (1 << VIR_DOMAIN_FEATURE_VIRIDIAN))
+ allocStringMap(&strings, (char *)"viridian", (char *)"true");
}
if (strings != NULL)
(*record)->platform = strings;
diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c
index 59d585d..b5877bb 100644
--- a/src/xenxs/xen_sxpr.c
+++ b/src/xenxs/xen_sxpr.c
@@ -1171,6 +1171,8 @@ xenParseSxpr(const struct sexpr *root,
def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
if (sexpr_int(root, "domain/image/hvm/hap"))
def->features |= (1 << VIR_DOMAIN_FEATURE_HAP);
+ if (sexpr_int(root, "domain/image/hvm/viridian"))
+ def->features |= (1 << VIR_DOMAIN_FEATURE_VIRIDIAN);
/* Old XenD only allows localtime here for HVM */
if (sexpr_int(root, "domain/image/hvm/localtime"))
@@ -2166,6 +2168,8 @@ xenFormatSxpr(virConnectPtr conn,
virBufferAddLit(&buf, "(pae 1)");
if (def->features & (1 << VIR_DOMAIN_FEATURE_HAP))
virBufferAddLit(&buf, "(hap 1)");
+ if (def->features & (1 << VIR_DOMAIN_FEATURE_VIRIDIAN))
+ virBufferAddLit(&buf, "(viridian 1)");
virBufferAddLit(&buf, "(usb 1)");
diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c
index accf5f4..c9440fa 100644
--- a/src/xenxs/xen_xm.c
+++ b/src/xenxs/xen_xm.c
@@ -369,6 +369,10 @@ xenParseXM(virConfPtr conf, int xendConfigVersion,
goto cleanup;
else if (val)
def->features |= (1 << VIR_DOMAIN_FEATURE_HAP);
+ if (xenXMConfigGetBool(conf, "viridian", &val, 0) < 0)
+ goto cleanup;
+ else if (val)
+ def->features |= (1 << VIR_DOMAIN_FEATURE_VIRIDIAN);
if (xenXMConfigGetBool(conf, "hpet", &val, -1) < 0)
goto cleanup;
@@ -1507,12 +1511,18 @@ virConfPtr xenFormatXM(virConnectPtr conn,
(1 << VIR_DOMAIN_FEATURE_APIC)) ? 1 : 0) < 0)
goto no_memory;
- if (xendConfigVersion >= 3)
+ if (xendConfigVersion >= 3) {
if (xenXMConfigSetInt(conf, "hap",
(def->features &
(1 << VIR_DOMAIN_FEATURE_HAP)) ? 1 : 0) < 0)
goto no_memory;
+ if (xenXMConfigSetInt(conf, "viridian",
+ (def->features &
+ (1 << VIR_DOMAIN_FEATURE_VIRIDIAN)) ? 1 : 0) < 0)
+ goto no_memory;
+ }
+
if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
if (def->clock.data.timezone) {
XENXS_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
--
1.7.1
--
Daniel Gollub
Linux Consultant & Developer
Tel.: +49-160 47 73 970
Mail: gollub(a)b1-systems.de
B1 Systems GmbH
Osterfeldstraße 7 / 85088 Vohburg / http://www.b1-systems.de
GF: Ralph Dehner / Unternehmenssitz: Vohburg / AG: Ingolstadt,HRB 3537
13 years, 5 months
[libvirt] [PATCH] qemu: domain I/O asynchronous handling
by Michal Privoznik
For virtio disks and interfaces, qemu allows users to enable or disable
ioeventfd feature. This means, qemu can execute domain code, while
another thread waits for I/O event. Basically, in some cases it is win,
in some loss. This feature is available via 'asyncio' attribute in disk
and interface <driver> element. It accepts 'on' and 'off'. Leaving this
attribute out defaults to hypervisor decision.
---
this is rework as suggested:
https://www.redhat.com/archives/libvir-list/2011-May/msg01269.html
docs/formatdomain.html.in | 34 ++++++++++++-
docs/schemas/domain.rng | 14 +++++
src/conf/domain_conf.c | 49 ++++++++++++++++++-
src/conf/domain_conf.h | 11 ++++
src/libvirt_private.syms | 2 +
src/qemu/qemu_capabilities.c | 3 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 23 +++++++++
tests/qemuhelptest.c | 3 +-
.../qemuxml2argv-disk-asyncio.args | 11 ++++
.../qemuxml2argvdata/qemuxml2argv-disk-asyncio.xml | 51 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 3 +
12 files changed, 201 insertions(+), 4 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-asyncio.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-asyncio.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 98fb2b4..8d23740 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -767,7 +767,7 @@
</disk>
...
<disk type='network'>
- <driver name="qemu" type="raw" io="threads"/>
+ <driver name="qemu" type="raw" io="threads" asyncio="on"/>
<source protocol="sheepdog" name="image_name">
<host name="hostname" port="7000"/>
</source>
@@ -851,6 +851,20 @@
policies on I/O; qemu guests support "threads" and
"native". <span class="since">Since 0.8.8</span>
</li>
+ <li>
+ The optional <code>asyncio</code> attribute allows users to
+ set <a href='https://patchwork.kernel.org/patch/43390/'>
+ domain I/O asynchronous handling</a> for disk device.
+ The default is left to the discretion of the hypervisor.
+ Accepted values are "on" and "off". Enabling this allows
+ qemu to execute VM while a separate thread handles I/O.
+ Typically guests experiencing high system CPU utilization
+ during I/O will benefit from this. On the other hand,
+ on overloaded host it could increase guest I/O latency.
+ <span class="since">Since 0.9.3 (QEMU and KVM only)</span>
+ <b>In general you should leave this option alone, unless you
+ are very certain you know what you are doing.</b>
+ </li>
</ul>
</dd>
<dt><code>boot</code></dt>
@@ -1631,7 +1645,7 @@ qemu-kvm -net nic,model=? /dev/null
<source network='default'/>
<target dev='vnet1'/>
<model type='virtio'/>
- <b><driver name='vhost' txmode='iothread'/></b>
+ <b><driver name='vhost' txmode='iothread' asyncio='on'/></b>
</interface>
</devices>
...</pre>
@@ -1682,6 +1696,22 @@ qemu-kvm -net nic,model=? /dev/null
<b>In general you should leave this option alone, unless you
are very certain you know what you are doing.</b>
</dd>
+ <dt><code>asyncio</code></dt>
+ <dd>
+ This optional attribute allows users to set
+ <a href='https://patchwork.kernel.org/patch/43390/'>
+ domain I/O asynchronous handling</a> for interface device.
+ The default is left to the discretion of the hypervisor.
+ Accepted values are "on" and "off". Enabling this allows
+ qemu to execute VM while a separate thread handles I/O.
+ Typically guests experiencing high system CPU utilization
+ during I/O will benefit from this. On the other hand,
+ on overloaded host it could increase guest I/O latency.
+ <span class="since">Since 0.9.3 (QEMU and KVM only)</span><br/><br/>
+
+ <b>In general you should leave this option alone, unless you
+ are very certain you know what you are doing.</b>
+ </dd>
</dl>
<h5><a name="elementsNICSTargetOverride">Overriding the target element</a></h5>
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 0be0371..08b92ed 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -758,6 +758,9 @@
<optional>
<ref name="driverIO"/>
</optional>
+ <optional>
+ <ref name="asyncIO"/>
+ </optional>
<empty/>
</element>
</define>
@@ -797,6 +800,14 @@
</choice>
</attribute>
</define>
+ <define name="asyncIO">
+ <attribute name="asyncio">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+ </define>
<define name="controller">
<element name="controller">
<choice>
@@ -1097,6 +1108,9 @@
</choice>
</attribute>
</optional>
+ <optional>
+ <ref name="asyncIO"/>
+ </optional>
<empty/>
</element>
</optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 65d4f89..2b81f2b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -163,6 +163,11 @@ VIR_ENUM_IMPL(virDomainDiskIo, VIR_DOMAIN_DISK_IO_LAST,
"native",
"threads")
+VIR_ENUM_IMPL(virDomainAsyncIo, VIR_DOMAIN_ASYNC_IO_LAST,
+ "default",
+ "on",
+ "off")
+
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
"ide",
"fdc",
@@ -2001,6 +2006,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
char *cachetag = NULL;
char *error_policy = NULL;
char *iotag = NULL;
+ char *asyncio = NULL;
char *devaddr = NULL;
virStorageEncryptionPtr encryption = NULL;
char *serial = NULL;
@@ -2116,6 +2122,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
cachetag = virXMLPropString(cur, "cache");
error_policy = virXMLPropString(cur, "error_policy");
iotag = virXMLPropString(cur, "io");
+ asyncio = virXMLPropString(cur, "asyncio");
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
def->readonly = 1;
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
@@ -2252,6 +2259,24 @@ virDomainDiskDefParseXML(virCapsPtr caps,
}
}
+ if (asyncio) {
+ if (def->bus != VIR_DOMAIN_DISK_BUS_VIRTIO) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("disk asyncio mode supported "
+ "only for virtio bus"));
+ goto error;
+ }
+
+ int i;
+ if ((i = virDomainAsyncIoTypeFromString(asyncio)) <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown disk asyncio mode '%s'"),
+ asyncio);
+ goto error;
+ }
+ def->asyncio=i;
+ }
+
if (devaddr) {
if (virDomainParseLegacyDeviceAddress(devaddr,
&def->info.addr.pci) < 0) {
@@ -2314,6 +2339,7 @@ cleanup:
VIR_FREE(cachetag);
VIR_FREE(error_policy);
VIR_FREE(iotag);
+ VIR_FREE(asyncio);
VIR_FREE(devaddr);
VIR_FREE(serial);
virStorageEncryptionFree(encryption);
@@ -2701,6 +2727,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *model = NULL;
char *backend = NULL;
char *txmode = NULL;
+ char *asyncio = NULL;
char *filter = NULL;
char *internal = NULL;
char *devaddr = NULL;
@@ -2790,6 +2817,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
} else if (xmlStrEqual (cur->name, BAD_CAST "driver")) {
backend = virXMLPropString(cur, "name");
txmode = virXMLPropString(cur, "txmode");
+ asyncio = virXMLPropString(cur, "asyncio");
} else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) {
filter = virXMLPropString(cur, "filter");
VIR_FREE(filterparams);
@@ -3006,6 +3034,16 @@ virDomainNetDefParseXML(virCapsPtr caps,
}
def->driver.virtio.txmode = m;
}
+ if (asyncio) {
+ int i;
+ if ((i = virDomainAsyncIoTypeFromString(asyncio)) <= 0) {
+ virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown interface asyncio mode '%s'"),
+ asyncio);
+ goto error;
+ }
+ def->driver.virtio.asyncio = i;
+ }
}
if (filter != NULL) {
@@ -3045,6 +3083,7 @@ cleanup:
VIR_FREE(model);
VIR_FREE(backend);
VIR_FREE(txmode);
+ VIR_FREE(asyncio);
VIR_FREE(filter);
VIR_FREE(type);
VIR_FREE(internal);
@@ -8175,6 +8214,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode);
const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy);
const char *iomode = virDomainDiskIoTypeToString(def->iomode);
+ const char *asyncio = virDomainAsyncIoTypeToString(def->asyncio);
if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -8206,7 +8246,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
" <disk type='%s' device='%s'>\n",
type, device);
- if (def->driverName || def->driverType || def->cachemode) {
+ if (def->driverName || def->driverType || def->cachemode ||
+ def->asyncio) {
virBufferAsprintf(buf, " <driver");
if (def->driverName)
virBufferAsprintf(buf, " name='%s'", def->driverName);
@@ -8218,6 +8259,8 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " error_policy='%s'", error_policy);
if (def->iomode)
virBufferAsprintf(buf, " io='%s'", iomode);
+ if (def->asyncio)
+ virBufferAsprintf(buf, " asyncio='%s'", asyncio);
virBufferAsprintf(buf, "/>\n");
}
@@ -8508,6 +8551,10 @@ virDomainNetDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " txmode='%s'",
virDomainNetVirtioTxModeTypeToString(def->driver.virtio.txmode));
}
+ if (def->driver.virtio.asyncio) {
+ virBufferAsprintf(buf, " asyncio='%s'",
+ virDomainAsyncIoTypeToString(def->driver.virtio.asyncio));
+ }
virBufferAddLit(buf, "/>\n");
}
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 41c8136..01a98c9 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -206,6 +206,14 @@ enum virDomainDiskIo {
VIR_DOMAIN_DISK_IO_LAST
};
+enum virDomainAsyncIo {
+ VIR_DOMAIN_ASYNC_IO_DEFAULT = 0,
+ VIR_DOMAIN_ASYNC_IO_ON,
+ VIR_DOMAIN_ASYNC_IO_OFF,
+
+ VIR_DOMAIN_ASYNC_IO_LAST
+};
+
/* Stores the virtual disk configuration */
typedef struct _virDomainDiskDef virDomainDiskDef;
typedef virDomainDiskDef *virDomainDiskDefPtr;
@@ -225,6 +233,7 @@ struct _virDomainDiskDef {
int error_policy;
int bootIndex;
int iomode;
+ int asyncio;
unsigned int readonly : 1;
unsigned int shared : 1;
virDomainDeviceInfo info;
@@ -361,6 +370,7 @@ struct _virDomainNetDef {
struct {
enum virDomainNetBackendType name; /* which driver backend to use */
enum virDomainNetVirtioTxModeType txmode;
+ enum virDomainAsyncIo asyncio;
} virtio;
} driver;
union {
@@ -1521,6 +1531,7 @@ VIR_ENUM_DECL(virDomainDiskCache)
VIR_ENUM_DECL(virDomainDiskErrorPolicy)
VIR_ENUM_DECL(virDomainDiskProtocol)
VIR_ENUM_DECL(virDomainDiskIo)
+VIR_ENUM_DECL(virDomainAsyncIo)
VIR_ENUM_DECL(virDomainController)
VIR_ENUM_DECL(virDomainControllerModel)
VIR_ENUM_DECL(virDomainFS)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 737cd31..f3a44f6 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -205,6 +205,8 @@ dnsmasqSave;
virDiskNameToBusDeviceIndex;
virDiskNameToIndex;
virDomainAssignDef;
+virDomainAsyncIoTypeFromString;
+virDomainAsyncIoTypeToString;
virDomainChrConsoleTargetTypeFromString;
virDomainChrConsoleTargetTypeToString;
virDomainChrDefForeach;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 28c89b5..ad62a07 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -121,6 +121,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"device-qxl-vga",
"pci-multifunction", /* 60 */
+ "virtio-blk-pci.ioeventfd",
);
struct qemu_feature_flags {
@@ -1207,6 +1208,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags)
qemuCapsSet(flags, QEMU_CAPS_VIRTIO_TX_ALG);
if (strstr(str, "name \"qxl-vga\""))
qemuCapsSet(flags, QEMU_CAPS_DEVICE_QXL_VGA);
+ if (strstr(str, "virtio-blk-pci.ioeventfd"))
+ qemuCapsSet(flags, QEMU_CAPS_VIRTIO_IOEVENTFD);
return 0;
}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index e6d2fa3..0b9c8be 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -96,6 +96,7 @@ enum qemuCapsFlags {
QEMU_CAPS_VIRTIO_TX_ALG = 58, /* -device virtio-net-pci,tx=string */
QEMU_CAPS_DEVICE_QXL_VGA = 59, /* Is the primary and vga campatible qxl device named qxl-vga? */
QEMU_CAPS_PCI_MULTIFUNCTION = 60, /* -device multifunction=on|off */
+ QEMU_CAPS_VIRTIO_IOEVENTFD = 61, /* IOeventFD feature: virtio-{net|blk}-pci.ioeventfd=on/off */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index cb81354..8273e7e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1287,6 +1287,26 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
return 0;
}
+static int
+qemuBuildAsyncIoStr(virBufferPtr buf,
+ enum virDomainAsyncIo use,
+ virBitmapPtr qemuCaps)
+{
+ if (qemuCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_IOEVENTFD)) {
+ switch (use) {
+ case VIR_DOMAIN_ASYNC_IO_ON:
+ case VIR_DOMAIN_ASYNC_IO_OFF:
+ virBufferAsprintf(buf, ",ioeventfd=%s",
+ virDomainAsyncIoTypeToString(use));
+ break;
+ default:
+ /* In other cases (_DEFAULT, _LAST) we don't
+ * want to add anything */
+ break;
+ }
+ }
+ return 0;
+}
#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
@@ -1552,6 +1572,7 @@ qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
break;
case VIR_DOMAIN_DISK_BUS_VIRTIO:
virBufferAddLit(&opt, "virtio-blk-pci");
+ qemuBuildAsyncIoStr(&opt, disk->asyncio, qemuCaps);
qemuBuildDeviceAddressStr(&opt, &disk->info, qemuCaps);
break;
case VIR_DOMAIN_DISK_BUS_USB:
@@ -1774,6 +1795,8 @@ qemuBuildNicDevStr(virDomainNetDefPtr net,
goto error;
}
}
+ if (usingVirtio)
+ qemuBuildAsyncIoStr(&buf, net->driver.virtio.asyncio, qemuCaps);
if (vlan == -1)
virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias);
else
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index 327a0c7..119e771 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -475,7 +475,8 @@ mymain(void)
QEMU_CAPS_CCID_PASSTHRU,
QEMU_CAPS_CHARDEV_SPICEVMC,
QEMU_CAPS_DEVICE_QXL_VGA,
- QEMU_CAPS_VIRTIO_TX_ALG);
+ QEMU_CAPS_VIRTIO_TX_ALG,
+ QEMU_CAPS_VIRTIO_IOEVENTFD);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-asyncio.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-asyncio.args
new file mode 100644
index 0000000..c512f15
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-asyncio.args
@@ -0,0 +1,11 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
+/usr/bin/qemu -S -M pc-0.13 -m 1024 -smp 1 -nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait -no-acpi \
+-boot dc -device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \
+-drive file=/var/lib/libvirt/images/f14.img,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,ioeventfd=on,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0 \
+-drive file=/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
+-device virtio-net-pci,tx=bh,ioeventfd=off,vlan=0,id=net0,mac=52:54:00:e5:48:58,bus=pci.0,addr=0x3 \
+-net user,vlan=0,name=hostnet0 -serial pty -usb -vnc 127.0.0.1:-809 -std-vga \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-asyncio.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-asyncio.xml
new file mode 100644
index 0000000..5a16bd1
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-asyncio.xml
@@ -0,0 +1,51 @@
+<domain type='qemu'>
+ <name>test</name>
+ <memory>1048576</memory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-0.13'>hvm</type>
+ <boot dev='cdrom'/>
+ <boot dev='hd'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2' asyncio='on'/>
+ <source file='/var/lib/libvirt/images/f14.img'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+ </disk>
+ <disk type='file' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <source file='/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <interface type='user'>
+ <mac address='52:54:00:e5:48:58'/>
+ <model type='virtio'/>
+ <driver name='vhost' txmode='iothread' asyncio='off'/>
+ </interface>
+ <controller type='virtio-serial' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
+ </controller>
+ <serial type='pty'>
+ <target port='0'/>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <graphics type='vnc' port='5091' autoport='no' listen='127.0.0.1'/>
+ <video>
+ <model type='vga' vram='9216' heads='1'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+ </video>
+ </devices>
+</domain>
+
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index b8fd468..489025f 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -333,6 +333,9 @@ mymain(void)
DO_TEST("disk-aio", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_AIO,
QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_FORMAT);
+ DO_TEST("disk-asyncio", false,
+ QEMU_CAPS_DRIVE, QEMU_CAPS_VIRTIO_IOEVENTFD,
+ QEMU_CAPS_VIRTIO_TX_ALG, QEMU_CAPS_DEVICE);
DO_TEST("graphics-vnc", false, NONE);
DO_TEST("graphics-vnc-socket", false, NONE);
--
1.7.5.rc3
13 years, 5 months
[libvirt] [PATCH] qemu: Translate boot config into bootindex if possible
by Jiri Denemark
Prefer bootindex=N option for -device over the old way -boot ORDER
possibly accompanied with boot=on option for -drive. This gives us full
control over which device will actually be used for booting guest OS.
Moreover, if qemu doesn't support boot=on, this is the only way to boot
of certain disks in some configurations (such as virtio disks when used
together IDE disks) without transforming domain XML to use per device
boot elements.
---
src/qemu/qemu_command.c | 141 +++++++++++++-------
src/qemu/qemu_command.h | 4 +-
src/qemu/qemu_hotplug.c | 14 +-
.../qemuxml2argv-boot-complex-bootindex.args | 30 ++++
.../qemuxml2argv-boot-complex-bootindex.xml | 65 +++++++++
.../qemuxml2argv-boot-complex.args | 30 ++++
.../qemuxml2argvdata/qemuxml2argv-boot-complex.xml | 65 +++++++++
...xml2argv-boot-menu-disable-drive-bootindex.args | 13 ++
...uxml2argv-boot-menu-disable-drive-bootindex.xml | 27 ++++
.../qemuxml2argv-boot-menu-disable-drive.args | 14 ++
.../qemuxml2argv-boot-menu-disable-drive.xml | 27 ++++
.../qemuxml2argv-boot-menu-enable.args | 14 ++
.../qemuxml2argv-boot-menu-enable.xml | 27 ++++
.../qemuxml2argv-disk-drive-no-boot.args | 18 +++
.../qemuxml2argv-disk-drive-no-boot.xml | 38 ++++++
tests/qemuxml2argvtest.c | 17 +++
16 files changed, 489 insertions(+), 55 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-complex-bootindex.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-complex-bootindex.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-complex.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-complex.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive-bootindex.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive-bootindex.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-menu-enable.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-boot-menu-enable.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-no-boot.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-no-boot.xml
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index ef2d002..277fa99 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1189,7 +1189,7 @@ qemuSafeSerialParamValue(const char *value)
char *
qemuBuildDriveStr(virDomainDiskDefPtr disk,
- int bootable,
+ bool bootable,
virBitmapPtr qemuCaps)
{
virBuffer opt = VIR_BUFFER_INITIALIZER;
@@ -1343,6 +1343,7 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
}
}
if (bootable &&
+ qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) &&
disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
disk->bus != VIR_DOMAIN_DISK_BUS_IDE)
virBufferAddLit(&opt, ",boot=on");
@@ -1406,6 +1407,7 @@ error:
char *
qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
+ int bootindex,
virBitmapPtr qemuCaps)
{
virBuffer opt = VIR_BUFFER_INITIALIZER;
@@ -1446,8 +1448,8 @@ qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
}
virBufferAsprintf(&opt, ",drive=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
virBufferAsprintf(&opt, ",id=%s", disk->info.alias);
- if (disk->bootIndex && qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX))
- virBufferAsprintf(&opt, ",bootindex=%d", disk->bootIndex);
+ if (bootindex && qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX))
+ virBufferAsprintf(&opt, ",bootindex=%d", bootindex);
if (virBufferError(&opt)) {
virReportOOMError();
@@ -1615,6 +1617,7 @@ qemuBuildNicStr(virDomainNetDefPtr net,
char *
qemuBuildNicDevStr(virDomainNetDefPtr net,
int vlan,
+ int bootindex,
virBitmapPtr qemuCaps)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
@@ -1667,8 +1670,8 @@ qemuBuildNicDevStr(virDomainNetDefPtr net,
net->mac[4], net->mac[5]);
if (qemuBuildDeviceAddressStr(&buf, &net->info, qemuCaps) < 0)
goto error;
- if (net->bootIndex && qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX))
- virBufferAsprintf(&buf, ",bootindex=%d", net->bootIndex);
+ if (bootindex && qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX))
+ virBufferAsprintf(&buf, ",bootindex=%d", bootindex);
if (virBufferError(&buf)) {
virReportOOMError();
@@ -2684,7 +2687,6 @@ qemuBuildCommandLine(virConnectPtr conn,
enum virVMOperationType vmop)
{
int i;
- char boot[VIR_DOMAIN_BOOT_LAST+1];
struct utsname ut;
int disableKQEMU = 0;
int enableKQEMU = 0;
@@ -2699,6 +2701,7 @@ qemuBuildCommandLine(virConnectPtr conn,
virCommandPtr cmd;
bool has_rbd_hosts = false;
virBuffer rbd_hosts = VIR_BUFFER_INITIALIZER;
+ bool emitBootindex = false;
uname_normalize(&ut);
@@ -3090,31 +3093,54 @@ qemuBuildCommandLine(virConnectPtr conn,
virCommandAddArg(cmd, "-no-acpi");
if (!def->os.bootloader) {
- for (i = 0 ; i < def->os.nBootDevs ; i++) {
- switch (def->os.bootDevs[i]) {
- case VIR_DOMAIN_BOOT_CDROM:
- boot[i] = 'd';
- break;
- case VIR_DOMAIN_BOOT_FLOPPY:
- boot[i] = 'a';
- break;
- case VIR_DOMAIN_BOOT_DISK:
- boot[i] = 'c';
- break;
- case VIR_DOMAIN_BOOT_NET:
- boot[i] = 'n';
- break;
- default:
- boot[i] = 'c';
- break;
+ /*
+ * We prefer using explicit bootindex=N parameters for predictable
+ * results even though domain XML doesn't use per device boot elements.
+ * However, we can't use bootindex if boot menu was requested.
+ */
+ if (!def->os.nBootDevs) {
+ /* def->os.nBootDevs is guaranteed to be > 0 unless per-device boot
+ * configuration is used
+ */
+ if (!qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX)) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("hypervisor lacks deviceboot feature"));
+ goto error;
}
+ emitBootindex = true;
+ } else if (qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX) &&
+ (def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_ENABLED ||
+ !qemuCapsGet(qemuCaps, QEMU_CAPS_BOOT_MENU))) {
+ emitBootindex = true;
}
- if (def->os.nBootDevs) {
+
+ if (!emitBootindex) {
virBuffer boot_buf = VIR_BUFFER_INITIALIZER;
- virCommandAddArg(cmd, "-boot");
+ char boot[VIR_DOMAIN_BOOT_LAST+1];
+ for (i = 0 ; i < def->os.nBootDevs ; i++) {
+ switch (def->os.bootDevs[i]) {
+ case VIR_DOMAIN_BOOT_CDROM:
+ boot[i] = 'd';
+ break;
+ case VIR_DOMAIN_BOOT_FLOPPY:
+ boot[i] = 'a';
+ break;
+ case VIR_DOMAIN_BOOT_DISK:
+ boot[i] = 'c';
+ break;
+ case VIR_DOMAIN_BOOT_NET:
+ boot[i] = 'n';
+ break;
+ default:
+ boot[i] = 'c';
+ break;
+ }
+ }
boot[def->os.nBootDevs] = '\0';
+ virCommandAddArg(cmd, "-boot");
+
if (qemuCapsGet(qemuCaps, QEMU_CAPS_BOOT_MENU) &&
def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_DEFAULT) {
if (def->os.bootmenu == VIR_DOMAIN_BOOT_MENU_ENABLED)
@@ -3126,13 +3152,6 @@ qemuBuildCommandLine(virConnectPtr conn,
}
virCommandAddArgBuffer(cmd, &boot_buf);
- } else if (!qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX)) {
- /* def->os.nBootDevs is guaranteed to be > 0 unless per-device boot
- * configuration is used
- */
- qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("hypervisor lacks deviceboot feature"));
- goto error;
}
if (def->os.kernel)
@@ -3190,19 +3209,20 @@ qemuBuildCommandLine(virConnectPtr conn,
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE)) {
int bootCD = 0, bootFloppy = 0, bootDisk = 0;
- /* If QEMU supports boot=on for -drive param... */
- if (qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) &&
+ if ((qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_BOOT) || emitBootindex) &&
!def->os.kernel) {
+ /* bootDevs will get translated into either bootindex=N or boot=on
+ * depending on what qemu supports */
for (i = 0 ; i < def->os.nBootDevs ; i++) {
switch (def->os.bootDevs[i]) {
case VIR_DOMAIN_BOOT_CDROM:
- bootCD = 1;
+ bootCD = i + 1;
break;
case VIR_DOMAIN_BOOT_FLOPPY:
- bootFloppy = 1;
+ bootFloppy = i + 1;
break;
case VIR_DOMAIN_BOOT_DISK:
- bootDisk = 1;
+ bootDisk = i + 1;
break;
}
}
@@ -3210,7 +3230,7 @@ qemuBuildCommandLine(virConnectPtr conn,
for (i = 0 ; i < def->ndisks ; i++) {
char *optstr;
- int bootable = 0;
+ int bootindex = 0;
virDomainDiskDefPtr disk = def->disks[i];
int withDeviceArg = 0;
bool deviceFlagMasked = false;
@@ -3234,15 +3254,15 @@ qemuBuildCommandLine(virConnectPtr conn,
switch (disk->device) {
case VIR_DOMAIN_DISK_DEVICE_CDROM:
- bootable = bootCD;
+ bootindex = bootCD;
bootCD = 0;
break;
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
- bootable = bootFloppy;
+ bootindex = bootFloppy;
bootFloppy = 0;
break;
case VIR_DOMAIN_DISK_DEVICE_DISK:
- bootable = bootDisk;
+ bootindex = bootDisk;
bootDisk = 0;
break;
}
@@ -3262,7 +3282,9 @@ qemuBuildCommandLine(virConnectPtr conn,
deviceFlagMasked = true;
}
}
- optstr = qemuBuildDriveStr(disk, bootable, qemuCaps);
+ optstr = qemuBuildDriveStr(disk,
+ emitBootindex ? false : !!bootindex,
+ qemuCaps);
if (deviceFlagMasked)
qemuCapsSet(qemuCaps, QEMU_CAPS_DEVICE);
if (!optstr)
@@ -3290,6 +3312,11 @@ qemuBuildCommandLine(virConnectPtr conn,
}
}
+ if (!emitBootindex)
+ bootindex = 0;
+ else if (disk->bootIndex)
+ bootindex = disk->bootIndex;
+
if (withDeviceArg) {
if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
virCommandAddArg(cmd, "-global");
@@ -3298,18 +3325,18 @@ qemuBuildCommandLine(virConnectPtr conn,
? 'B' : 'A',
disk->info.alias);
- if (disk->bootIndex &&
- qemuCapsGet(qemuCaps, QEMU_CAPS_BOOTINDEX)) {
+ if (bootindex) {
virCommandAddArg(cmd, "-global");
virCommandAddArgFormat(cmd, "isa-fdc.bootindex%c=%d",
disk->info.addr.drive.unit
? 'B' : 'A',
- disk->bootIndex);
+ bootindex);
}
} else {
virCommandAddArg(cmd, "-device");
- if (!(optstr = qemuBuildDriveDevStr(disk, qemuCaps)))
+ if (!(optstr = qemuBuildDriveDevStr(disk, bootindex,
+ qemuCaps)))
goto error;
virCommandAddArg(cmd, optstr);
VIR_FREE(optstr);
@@ -3470,12 +3497,31 @@ qemuBuildCommandLine(virConnectPtr conn,
if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE))
virCommandAddArgList(cmd, "-net", "none", NULL);
} else {
+ int bootNet = 0;
+
+ if (emitBootindex) {
+ /* convert <boot dev='network'/> to bootindex since we didn't emit
+ * -boot n
+ */
+ for (i = 0 ; i < def->os.nBootDevs ; i++) {
+ if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) {
+ bootNet = i + 1;
+ break;
+ }
+ }
+ }
+
for (i = 0 ; i < def->nnets ; i++) {
virDomainNetDefPtr net = def->nets[i];
char *nic, *host;
char tapfd_name[50];
char vhostfd_name[50] = "";
int vlan;
+ int bootindex = bootNet;
+
+ bootNet = 0;
+ if (!bootindex)
+ bootindex = net->bootIndex;
/* VLANs are not used with -netdev, so don't record them */
if (qemuCapsGet(qemuCaps, QEMU_CAPS_NETDEV) &&
@@ -3547,7 +3593,8 @@ qemuBuildCommandLine(virConnectPtr conn,
}
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
virCommandAddArg(cmd, "-device");
- if (!(nic = qemuBuildNicDevStr(net, vlan, qemuCaps)))
+ nic = qemuBuildNicDevStr(net, vlan, bootindex, qemuCaps);
+ if (!nic)
goto error;
virCommandAddArg(cmd, nic);
VIR_FREE(nic);
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 528031d..d6e5dcb 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -68,6 +68,7 @@ char * qemuBuildNicStr(virDomainNetDefPtr net,
/* Current, best practice */
char * qemuBuildNicDevStr(virDomainNetDefPtr net,
int vlan,
+ int bootindex,
virBitmapPtr qemuCaps);
char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
@@ -75,13 +76,14 @@ char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
/* Both legacy & current support */
char *qemuBuildDriveStr(virDomainDiskDefPtr disk,
- int bootable,
+ bool bootable,
virBitmapPtr qemuCaps);
char *qemuBuildFSStr(virDomainFSDefPtr fs,
virBitmapPtr qemuCaps);
/* Current, best practice */
char * qemuBuildDriveDevStr(virDomainDiskDefPtr disk,
+ int bootindex,
virBitmapPtr qemuCaps);
char * qemuBuildFSDevStr(virDomainFSDefPtr fs,
virBitmapPtr qemuCaps);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index fe47896..b605b3a 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -186,10 +186,10 @@ int qemuDomainAttachPciDiskDevice(struct qemud_driver *driver,
if (qemuAssignDeviceDiskAlias(disk, priv->qemuCaps) < 0)
goto error;
- if (!(drivestr = qemuBuildDriveStr(disk, 0, priv->qemuCaps)))
+ if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
goto error;
- if (!(devstr = qemuBuildDriveDevStr(disk, priv->qemuCaps)))
+ if (!(devstr = qemuBuildDriveDevStr(disk, 0, priv->qemuCaps)))
goto error;
}
@@ -409,11 +409,11 @@ int qemuDomainAttachSCSIDisk(struct qemud_driver *driver,
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
if (qemuAssignDeviceDiskAlias(disk, priv->qemuCaps) < 0)
goto error;
- if (!(devstr = qemuBuildDriveDevStr(disk, priv->qemuCaps)))
+ if (!(devstr = qemuBuildDriveDevStr(disk, 0, priv->qemuCaps)))
goto error;
}
- if (!(drivestr = qemuBuildDriveStr(disk, 0, priv->qemuCaps)))
+ if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
goto error;
for (i = 0 ; i <= disk->info.addr.drive.controller ; i++) {
@@ -529,9 +529,9 @@ int qemuDomainAttachUsbMassstorageDevice(struct qemud_driver *driver,
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
if (qemuAssignDeviceDiskAlias(disk, priv->qemuCaps) < 0)
goto error;
- if (!(drivestr = qemuBuildDriveStr(disk, 0, priv->qemuCaps)))
+ if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
goto error;
- if (!(devstr = qemuBuildDriveDevStr(disk, priv->qemuCaps)))
+ if (!(devstr = qemuBuildDriveDevStr(disk, 0, priv->qemuCaps)))
goto error;
}
@@ -702,7 +702,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
}
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
- if (!(nicstr = qemuBuildNicDevStr(net, vlan, priv->qemuCaps)))
+ if (!(nicstr = qemuBuildNicDevStr(net, vlan, 0, priv->qemuCaps)))
goto try_remove;
} else {
if (!(nicstr = qemuBuildNicStr(net, NULL, vlan)))
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-complex-bootindex.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-complex-bootindex.args
new file mode 100644
index 0000000..ae0b2b1
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-complex-bootindex.args
@@ -0,0 +1,30 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
+/usr/bin/qemu \
+-S \
+-M pc \
+-m 214 \
+-smp 1 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-drive file=/tmp/vda.img,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,bus=pci.0,addr=0x5,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=3 \
+-drive file=/tmp/vdb.img,if=none,id=drive-virtio-disk1 \
+-device virtio-blk-pci,bus=pci.0,addr=0x6,drive=drive-virtio-disk1,id=virtio-disk1 \
+-drive file=/dev/HostVG/hda,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
+-drive file=/dev/HostVG/hdb,if=none,id=drive-ide0-0-1 \
+-device ide-drive,bus=ide.0,unit=1,drive=drive-ide0-0-1,id=ide0-0-1 \
+-drive file=/dev/HostVG/hdc,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0,bootindex=1 \
+-drive file=/dev/fd0,if=none,id=drive-fdc0-0-0 \
+-global isa-fdc.driveA=drive-fdc0-0-0 \
+-global isa-fdc.bootindexA=4 \
+-drive file=/dev/fd1,if=none,id=drive-fdc0-0-1 \
+-global isa-fdc.driveB=drive-fdc0-0-1 \
+-device virtio-net-pci,vlan=0,id=net0,mac=00:11:22:33:44:11,bus=pci.0,addr=0x3,bootindex=2 \
+-net user,vlan=0,name=hostnet0 \
+-device virtio-net-pci,vlan=1,id=net1,mac=00:11:22:33:44:22,bus=pci.0,addr=0x4 \
+-net user,vlan=1,name=hostnet1 \
+-usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-complex-bootindex.xml b/tests/qemuxml2argvdata/qemuxml2argv-boot-complex-bootindex.xml
new file mode 100644
index 0000000..b4d6f4f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-complex-bootindex.xml
@@ -0,0 +1,65 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='cdrom'/>
+ <boot dev='network'/>
+ <boot dev='hd'/>
+ <boot dev='fd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='file' device='disk'>
+ <source file='/tmp/vdb.img'/>
+ <target dev='vdb' bus='virtio'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/hdb'/>
+ <target dev='hdb' bus='ide'/>
+ <address type='drive' controller='0' bus='0' unit='1'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/hda'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <disk type='file' device='disk'>
+ <source file='/tmp/vda.img'/>
+ <target dev='vda' bus='virtio'/>
+ </disk>
+ <disk type='block' device='cdrom'>
+ <source dev='/dev/HostVG/hdc'/>
+ <target dev='hdc' bus='ide'/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <disk type='block' device='floppy'>
+ <source dev='/dev/fd1'/>
+ <target dev='fdb' bus='fdc'/>
+ <address type='drive' controller='0' bus='0' unit='1'/>
+ </disk>
+ <disk type='block' device='floppy'>
+ <source dev='/dev/fd0'/>
+ <target dev='fda' bus='fdc'/>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <controller type='fdc' index='0'/>
+ <controller type='ide' index='0'/>
+ <interface type='user'>
+ <mac address='00:11:22:33:44:11'/>
+ <model type='virtio'/>
+ </interface>
+ <interface type='user'>
+ <mac address='00:11:22:33:44:22'/>
+ <model type='virtio'/>
+ </interface>
+ <memballoon model='none'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-complex.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-complex.args
new file mode 100644
index 0000000..c8d32ec
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-complex.args
@@ -0,0 +1,30 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
+/usr/bin/qemu \
+-S \
+-M pc \
+-m 214 \
+-smp 1 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-boot dnca \
+-drive file=/tmp/vda.img,if=none,id=drive-virtio-disk0,boot=on \
+-device virtio-blk-pci,bus=pci.0,addr=0x5,drive=drive-virtio-disk0,id=virtio-disk0 \
+-drive file=/tmp/vdb.img,if=none,id=drive-virtio-disk1 \
+-device virtio-blk-pci,bus=pci.0,addr=0x6,drive=drive-virtio-disk1,id=virtio-disk1 \
+-drive file=/dev/HostVG/hda,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
+-drive file=/dev/HostVG/hdb,if=none,id=drive-ide0-0-1 \
+-device ide-drive,bus=ide.0,unit=1,drive=drive-ide0-0-1,id=ide0-0-1 \
+-drive file=/dev/HostVG/hdc,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
+-drive file=/dev/fd0,if=none,id=drive-fdc0-0-0 \
+-global isa-fdc.driveA=drive-fdc0-0-0 \
+-drive file=/dev/fd1,if=none,id=drive-fdc0-0-1 \
+-global isa-fdc.driveB=drive-fdc0-0-1 \
+-device virtio-net-pci,vlan=0,id=net0,mac=00:11:22:33:44:11,bus=pci.0,addr=0x3 \
+-net user,vlan=0,name=hostnet0 \
+-device virtio-net-pci,vlan=1,id=net1,mac=00:11:22:33:44:22,bus=pci.0,addr=0x4 \
+-net user,vlan=1,name=hostnet1 \
+-usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-complex.xml b/tests/qemuxml2argvdata/qemuxml2argv-boot-complex.xml
new file mode 100644
index 0000000..b4d6f4f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-complex.xml
@@ -0,0 +1,65 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='cdrom'/>
+ <boot dev='network'/>
+ <boot dev='hd'/>
+ <boot dev='fd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='file' device='disk'>
+ <source file='/tmp/vdb.img'/>
+ <target dev='vdb' bus='virtio'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/hdb'/>
+ <target dev='hdb' bus='ide'/>
+ <address type='drive' controller='0' bus='0' unit='1'/>
+ </disk>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/hda'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <disk type='file' device='disk'>
+ <source file='/tmp/vda.img'/>
+ <target dev='vda' bus='virtio'/>
+ </disk>
+ <disk type='block' device='cdrom'>
+ <source dev='/dev/HostVG/hdc'/>
+ <target dev='hdc' bus='ide'/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <disk type='block' device='floppy'>
+ <source dev='/dev/fd1'/>
+ <target dev='fdb' bus='fdc'/>
+ <address type='drive' controller='0' bus='0' unit='1'/>
+ </disk>
+ <disk type='block' device='floppy'>
+ <source dev='/dev/fd0'/>
+ <target dev='fda' bus='fdc'/>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <controller type='fdc' index='0'/>
+ <controller type='ide' index='0'/>
+ <interface type='user'>
+ <mac address='00:11:22:33:44:11'/>
+ <model type='virtio'/>
+ </interface>
+ <interface type='user'>
+ <mac address='00:11:22:33:44:22'/>
+ <model type='virtio'/>
+ </interface>
+ <memballoon model='none'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive-bootindex.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive-bootindex.args
new file mode 100644
index 0000000..5074e32
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive-bootindex.args
@@ -0,0 +1,13 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu \
+-S \
+-M pc \
+-m 214 \
+-smp 1 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-drive file=/dev/cdrom,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0,bootindex=1 \
+-usb \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive-bootindex.xml b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive-bootindex.xml
new file mode 100644
index 0000000..bc1da8a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive-bootindex.xml
@@ -0,0 +1,27 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='cdrom'/>
+ <bootmenu enable='no'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='cdrom'>
+ <source dev='/dev/cdrom'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive.args
new file mode 100644
index 0000000..42b48e5
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive.args
@@ -0,0 +1,14 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu \
+-S \
+-M pc \
+-m 214 \
+-smp 1 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-boot order=d,menu=off \
+-drive file=/dev/cdrom,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
+-usb \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive.xml b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive.xml
new file mode 100644
index 0000000..bc1da8a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-disable-drive.xml
@@ -0,0 +1,27 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='cdrom'/>
+ <bootmenu enable='no'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='cdrom'>
+ <source dev='/dev/cdrom'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-enable.args b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-enable.args
new file mode 100644
index 0000000..5d7c4a4
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-enable.args
@@ -0,0 +1,14 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu \
+-S \
+-M pc \
+-m 214 \
+-smp 1 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-boot order=d,menu=on \
+-drive file=/dev/cdrom,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
+-usb \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-enable.xml b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-enable.xml
new file mode 100644
index 0000000..c35b2bd
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-boot-menu-enable.xml
@@ -0,0 +1,27 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='cdrom'/>
+ <bootmenu enable='yes'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='cdrom'>
+ <source dev='/dev/cdrom'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-no-boot.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-no-boot.args
new file mode 100644
index 0000000..357723f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-no-boot.args
@@ -0,0 +1,18 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
+/usr/bin/qemu \
+-S \
+-M pc \
+-m 214 \
+-smp 1 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi \
+-drive file=/dev/HostVG/QEMUGuest1,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=2 \
+-drive file=/dev/HostVG/QEMUGuest2,if=none,media=cdrom,id=drive-ide0-1-0 \
+-device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0,bootindex=1 \
+-drive file=/dev/fd0,if=none,id=drive-fdc0-0-0 \
+-global isa-fdc.driveA=drive-fdc0-0-0 \
+-global isa-fdc.bootindexA=3 \
+-usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-no-boot.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-no-boot.xml
new file mode 100644
index 0000000..a7e08fd
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-no-boot.xml
@@ -0,0 +1,38 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='cdrom'/>
+ <boot dev='hd'/>
+ <boot dev='fd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <disk type='block' device='cdrom'>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='hdc' bus='ide'/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <disk type='block' device='floppy'>
+ <source dev='/dev/fd0'/>
+ <target dev='fda' bus='fdc'/>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <controller type='fdc' index='0'/>
+ <controller type='ide' index='0'/>
+ <memballoon model='none'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index cbd9a5f..a0f3354 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -265,9 +265,24 @@ mymain(void)
DO_TEST("boot-network", false, NONE);
DO_TEST("boot-floppy", false, NONE);
DO_TEST("boot-multi", false, QEMU_CAPS_BOOT_MENU);
+ DO_TEST("boot-menu-enable", false,
+ QEMU_CAPS_BOOT_MENU, QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE);
+ DO_TEST("boot-menu-enable", false,
+ QEMU_CAPS_BOOT_MENU, QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE,
+ QEMU_CAPS_BOOTINDEX);
DO_TEST("boot-menu-disable", false, QEMU_CAPS_BOOT_MENU);
+ DO_TEST("boot-menu-disable-drive", false,
+ QEMU_CAPS_BOOT_MENU, QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE);
+ DO_TEST("boot-menu-disable-drive-bootindex", false,
+ QEMU_CAPS_BOOT_MENU, QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE,
+ QEMU_CAPS_BOOTINDEX);
DO_TEST("boot-order", false,
QEMU_CAPS_BOOTINDEX, QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE);
+ DO_TEST("boot-complex", false,
+ QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_BOOT);
+ DO_TEST("boot-complex-bootindex", false,
+ QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_BOOT,
+ QEMU_CAPS_BOOTINDEX);
DO_TEST("bootloader", true, QEMU_CAPS_DOMID);
DO_TEST("clock-utc", false, NONE);
DO_TEST("clock-localtime", false, NONE);
@@ -323,6 +338,8 @@ mymain(void)
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-sheepdog", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
+ DO_TEST("disk-drive-no-boot", false,
+ QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_BOOTINDEX);
DO_TEST("disk-usb", false, NONE);
DO_TEST("disk-usb-device", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
--
1.7.5.3
13 years, 5 months