[libvirt] [PATCH] initgroups() in qemudOpenAsUID()
by Dan Kenigsberg
qemudOpenAsUID is intended to open a file with the credentials of a
specified uid. Current implementation fails if the file is accessible to
one of uid's groups but not owned by uid.
This patch replaces the supplementary group list that the child process
inherited from libvirtd with the default group list of uid.
---
src/qemu/qemu_driver.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0ce2d40..a1027d4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6353,6 +6353,7 @@ parent_cleanup:
char *buf = NULL;
size_t bufsize = 1024 * 1024;
int bytesread;
+ struct passwd *pwd;
/* child doesn't need the read side of the pipe */
close(pipefd[0]);
@@ -6365,6 +6366,21 @@ parent_cleanup:
goto child_cleanup;
}
+ /* we can avoid getpwuid_r() in threadless child */
+ if ((pwd = getpwuid(uid)) == NULL) {
+ exit_code = errno;
+ virReportSystemError(errno,
+ _("cannot setuid(%d) to read '%s'"),
+ uid, path);
+ goto child_cleanup;
+ }
+ if (initgroups(pwd->pw_name, pwd->pw_gid) != 0) {
+ exit_code = errno;
+ virReportSystemError(errno,
+ _("cannot setuid(%d) to read '%s'"),
+ uid, path);
+ goto child_cleanup;
+ }
if (setuid(uid) != 0) {
exit_code = errno;
virReportSystemError(errno,
--
1.7.2.3
14 years
[libvirt] [PATCH] Introduce yet another migration version in API.
by Daniel P. Berrange
Migration just seems togo from bad to worse. We already had to
introduce a second migration protocol when adding the QEMU driver,
since the one from Xen was insufficiently flexible to cope with
passing the data the QEMU driver required.
It turns out that this protocol still has some flaws that we
need to address. The current sequence is
* Src: DumpXML
- Generate XML to pass to dst
* Dst: Prepare
- Get ready to accept incoming VM
- Generate optional cookie to pass to src
* Src: Perform
- Start migration and wait for send completion
- Kill off VM if successful, resume if failed
* Dst: Finish
- Wait for recv completion and check status
- Kill off VM if unsuccessful
The problems with this are:
- Since the first step is a generic 'DumpXML' call, we can't
add in other migration specific data. eg, we can't include
any VM lease data from lock manager plugins
- Since the first step is a generic 'DumpXML' call, we can't
emit any 'migration begin' event on the source, or have
any hook that runs right at the start of the process
- Since there is no final step on the source, if the Finish
method fails to receive all migration data & has to kill
the VM, then there's no way to resume the original VM
on the source
This patch attempts to introduce a version 3 that uses the
improved 5 step sequence
* Src: Begin
- Generate XML to pass to dst
- Generate optional cookie to pass to dst
* Dst: Prepare
- Get ready to accept incoming VM
- Generate optional cookie to pass to src
* Src: Perform
- Start migration and wait for send completion
- Generate optional cookie to pass to dst
* Dst: Finish
- Wait for recv completion and check status
- Kill off VM if failed, resume if success
- Generate optional cookie to pass to src
* Src: Confirm
- Kill off VM if success, resume if failed
The API is designed to allow both input and output cookies
in all methods where applicable. This lets us pass around
arbitrary extra driver specific data between src & dst during
migration. Combined with the extra 'Begin' method this lets
us pass lease information from source to dst at the start of
migration
Moving the killing of the source VM out of Perform and
into Confirm, means we can now recover if the dst host
can't successfully Finish receiving migration data.
---
src/driver.h | 64 +++++++++++++++++++
src/libvirt.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++
src/libvirt_internal.h | 7 ++
3 files changed, 235 insertions(+), 0 deletions(-)
diff --git a/src/driver.h b/src/driver.h
index e3a232d..b2514ed 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -486,6 +486,65 @@ typedef int
virStreamPtr st,
unsigned int flags);
+typedef char *
+ (*virDrvDomainMigrateBegin3)
+ (virConnectPtr dconn,
+ char **cookiesrc,
+ int *cookiesrclen,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource);
+
+typedef int
+ (*virDrvDomainMigratePrepare3)
+ (virConnectPtr dconn,
+ const char *cookiesrc,
+ int cookiesrclen,
+ char **cookiedst,
+ int *cookiedstlen,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource,
+ const char *dom_xml);
+
+typedef int
+ (*virDrvDomainMigratePerform3)
+ (virDomainPtr domain,
+ char **cookiesrc,
+ int *cookiesrclen,
+ const char *cookiedst,
+ int cookiedstlen,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource);
+
+typedef virDomainPtr
+ (*virDrvDomainMigrateFinish3)
+ (virConnectPtr dconn,
+ const char *dname,
+ const char *cookiesrc,
+ int cookiesrclen,
+ char **cookiedst,
+ int *cookiedstlen,
+ const char *uri,
+ unsigned long flags,
+ int retcode);
+
+typedef int
+ (*virDrvDomainMigrateConfirm3)
+ (virConnectPtr dconn,
+ const char *dname,
+ const char *cookiesrc,
+ int cookiesrclen,
+ const char *cookiedst,
+ int cookiedstlen,
+ const char *uri,
+ unsigned long flags,
+ int retcode);
/**
* _virDriver:
@@ -604,6 +663,11 @@ struct _virDriver {
virDrvDomainSetMemoryParameters domainSetMemoryParameters;
virDrvDomainGetMemoryParameters domainGetMemoryParameters;
virDrvDomainOpenConsole domainOpenConsole;
+ virDrvDomainMigrateBegin3 domainMigrateBegin3;
+ virDrvDomainMigratePrepare3 domainMigratePrepare3;
+ virDrvDomainMigratePerform3 domainMigratePerform3;
+ virDrvDomainMigrateFinish3 domainMigrateFinish3;
+ virDrvDomainMigrateConfirm3 domainMigrateConfirm3;
};
typedef int
diff --git a/src/libvirt.c b/src/libvirt.c
index e24fb9e..04a7cd0 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -3342,6 +3342,22 @@ error:
}
+/*
+ * Sequence v1:
+ *
+ * Dst: Prepare
+ * - Get ready to accept incoming VM
+ * - Generate optional cookie to pass to src
+ *
+ * Src: Perform
+ * - Start migration and wait for send completion
+ * - Kill off VM if successful, resume if failed
+ *
+ * Dst: Finish
+ * - Wait for recv completion and check status
+ * - Kill off VM if unsuccessful
+ *
+ */
static virDomainPtr
virDomainMigrateVersion1 (virDomainPtr domain,
virConnectPtr dconn,
@@ -3411,6 +3427,25 @@ virDomainMigrateVersion1 (virDomainPtr domain,
return ddomain;
}
+/*
+ * Sequence v2:
+ *
+ * Src: DumpXML
+ * - Generate XML to pass to dst
+ *
+ * Dst: Prepare
+ * - Get ready to accept incoming VM
+ * - Generate optional cookie to pass to src
+ *
+ * Src: Perform
+ * - Start migration and wait for send completion
+ * - Kill off VM if successful, resume if failed
+ *
+ * Dst: Finish
+ * - Wait for recv completion and check status
+ * - Kill off VM if unsuccessful
+ *
+ */
static virDomainPtr
virDomainMigrateVersion2 (virDomainPtr domain,
virConnectPtr dconn,
@@ -3505,6 +3540,130 @@ virDomainMigrateVersion2 (virDomainPtr domain,
}
+/*
+ * Sequence v3:
+ *
+ * Src: Begin
+ * - Generate XML to pass to dst
+ * - Generate optional cookie to pass to dst
+ *
+ * Dst: Prepare
+ * - Get ready to accept incoming VM
+ * - Generate optional cookie to pass to src
+ *
+ * Src: Perform
+ * - Start migration and wait for send completion
+ * - Generate optional cookie to pass to dst
+ *
+ * Dst: Finish
+ * - Wait for recv completion and check status
+ * - Kill off VM if failed, resume if success
+ * - Generate optional cookie to pass to src
+ *
+ * Src: Confirm
+ * - Kill off VM if success, resume if failed
+ *
+ */
+static virDomainPtr
+virDomainMigrateVersion3 (virDomainPtr domain,
+ virConnectPtr dconn,
+ unsigned long flags,
+ const char *dname,
+ const char *uri,
+ unsigned long bandwidth)
+{
+ virDomainPtr ddomain = NULL;
+ char *uri_out = NULL;
+ char *cookiesrc = NULL;
+ char *cookiedst = NULL;
+ char *dom_xml = NULL;
+ int cookiesrclen = 0;
+ int cookiedstlen = 0;
+ int ret;
+ virDomainInfo info;
+ virErrorPtr orig_err = NULL;
+
+ if (!domain->conn->driver->domainMigrateBegin3) {
+ virLibConnError (domain->conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
+ virDispatchError(domain->conn);
+ return NULL;
+ }
+ dom_xml = domain->conn->driver->domainMigrateBegin3
+ (domain->conn, &cookiesrc, &cookiesrclen, uri, flags, dname,
+ bandwidth);
+ if (!dom_xml)
+ goto done;
+
+ ret = virDomainGetInfo (domain, &info);
+ if (ret == 0 && info.state == VIR_DOMAIN_PAUSED) {
+ flags |= VIR_MIGRATE_PAUSED;
+ }
+
+ ret = dconn->driver->domainMigratePrepare3
+ (dconn, cookiesrc, cookiesrclen, &cookiedst, &cookiedstlen,
+ uri, &uri_out, flags, dname, bandwidth, dom_xml);
+ VIR_FREE (dom_xml);
+ if (ret == -1)
+ goto done;
+
+ if (uri == NULL && uri_out == NULL) {
+ virLibConnError (domain->conn, VIR_ERR_INTERNAL_ERROR,
+ _("domainMigratePrepare2 did not set uri"));
+ virDispatchError(domain->conn);
+ goto done;
+ }
+ if (uri_out)
+ uri = uri_out; /* Did domainMigratePrepare2 change URI? */
+ assert (uri != NULL);
+
+ /* Perform the migration. The driver isn't supposed to return
+ * until the migration is complete. The src VM should remain
+ * running, but in paused state until the destination can
+ * confirm migration completion.
+ */
+ ret = domain->conn->driver->domainMigratePerform3
+ (domain, &cookiesrc, &cookiesrclen, cookiedst, cookiedstlen,
+ uri, flags, dname, bandwidth);
+
+ /* Perform failed. Make sure Finish doesn't overwrite the error */
+ if (ret < 0)
+ orig_err = virSaveLastError();
+
+ /*
+ * The status code from the source is passed to the destination.
+ * The dest can cleanup in the source indicated it failed to
+ * send all migration data. Returns NULL for ddomain if
+ * the dest was unable to complete migration.
+ */
+ dname = dname ? dname : domain->name;
+ ddomain = dconn->driver->domainMigrateFinish3
+ (dconn, dname, cookiesrc, cookiesrclen, &cookiedst, &cookiedstlen,
+ uri, flags, ret);
+
+ /*
+ * If Perform3 indicated an error, or if NULL was returned
+ * from Finish3, then the status code tells the source
+ * to resume CPUs on the original VM.
+ */
+ ret = domain->conn->driver->domainMigrateConfirm3
+ (domain->conn, dname, cookiesrc, cookiesrclen, cookiedst, cookiedstlen,
+ uri, flags, ret >= 0 && domain ? 0 : -1);
+ /* XXX is there anything we can do if Confirm3 returns -1.
+ * Probably nothing beyond praying
+ */
+
+ done:
+ if (orig_err) {
+ virSetError(orig_err);
+ virFreeError(orig_err);
+ }
+ VIR_FREE(uri_out);
+ VIR_FREE(cookiesrc);
+ VIR_FREE(cookiedst);
+ return ddomain;
+}
+
+
/*
* This is sort of a migration v3
*
@@ -3716,6 +3875,11 @@ virDomainMigrate (virDomainPtr domain,
VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
VIR_DRV_FEATURE_MIGRATION_V2))
ddomain = virDomainMigrateVersion2(domain, dconn, flags, dname, uri, bandwidth);
+ else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+ VIR_DRV_FEATURE_MIGRATION_V3) &&
+ VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+ VIR_DRV_FEATURE_MIGRATION_V3))
+ ddomain = virDomainMigrateVersion3(domain, dconn, flags, dname, uri, bandwidth);
else {
/* This driver does not support any migration method */
virLibConnError(domain->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
diff --git a/src/libvirt_internal.h b/src/libvirt_internal.h
index 1c4fa4f..d781d6b 100644
--- a/src/libvirt_internal.h
+++ b/src/libvirt_internal.h
@@ -66,6 +66,13 @@ enum {
* perform step is used.
*/
VIR_DRV_FEATURE_MIGRATION_DIRECT = 5,
+
+ /*
+ * Driver supports V3-style virDomainMigrate, ie domainMigrateBegin3/
+ * domainMigratePrepare3/domainMigratePerform3/domainMigrateFinish3/
+ * domainMigrateConfirm3.
+ */
+ VIR_DRV_FEATURE_MIGRATION_V3 = 6,
};
--
1.7.2.3
14 years
[libvirt] [PATCH] qemu: plug memory leak
by Eric Blake
https://bugzilla.redhat.com/show_bug.cgi?id=656795
* src/qemu/qemu_monitor.c (qemuMonitorFree): Also free the buffer.
---
src/qemu/qemu_monitor.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 86ed82f..85d0d0f 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -199,6 +199,7 @@ static void qemuMonitorFree(qemuMonitorPtr mon)
if (virCondDestroy(&mon->notify) < 0)
{}
virMutexDestroy(&mon->lock);
+ VIR_FREE(mon->buffer);
VIR_FREE(mon);
}
--
1.7.3.2
14 years
[libvirt] [PATCH 0/8] Initial integration of lock managers
by Daniel P. Berrange
This patch series is the bare minimum framework required to integrate
with external lock managers. This is a fleshing out of the original
proposal in
http://www.redhat.com/archives/libvir-list/2010-September/msg00167.html
What's in this series
* Major refactor of the security drivers to simplify code
and clarify interaction with lock maanger
* Low level internal lock manager plugin API for locking
objects and their resources
* High level internal lock manager API for locking virtual
machines and their disks
* Simple 'no op' plugin impl to stub out all the code
* Re-ordering of QEMU startup to add a handshake between
libvirtd & the child process, immediately prior to exec().
This allows acquiring locks in the child, before the
parent libvirtd process then re-labels disks
* The public API header for 3rd parties to implement
new lock manager plugins against
* Some basic documentation
What's not in this series
* A standard 'fcntl' based plugin
* Enhanced migration process to transfer lock state
* Hooks to re-validate the lock at time of VM resume
14 years
[libvirt] [PATCH] add network disk support
by MORITA Kazutaka
This patch adds network disk support to libvirt/QEMU. The currently
supported protcols are nbd, rbd, and sheepdog. The XML syntax is like
this:
<disk type="network" device="disk">
<driver name="qemu" type="raw" />
<source protocol='rbd|sheepdog|nbd' name="...some image identifier...">
<host name="mon1.example.org" port="6000">
<host name="mon2.example.org" port="6000">
<host name="mon3.example.org" port="6000">
</source>
<target dev="vda" bus="virtio" />
</disk>
Signed-off-by: MORITA Kazutaka <morita.kazutaka(a)lab.ntt.co.jp>
---
This patch addresses the discussion on
https://www.redhat.com/archives/libvir-list/2010-November/msg00759.html
Josh mentioned that the monitor hostnames of RBD can be set through
the environment variables, but I couldn't find any documentations
about it, so the monitors are not set in this patch. I hope someone
who is familiar with RBD implements it.
I appreciate any feedback.
Thanks,
Kazutaka
docs/schemas/domain.rng | 31 +++++++++
src/conf/domain_conf.c | 68 +++++++++++++++++--
src/conf/domain_conf.h | 20 ++++++
src/qemu/qemu_conf.c | 169 +++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 279 insertions(+), 9 deletions(-)
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index fb44335..81f4004 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -612,6 +612,37 @@
<ref name="diskspec"/>
</interleave>
</group>
+ <group>
+ <attribute name="type">
+ <value>network</value>
+ </attribute>
+ <interleave>
+ <optional>
+ <element name="source">
+ <attribute name="protocol">
+ <choice>
+ <value>nbd</value>
+ <value>rbd</value>
+ <value>sheepdog</value>
+ </choice>
+ </attribute>
+ <attribute name="name"/>
+ <zeroOrMore>
+ <element name="host">
+ <attribute name="name">
+ <ref name="genericName"/>
+ </attribute>
+ <attribute name="port">
+ <ref name="unsignedInt"/>
+ </attribute>
+ </element>
+ </zeroOrMore>
+ <empty/>
+ </element>
+ </optional>
+ <ref name="diskspec"/>
+ </interleave>
+ </group>
<ref name="diskspec"/>
</choice>
</element>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 3f14cee..b9dbc61 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -113,7 +113,8 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
"block",
"file",
- "dir")
+ "dir",
+ "network")
VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
"disk",
@@ -142,6 +143,11 @@ VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
"ignore",
"enospace")
+VIR_ENUM_IMPL(virDomainDiskProtocol, VIR_DOMAIN_DISK_PROTOCOL_LAST,
+ "nbd",
+ "rbd",
+ "sheepdog")
+
VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
"ide",
"fdc",
@@ -508,6 +514,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def)
VIR_FREE(def->serial);
VIR_FREE(def->src);
+ VIR_FREE(def->hosts);
VIR_FREE(def->dst);
VIR_FREE(def->driverName);
VIR_FREE(def->driverType);
@@ -1574,13 +1581,15 @@ virDomainDiskDefParseXML(virCapsPtr caps,
xmlNodePtr node,
int flags) {
virDomainDiskDefPtr def;
- xmlNodePtr cur;
+ xmlNodePtr cur, host;
char *type = NULL;
char *device = NULL;
char *driverName = NULL;
char *driverType = NULL;
char *source = NULL;
char *target = NULL;
+ char *protocol = NULL;
+ virDomainDiskHostDefPtr hosts = NULL;
char *bus = NULL;
char *cachetag = NULL;
char *error_policy = NULL;
@@ -1607,7 +1616,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
cur = node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE) {
- if ((source == NULL) &&
+ if ((source == NULL && hosts == NULL) &&
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
switch (def->type) {
@@ -1620,6 +1629,30 @@ virDomainDiskDefParseXML(virCapsPtr caps,
case VIR_DOMAIN_DISK_TYPE_DIR:
source = virXMLPropString(cur, "dir");
break;
+ case VIR_DOMAIN_DISK_TYPE_NETWORK:
+ protocol = virXMLPropString(cur, "protocol");
+ if (protocol == NULL) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing protocol type"));
+ break;
+ }
+ def->protocol = virDomainDiskProtocolTypeFromString(protocol);
+ source = virXMLPropString(cur, "name");
+ host = cur->children;
+ while (host != NULL) {
+ if (host->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(host->name, BAD_CAST "host")) {
+ if (VIR_REALLOC_N(hosts, def->nhosts + 1) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ hosts[def->nhosts].name = virXMLPropString(host, "name");
+ hosts[def->nhosts].port = virXMLPropString(host, "port");
+ def->nhosts++;
+ }
+ host = host->next;
+ }
+ break;
default:
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected disk type %s"),
@@ -1685,7 +1718,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
/* Only CDROM and Floppy devices are allowed missing source path
* to indicate no media present */
- if (source == NULL &&
+ if (source == NULL && hosts == NULL &&
def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
virDomainReportError(VIR_ERR_NO_SOURCE,
@@ -1791,6 +1824,8 @@ virDomainDiskDefParseXML(virCapsPtr caps,
source = NULL;
def->dst = target;
target = NULL;
+ def->hosts = hosts;
+ hosts = NULL;
def->driverName = driverName;
driverName = NULL;
def->driverType = driverType;
@@ -1819,6 +1854,8 @@ cleanup:
VIR_FREE(type);
VIR_FREE(target);
VIR_FREE(source);
+ VIR_FREE(hosts);
+ VIR_FREE(protocol);
VIR_FREE(device);
VIR_FREE(driverType);
VIR_FREE(driverName);
@@ -5887,7 +5924,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferVSprintf(buf, "/>\n");
}
- if (def->src) {
+ if (def->src || def->nhosts > 0) {
switch (def->type) {
case VIR_DOMAIN_DISK_TYPE_FILE:
virBufferEscapeString(buf, " <source file='%s'/>\n",
@@ -5901,6 +5938,27 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferEscapeString(buf, " <source dir='%s'/>\n",
def->src);
break;
+ case VIR_DOMAIN_DISK_TYPE_NETWORK:
+ virBufferVSprintf(buf, " <source protocol='%s'",
+ virDomainDiskProtocolTypeToString(def->protocol));
+ if (def->src) {
+ virBufferEscapeString(buf, " name='%s'", def->src);
+ }
+ if (def->nhosts == 0) {
+ virBufferVSprintf(buf, "/>\n");
+ } else {
+ int i;
+
+ virBufferVSprintf(buf, ">\n");
+ for (i = 0; i < def->nhosts; i++) {
+ virBufferEscapeString(buf, " <host name='%s'",
+ def->hosts[i].name);
+ virBufferEscapeString(buf, " port='%s'/>\n",
+ def->hosts[i].port);
+ }
+ virBufferVSprintf(buf, " </source>\n");
+ }
+ break;
default:
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected disk type %s"),
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 899b19f..6c97289 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -120,6 +120,7 @@ enum virDomainDiskType {
VIR_DOMAIN_DISK_TYPE_BLOCK,
VIR_DOMAIN_DISK_TYPE_FILE,
VIR_DOMAIN_DISK_TYPE_DIR,
+ VIR_DOMAIN_DISK_TYPE_NETWORK,
VIR_DOMAIN_DISK_TYPE_LAST
};
@@ -164,6 +165,21 @@ enum virDomainDiskErrorPolicy {
VIR_DOMAIN_DISK_ERROR_POLICY_LAST
};
+enum virDomainDiskProtocol {
+ VIR_DOMAIN_DISK_PROTOCOL_NBD,
+ VIR_DOMAIN_DISK_PROTOCOL_RBD,
+ VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG,
+
+ VIR_DOMAIN_DISK_PROTOCOL_LAST
+};
+
+typedef struct _virDomainDiskHostDef virDomainDiskHostDef;
+typedef virDomainDiskHostDef *virDomainDiskHostDefPtr;
+struct _virDomainDiskHostDef {
+ char *name;
+ char *port;
+};
+
/* Stores the virtual disk configuration */
typedef struct _virDomainDiskDef virDomainDiskDef;
typedef virDomainDiskDef *virDomainDiskDefPtr;
@@ -173,6 +189,9 @@ struct _virDomainDiskDef {
int bus;
char *src;
char *dst;
+ int protocol;
+ int nhosts;
+ virDomainDiskHostDefPtr hosts;
char *driverName;
char *driverType;
char *serial;
@@ -1237,6 +1256,7 @@ VIR_ENUM_DECL(virDomainDiskDevice)
VIR_ENUM_DECL(virDomainDiskBus)
VIR_ENUM_DECL(virDomainDiskCache)
VIR_ENUM_DECL(virDomainDiskErrorPolicy)
+VIR_ENUM_DECL(virDomainDiskProtocol)
VIR_ENUM_DECL(virDomainController)
VIR_ENUM_DECL(virDomainControllerModel)
VIR_ENUM_DECL(virDomainFS)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 35caccc..63abd75 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -2714,7 +2714,7 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
break;
}
- if (disk->src) {
+ if (disk->src || disk->nhosts > 0) {
if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
/* QEMU only supports magic FAT format for now */
if (disk->driverType &&
@@ -2733,6 +2733,24 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
virBufferVSprintf(&opt, "file=fat:floppy:%s,", disk->src);
else
virBufferVSprintf(&opt, "file=fat:%s,", disk->src);
+ } else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
+ switch (disk->protocol) {
+ case VIR_DOMAIN_DISK_PROTOCOL_NBD:
+ virBufferVSprintf(&opt, "file=nbd:%s:%s,",
+ disk->hosts->name, disk->hosts->port);
+ break;
+ case VIR_DOMAIN_DISK_PROTOCOL_RBD:
+ virBufferVSprintf(&opt, "file=rbd:%s,", disk->src);
+ break;
+ case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
+ if (disk->nhosts > 0)
+ virBufferVSprintf(&opt, "file=sheepdog:%s:%s:%s,",
+ disk->hosts->name, disk->hosts->port,
+ disk->src);
+ else
+ virBufferVSprintf(&opt, "file=sheepdog:%s,", disk->src);
+ break;
+ }
} else {
virBufferVSprintf(&opt, "file=%s,", disk->src);
}
@@ -4722,6 +4740,24 @@ int qemudBuildCommandLine(virConnectPtr conn,
snprintf(file, PATH_MAX, "fat:floppy:%s", disk->src);
else
snprintf(file, PATH_MAX, "fat:%s", disk->src);
+ } else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
+ switch (disk->protocol) {
+ case VIR_DOMAIN_DISK_PROTOCOL_NBD:
+ snprintf(file, PATH_MAX, "nbd:%s:%s,",
+ disk->hosts->name, disk->hosts->port);
+ break;
+ case VIR_DOMAIN_DISK_PROTOCOL_RBD:
+ snprintf(file, PATH_MAX, "rbd:%s,", disk->src);
+ break;
+ case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
+ if (disk->nhosts > 0)
+ snprintf(file, PATH_MAX, "sheepdog:%s:%s:%s,",
+ disk->hosts->name, disk->hosts->port,
+ disk->src);
+ else
+ snprintf(file, PATH_MAX, "sheepdog:%s,", disk->src);
+ break;
+ }
} else {
snprintf(file, PATH_MAX, "%s", disk->src);
}
@@ -5794,7 +5830,67 @@ qemuParseCommandLineDisk(virCapsPtr caps,
values[i] = NULL;
if (STRPREFIX(def->src, "/dev/"))
def->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
- else
+ else if (STRPREFIX(def->src, "nbd:")) {
+ char *host, *port;
+
+ def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ host = def->src + strlen("nbd:");
+ port = strchr(host, ':');
+ if (!port) {
+ def = NULL;
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse nbd filename '%s'"), def->src);
+ goto cleanup;
+ }
+ *port++ = '\0';
+ if (VIR_ALLOC(def->hosts) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ def->nhosts = 1;
+ def->hosts->name = strdup(host);
+ def->hosts->port = strdup(port);
+
+ VIR_FREE(def->src);
+ def->src = NULL;
+ } else if (STRPREFIX(def->src, "rbd:")) {
+ char *p = def->src;
+
+ def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ def->src = strdup(p + strlen("rbd:"));
+
+ VIR_FREE(p);
+ } else if (STRPREFIX(def->src, "sheepdog:")) {
+ char *p = def->src;
+ char *port, *vdi;
+
+ def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ def->src = strdup(p + strlen("sheepdog:"));
+
+ /* def->src must be [vdiname] or [host]:[port]:[vdiname] */
+ port = strchr(def->src, ':');
+ if (port) {
+ *port++ = '\0';
+ vdi = strchr(port, ':');
+ if (!vdi) {
+ def = NULL;
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse sheepdog filename '%s'"), p);
+ goto cleanup;
+ }
+ *vdi++ = '\0';
+ if (VIR_ALLOC(def->hosts) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ def->nhosts = 1;
+ def->hosts->name = def->src;
+ def->hosts->port = strdup(port);
+ def->src = strdup(vdi);
+ }
+
+ VIR_FREE(p);
+ } else
def->type = VIR_DOMAIN_DISK_TYPE_FILE;
} else {
def->type = VIR_DOMAIN_DISK_TYPE_FILE;
@@ -6731,7 +6827,19 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
if (STRPREFIX(val, "/dev/"))
disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
- else
+ else if (STRPREFIX(val, "nbd:")) {
+ disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
+ val += strlen("nbd:");
+ } else if (STRPREFIX(val, "rbd:")) {
+ disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
+ val += strlen("rbd:");
+ } else if (STRPREFIX(val, "sheepdog:")) {
+ disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
+ val += strlen("sheepdog:");
+ } else
disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
if (STREQ(arg, "-cdrom")) {
disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
@@ -6751,7 +6859,60 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
disk->dst = strdup(arg + 1);
}
disk->src = strdup(val);
- if (!disk->src ||
+
+ if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
+ char *host, *port;
+
+ switch (disk->protocol) {
+ case VIR_DOMAIN_DISK_PROTOCOL_NBD:
+ host = disk->src;
+ port = strchr(host, ':');
+ if (!port) {
+ def = NULL;
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse nbd filename '%s'"), disk->src);
+ goto error;
+ }
+ *port++ = '\0';
+ if (VIR_ALLOC(disk->hosts) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ disk->nhosts = 1;
+ disk->hosts->name = host;
+ disk->hosts->port = strdup(port);
+ disk->src = NULL;
+ break;
+ case VIR_DOMAIN_DISK_PROTOCOL_RBD:
+ break;
+ case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
+ /* disk->src must be [vdiname] or [host]:[port]:[vdiname] */
+ port = strchr(disk->src, ':');
+ if (port) {
+ char *vdi;
+
+ *port++ = '\0';
+ vdi = strchr(port, ':');
+ if (!vdi) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse sheepdog filename '%s'"), val);
+ goto error;
+ }
+ *vdi++ = '\0';
+ if (VIR_ALLOC(disk->hosts) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ disk->nhosts = 1;
+ disk->hosts->name = disk->src;
+ disk->hosts->port = strdup(port);
+ disk->src = strdup(vdi);
+ }
+ break;
+ }
+ }
+
+ if (!(disk->src || disk->nhosts > 0) ||
!disk->dst) {
virDomainDiskDefFree(disk);
goto no_memory;
--
1.7.1
14 years
[libvirt] [PATCH v5] qemu: call drive_del in DetachPciDiskDevice
by Ryan Harper
Currently libvirt doesn't confirm whether the guest has responded to the
disk removal request. In some cases this can leave the guest with
continued access to the device while the mgmt layer believes that it has
been removed. With a recent qemu monitor command[1] we can
deterministically revoke a guests access to the disk (on the QEMU side)
to ensure no futher access is permitted.
This patch adds support for the drive_del() command and introduces it
in the disk removal paths. If the guest is running in a QEMU without this
command we currently explicitly check for unknown command/CommandNotFound
and log the issue.
If QEMU supports the command we issue the drive_del command after we attempt
to remove the device. The guest may respond and remove the block device
before we get to attempt to call drive_del. In that case, we explicitly check
for 'Device not found' from the monitor indicating that the target drive
was auto-deleted upon guest responds to the device removal notification.
1. http://thread.gmane.org/gmane.comp.emulators.qemu/84745
Signed-off-by: Ryan Harper <ryanh(a)us.ibm.com>
---
Changes since v4:
- removed PATH_MAX, use virAsprintf()
- moved drivestr allocation before call to EnterMonitor
Changes since v3:
- Renamed DriveUnplug -> DriveDel, use drive_del monitor cmd.
- Moved invocation to after DelDevice and guest notification.
- Handle the case where drive is auto-deleted before we call
DriveDel by catching and ignoring 'Device not found' error.
- Simplified DriveDel invocation; no need to check return codes
as the monitor implementations handle all failure case and logs
or ignores as needed.
Changes since v2:
- use VIR_ERROR to report when unplug command not found
Changes since v1:
- return > 0 when command isn't present, < 0 on command failure
- detect when drive_unplug command isn't present and log error
instead of failing entire command
src/qemu/qemu_driver.c | 28 +++++++++++++++++++++
src/qemu/qemu_monitor.c | 19 ++++++++++++++
src/qemu/qemu_monitor.h | 3 ++
src/qemu/qemu_monitor_json.c | 38 +++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 3 ++
src/qemu/qemu_monitor_text.c | 54 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 3 ++
7 files changed, 148 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index e7b37e1..a6a7b8d 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9037,6 +9037,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
virDomainDiskDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
virCgroupPtr cgroup = NULL;
+ char *drivestr = NULL;
i = qemudFindDisk(vm->def, dev->data.disk->dst);
@@ -9064,6 +9065,14 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
goto cleanup;
}
+ /* build the actual drive id string as the disk->info.alias doesn't
+ * contain the QEMU_DRIVE_HOST_PREFIX that is passed to qemu */
+ if (virAsprintf(&drivestr, "%s%s",
+ QEMU_DRIVE_HOST_PREFIX, detach->info.alias) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
@@ -9077,6 +9086,10 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
goto cleanup;
}
}
+
+ /* disconnect guest from host device */
+ qemuMonitorDriveDel(priv->mon, drivestr);
+
qemuDomainObjExitMonitorWithDriver(driver, vm);
qemuDomainDiskAudit(vm, detach, NULL, "detach", ret >= 0);
@@ -9104,6 +9117,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
ret = 0;
cleanup:
+ VIR_FREE(drivestr);
return ret;
}
@@ -9116,6 +9130,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
virDomainDiskDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
virCgroupPtr cgroup = NULL;
+ char *drivestr = NULL;
i = qemudFindDisk(vm->def, dev->data.disk->dst);
@@ -9142,11 +9157,23 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
}
}
+ /* build the actual drive id string as the disk->info.alias doesn't
+ * contain the QEMU_DRIVE_HOST_PREFIX that is passed to qemu */
+ if (virAsprintf(&drivestr, "%s%s",
+ QEMU_DRIVE_HOST_PREFIX, detach->info.alias) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
qemuDomainObjExitMonitor(vm);
goto cleanup;
}
+
+ /* disconnect guest from host device */
+ qemuMonitorDriveDel(priv->mon, drivestr);
+
qemuDomainObjExitMonitorWithDriver(driver, vm);
qemuDomainDiskAudit(vm, detach, NULL, "detach", ret >= 0);
@@ -9170,6 +9197,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
ret = 0;
cleanup:
+ VIR_FREE(drivestr);
virCgroupFree(&cgroup);
return ret;
}
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 2366fdb..80adba4 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1781,6 +1781,25 @@ int qemuMonitorGetAllPCIAddresses(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorDriveDel(qemuMonitorPtr mon,
+ const char *drivestr)
+{
+ DEBUG("mon=%p drivestr=%s", mon, drivestr);
+ int ret;
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONDriveDel(mon, drivestr);
+ else
+ ret = qemuMonitorTextDriveDel(mon, drivestr);
+ return ret;
+}
+
int qemuMonitorDelDevice(qemuMonitorPtr mon,
const char *devalias)
{
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 7d09145..8cda43b 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -381,6 +381,9 @@ int qemuMonitorDelDevice(qemuMonitorPtr mon,
int qemuMonitorAddDrive(qemuMonitorPtr mon,
const char *drivestr);
+int qemuMonitorDriveDel(qemuMonitorPtr mon,
+ const char *drivestr);
+
int qemuMonitorSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index d2c6f0a..a380ab2 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2244,6 +2244,44 @@ int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
}
+int qemuMonitorJSONDriveDel(qemuMonitorPtr mon,
+ const char *drivestr)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ DEBUG("JSONDriveDel drivestr=%s", drivestr);
+ cmd = qemuMonitorJSONMakeCommand("drive_del",
+ "s:id", drivestr,
+ NULL);
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0) {
+ /* See if drive_del isn't supported */
+ if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
+ VIR_ERROR0(_("deleting disk is not supported. "
+ "This may leak data if disk is reassigned"));
+ ret = 1;
+ goto cleanup;
+ } else if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {
+ /* NB: device not found errors mean the drive was
+ * auto-deleted and we ignore the error */
+ ret = 0;
+ } else {
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+ }
+ }
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase)
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 94806c1..82671c7 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -188,6 +188,9 @@ int qemuMonitorJSONDelDevice(qemuMonitorPtr mon,
int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
const char *drivestr);
+int qemuMonitorJSONDriveDel(qemuMonitorPtr mon,
+ const char *drivestr);
+
int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase);
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 7f15008..483ceb0 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2285,6 +2285,7 @@ int qemuMonitorTextDelDevice(qemuMonitorPtr mon,
goto cleanup;
}
+ DEBUG("TextDelDevice devalias=%s", devalias);
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
_("cannot detach %s device"), devalias);
@@ -2391,6 +2392,59 @@ cleanup:
return ret;
}
+/* Attempts to remove a host drive.
+ * Returns 1 if unsupported, 0 if ok, and -1 on other failure */
+int qemuMonitorTextDriveDel(qemuMonitorPtr mon,
+ const char *drivestr)
+{
+ char *cmd = NULL;
+ char *reply = NULL;
+ char *safedev;
+ int ret = -1;
+ DEBUG("TextDriveDel drivestr=%s", drivestr);
+
+ if (!(safedev = qemuMonitorEscapeArg(drivestr))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virAsprintf(&cmd, "drive_del %s", safedev) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("cannot delete %s drive"), drivestr);
+ goto cleanup;
+ }
+
+ if (strstr(reply, "unknown command:")) {
+ VIR_ERROR0(_("deleting drive is not supported. "
+ "This may leak data if disk is reassigned"));
+ ret = 1;
+ goto cleanup;
+
+ /* (qemu) drive_del wark
+ * Device 'wark' not found */
+ } else if (STRPREFIX(reply, "Device '") && (strstr(reply, "not found"))) {
+ /* NB: device not found errors mean the drive was auto-deleted and we
+ * ignore the error */
+ ret = 0;
+ } else if (STRNEQ(reply, "")) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("deleting %s drive failed: %s"), drivestr, reply);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ VIR_FREE(safedev);
+ return ret;
+}
int qemuMonitorTextSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index c017509..3a88f87 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -186,6 +186,9 @@ int qemuMonitorTextDelDevice(qemuMonitorPtr mon,
int qemuMonitorTextAddDrive(qemuMonitorPtr mon,
const char *drivestr);
+int qemuMonitorTextDriveDel(qemuMonitorPtr mon,
+ const char *drivestr);
+
int qemuMonitorTextSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase);
--
1.6.3.3
--
Ryan Harper
Software Engineer; Linux Technology Center
IBM Corp., Austin, Tx
ryanh(a)us.ibm.com
14 years
[libvirt] [PATCH v3] qemu: call drive_unplug in DetachPciDiskDevice
by Ryan Harper
Currently libvirt doesn't confirm whether the guest has responded to the
disk removal request. In some cases this can leave the guest with
continued access to the device while the mgmt layer believes that it has
been removed. With a recent qemu monitor command[1] we can
deterministically revoke a guests access to the disk (on the QEMU side)
to ensure no futher access is permitted.
This patch adds support for the drive_unplug() command and introduces it
in the disk removal paths. There is some discussion to be had about how
to handle the case where the guest is running in a QEMU without this
command (and the fact that we currently don't have a way of detecting
what monitor commands are available).
Changes since v2:
- use VIR_ERROR to report when unplug command not found
Changes since v1:
- return > 0 when command isn't present, < 0 on command failure
- detect when drive_unplug command isn't present and log error
instead of failing entire command
Signed-off-by: Ryan Harper <ryanh(a)us.ibm.com>
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index abd8e9d..615427a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8646,6 +8646,7 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
virDomainDiskDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
virCgroupPtr cgroup = NULL;
+ char drivestr[PATH_MAX];
i = qemudFindDisk(vm->def, dev->data.disk->dst);
@@ -8673,13 +8674,36 @@ static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
goto cleanup;
}
+ /* build the actual drive id string as the disk->info.alias doesn't
+ * contain the QEMU_DRIVE_HOST_PREFIX that is passed to qemu */
+ if ((ret = snprintf(drivestr, sizeof(drivestr), "%s%s",
+ QEMU_DRIVE_HOST_PREFIX,
+ detach->info.alias))
+ < 0 || ret >= sizeof(drivestr)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+ ret = qemuMonitorDriveUnplug(priv->mon, drivestr);
+ DEBUG("DriveUnplug ret=%d", ret);
+ /* ret > 0 indicates unplug isn't supported, issue will be logged */
+ if (ret < 0) {
+ qemuDomainObjExitMonitor(vm);
+ goto cleanup;
+ }
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
qemuDomainObjExitMonitor(vm);
goto cleanup;
}
} else {
+ ret = qemuMonitorDriveUnplug(priv->mon, drivestr);
+ /* ret > 0 indicates unplug isn't supported, issue will be logged */
+ if (ret < 0) {
+ qemuDomainObjExitMonitor(vm);
+ goto cleanup;
+ }
if (qemuMonitorRemovePCIDevice(priv->mon,
&detach->info.addr.pci) < 0) {
qemuDomainObjExitMonitor(vm);
@@ -8723,6 +8747,7 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
virDomainDiskDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
virCgroupPtr cgroup = NULL;
+ char drivestr[PATH_MAX];
i = qemudFindDisk(vm->def, dev->data.disk->dst);
@@ -8749,7 +8774,22 @@ static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
}
}
+ /* build the actual drive id string as the disk->info.alias doesn't
+ * contain the QEMU_DRIVE_HOST_PREFIX that is passed to qemu */
+ if ((ret = snprintf(drivestr, sizeof(drivestr), "%s%s",
+ QEMU_DRIVE_HOST_PREFIX,
+ detach->info.alias))
+ < 0 || ret >= sizeof(drivestr)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ /* ret > 0 indicates unplug isn't supported, issue will be logged */
+ if (qemuMonitorDriveUnplug(priv->mon, drivestr) < 0) {
+ qemuDomainObjExitMonitor(vm);
+ goto cleanup;
+ }
if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
qemuDomainObjExitMonitor(vm);
goto cleanup;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 2366fdb..285381d 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1781,6 +1781,25 @@ int qemuMonitorGetAllPCIAddresses(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorDriveUnplug(qemuMonitorPtr mon,
+ const char *drivestr)
+{
+ DEBUG("mon=%p drivestr=%s", mon, drivestr);
+ int ret;
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONDriveUnplug(mon, drivestr);
+ else
+ ret = qemuMonitorTextDriveUnplug(mon, drivestr);
+ return ret;
+}
+
int qemuMonitorDelDevice(qemuMonitorPtr mon,
const char *devalias)
{
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 48f4c20..bfe3641 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -381,6 +381,9 @@ int qemuMonitorDelDevice(qemuMonitorPtr mon,
int qemuMonitorAddDrive(qemuMonitorPtr mon,
const char *drivestr);
+int qemuMonitorDriveUnplug(qemuMonitorPtr mon,
+ const char *drivestr);
+
int qemuMonitorSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index d3ab25f..b11fd4f 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2243,6 +2243,39 @@ int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
}
+int qemuMonitorJSONDriveUnplug(qemuMonitorPtr mon,
+ const char *drivestr)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ DEBUG("JSONDriveUnplug drivestr=%s", drivestr);
+ cmd = qemuMonitorJSONMakeCommand("drive_unplug",
+ "s:id", drivestr,
+ NULL);
+ if (!cmd)
+ return -1;
+
+ ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+
+ if (ret == 0) {
+ /* See if drive_unplug isn't supported */
+ if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
+ VIR_ERROR0(_("unplugging disk is not supported. "
+ "This may leak data if disk is reassigned"));
+ ret = 1;
+ goto cleanup;
+ }
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+ }
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase)
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 94806c1..6a8692e 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -188,6 +188,9 @@ int qemuMonitorJSONDelDevice(qemuMonitorPtr mon,
int qemuMonitorJSONAddDrive(qemuMonitorPtr mon,
const char *drivestr);
+int qemuMonitorJSONDriveUnplug(qemuMonitorPtr mon,
+ const char *drivestr);
+
int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase);
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 69971a6..6e5bc95 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2380,6 +2380,52 @@ cleanup:
return ret;
}
+/* Attempts to unplug a drive. Returns 1 if unsupported, 0 if ok, and -1 on
+ * other failure */
+int qemuMonitorTextDriveUnplug(qemuMonitorPtr mon,
+ const char *drivestr)
+{
+ char *cmd = NULL;
+ char *reply = NULL;
+ char *safedev;
+ int ret = -1;
+ DEBUG("TextDriveUnplug drivestr=%s", drivestr);
+
+ if (!(safedev = qemuMonitorEscapeArg(drivestr))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virAsprintf(&cmd, "drive_unplug %s", safedev) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("cannot unplug %s drive"), drivestr);
+ goto cleanup;
+ }
+
+ if (strstr(reply, "unknown command:")) {
+ VIR_ERROR0(_("unplugging disk is not supported. "
+ "This may leak data if disk is reassigned"));
+ ret = 1;
+ goto cleanup;
+ } else if (STRNEQ(reply, "")) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("unplugging %s drive failed: %s"), drivestr, reply);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ VIR_FREE(safedev);
+ return ret;
+}
int qemuMonitorTextSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index c017509..8355ce8 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -186,6 +186,9 @@ int qemuMonitorTextDelDevice(qemuMonitorPtr mon,
int qemuMonitorTextAddDrive(qemuMonitorPtr mon,
const char *drivestr);
+int qemuMonitorTextDriveUnplug(qemuMonitorPtr mon,
+ const char *drivestr);
+
int qemuMonitorTextSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase);
--
Ryan Harper
Software Engineer; Linux Technology Center
IBM Corp., Austin, Tx
ryanh(a)us.ibm.com
14 years
[libvirt] Looking for Hypervisor Vulerability Example
by Shi Jin
Hi there,
I am researching on virtualization security and particularly on sVirt.
>From this sVirt presentation[1] and this RHEL-6 documentation on sVirt [2], I read:
If there is a security flaw in the hypervisor that can be exploited by a guest instance, this guest may be able to not only attack the host, but also other guests running on that host. This is not theoretical; attacks already exist on hypervisors. These attacks can extend beyond the guest instance and could expose other guests to attack.
I am very interested to know about the exact attacks: which version of hypervisor on which OS, how was the exploit used and how it affected the systems.
I want to be able to reproduce one of the attacks in our lab so that I can demonstrate to people on the security issues and then how sVirt could be used to actually prevent to attacks on hosting system and other VMs. I believe a real demonstration is better than a million words.
I appreciate your help.
Shi
[1]:http://namei.org/presentations/svirt-lca-2009.pdf
[2]:http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Virt...
--
Shi Jin, PhD
14 years
[libvirt] Release of libvirt 0.8.6
by Daniel Veillard
As indicated 10 days ago, today was time for a release, I didn't
had much time so I simply generated a release from libvirt git
without much testing. Hopefully this will be okay !
Release is available as usual at
ftp://libvirt.org/libvirt/
There is actually a number of significant features rolled in this
release, along with the usual fixes and improvements:
Features:
- new API virDomainIsUpdated (Osier Yang)
- Add support for iSCSI target auto-discovery (Daniel P. Berrange)
- QED: Basic support for QED images (Adam Litke)
- Introduce a virDomainOpenConsole API (Daniel P. Berrange)
- Support for SPICE graphics (Daniel P. Berrange)
- Add a sysinfo and SMBIOS support (Daniel Veillard)
- Implement virsh qemu-monitor-command. (Chris Lalancette)
Documentation:
- updated c# bindings with arnauds latest changes (Justin Clift)
- Fix spelling of virBufferVSprintf (Jiri Denemark)
- Fix broken XML entity for '>' (Philipp Hahn)
- removed outdated reference to virt-mem (Justin Clift)
- Add doc for missed options of migrate (Osier Yang)
- add doc for missed parameters of attach-disk (Osier Yang)
- update virsh manual (Osier Yang)
- updated virsh command reference with libvirt.org links (Justin Clift)
- Generate HACKING from docs/hacking.html.in (Matthias Bolte)
- Prepare hacking.html.in to generate HACKING from it (Matthias Bolte)
- updated csharp pages with latest info (Justin Clift)
- trivial typo fix (Justin Clift)
- added virsh command reference page. (Justin Clift)
- rpm: Fix summary wording (Cole Robinson)
- Augment bug reporting documentation (Daniel Veillard)
- virsh: fix incorrect help text mentioning non-existent network 'id' (Justin Clift)
- Fix off-by-1 in todo page generator (Daniel P. Berrange)
- Fix comment for <video> tag in domain RNG schema (Daniel P. Berrange)
- fix typo (Eric Blake)
Portability:
- remote: Fix TLS transport on Windows (Matthias Bolte)
- Rename 'remove' param to 'toremove' to avoid clash with stdio.h (Daniel P. Berrange)
- virt-aa-helper: Fix several compile errors (Matthias Bolte)
- maint: improve i18n on non-Linux (Eric Blake)
- nwfilter: use /bin/sh rather than requiring bash (Eric Blake)
- Use python discovered through env instead of hardcoding a path (Matthias Bolte)
- esx: Avoid warnings about breaking strict-aliasing rules on FreeBSD (Matthias Bolte)
- Make sure struct sockaddr_in is defined on FreeBSD (Matthias Bolte)
- configure: Disable FS storage driver if mntent.h is not available (Matthias Bolte)
- daemon: Include stdlib.h in dispatch.c (Matthias Bolte)
- xen: work with xen 4.0.1 headers (Eric Blake)
- Fix build with polkit 0 (Jim Fehlig)
- xen: work with ia64 MAX_VIRT_CPUS of 64 (Eric Blake)
- build: cleanup declaration of xen tests. (Diego Elio Pettenò)
- qemu: check compression program availability of virsh save and dump (KAMEZAWA Hiroyuki)
Bug Fixes:
- correct the arguments of migrate_speed (Wen Congyang)
- Fix memory leaks in audit & VirtualBox code (Daniel P. Berrange)
- Fix host CPU counting on unusual NUMA topologies (Jiri Denemark)
- security, storage: plug memory leaks for security_context_t (Eric Blake)
- network: plug memory leak (Eric Blake)
- qemu: plug memory leak (Eric Blake)
- Always close drivers when a virConnectPtr is released (Matthias Bolte)
- libvirtd: fix bug when shrinking number of clients (Eric Blake)
- Fix 32-bit int truncation in QED header check (Daniel P. Berrange)
- Fix error handling in virsh when listing storage volumes (Daniel P. Berrange)
- Fix parsing of port attribute in storage XML configuration (Daniel P. Berrange)
- Don't catch SIGCHLD in libvirtd (Daniel P. Berrange)
- Ensure logfile isn't truncated by shutdown message. (Daniel P. Berrange)
- xend: Escape reserved sexpr characters (Cole Robinson)
- xend: urlencode: Properly escape '&' (Cole Robinson)
- conf: Fix parsing python style triple quotes (Cole Robinson)
- nwfilter: re-order lock grabbed by IP addr. learn thread (Stefan Berger)
- virExec: fix bug in setting up child stderr/out with /dev/null (Daniel P. Berrange)
- Fix a failure to restore SELinux label for character devices (Daniel Veillard)
- nwfilter: also purge ip(6)tables rules before detecting IP address (Stefan Berger)
- Fix ipv4-addr definition in interface.rng (Laine Stump)
- remote_driver.c: fix non-literal format strings w/o args (Laine Stump)
- ignore SELinuxSetFilecon error in SELinuxSetSecurityFileLabel if on nfs (Laine Stump)
- Fix reference counting bug in virsh console (Daniel P. Berrange)
- Fix busy-wait loop on closed file descriptor (Daniel P. Berrange)
- Fix LXC container console device setup (Daniel P. Berrange)
- rpm: fix /var/lib/libvirt permissions (Eric Blake)
- xencapstest: Don't fail when Xen is installed (Matthias Bolte)
- virsh: fix non-literal string format (Laine Stump)
- Fix syntax-check error in domain.rng (Matthias Bolte)
- qemu: Fix non-literal format string (Jiri Denemark)
- macvtap: libvirtd forgot macvtap dev name when restarted (Stefan Berger)
- tests: fix daemon-conf testing failure (Osier Yang)
- Fix virPipeReadUntilEOF on more than 1024 bytes of data (Daniel Veillard)
- Misc error handling fixes in text mode monitor commands (Daniel P. Berrange)
- Ignore open failures when relabelling disk images (Daniel P. Berrange)
- Treat failure to relabel stdin_path as non-fatal on NFS (Daniel P. Berrange)
- qemu: add the USB devices to the cgroup whitelist (Diego Elio Pettenò)
Improvements:
- Log client errors in libvirtd at debug priority
- maint: prohibit most uses of xmlGetProp (Eric Blake)
- maint: ensure syntax check exceptions are distributed (Eric Blake)
- Implementations of virDomainIsUpdated for drivers except qemu (Osier Yang)
- implement callback function for qemu driver (Osier Yang)
- implement the remote protocol (Osier Yang)
- implement public API virDomainIsUpdated (Osier Yang)
- define internal driver API (Osier Yang)
- tests: Fix dispatching internal error reports (Cole Robinson)
- Improve SCSI volume name generation (Daniel P. Berrange)
- Fix error codes returned when a storage pool is inactive (Daniel P. Berrange)
- Check whether pools are already active upon libvirtd startup (Daniel P. Berrange)
- Allow iSCSI IQN to be set with find-storage-pool-sources-as command (Daniel P. Berrange)
- Switch the virsh XML generation to use virBuffer instead of virAsprintf (Daniel P. Berrange)
- Stop iSCSI targets automatically logging back in after logout (Daniel P. Berrange)
- Refactor iSCSI driver code to facilitate future changes (Daniel P. Berrange)
- Ensure virExec preserves logging environment (Daniel P. Berrange)
- Include a thread identifier in log messages (Daniel P. Berrange)
- qemu: setvcpus: Save config changes to disk (Cole Robinson)
- qemu: setvcpus: Simplify altering the persistent config (Cole Robinson)
- qemu: setvcpus: Fix maxvcpus check (Cole Robinson)
- conf: domain: Improve vcpus validation reporting (Cole Robinson)
- Make state driver device hotplug/update actually transient (Cole Robinson)
- domain_conf: Add virDomainObjSetDefTransient (Cole Robinson)
- buf: Simplify virBufferEscapeString (Cole Robinson)
- conf: Convert ParseString to use STRPREFIX (Cole Robinson)
- schemas: domain: Add more valid file path chars (Cole Robinson)
- qed: Minor updates to QED support patches (Adam Litke)
- Support for probing qed image metadata (Adam Litke)
- storage_file: Add a new flag to mark backing files that are safe to probe (Adam Litke)
- Allow probing of image formats without version information (Adam Litke)
- maint: tighten strncmp syntax check (Eric Blake)
- capabilities, cpu: use new array API (Eric Blake)
- memory: make it easier to avoid quadratic scaling of arrays (Eric Blake)
- memory: make it safer to expand arrays (Eric Blake)
- build: fix autobuild failures on gcov upgrade (Eric Blake)
- virt-aa-helper: translate error messages (Eric Blake)
- maint: update to latest gnulib (Eric Blake)
- deprecate fclose() and introduce VIR_{FORCE_}FCLOSE() (Stefan Berger)
- qemu: record timestamp in qemu domain log (Osier Yang)
- virsh: add net-info command (Osier Yang)
- interface.rng: Make miimon and arpmon optional for bond interfaces (Laine Stump)
- macvtap: convert send / recv function to use libnl (Stefan Berger)
- configure: Remove bashism and replace 'test ==' with 'test =' (Matthias Bolte)
- virsh: Fix compile error in VPATH build (Matthias Bolte)
- qemu: Remove unnecessary quoting from the process name argument (John Morrissey)
- phyp: Don't do a flags check in the storage driver (Matthias Bolte)
- qemu: Add qemu-system-s390x to the emulators list (Matthias Bolte)
- macvtap: convert nl msg construction to use libnl (Stefan Berger)
- Do a better job of validating IP and MAC addresses in network.rng (Laine Stump)
- virt-aa-helper should require <uuid> in XML (Jamie Strandboge)
- esx: Support SMBIOS host mode (Matthias Bolte)
- Wire up virDomainOpenConsole for LXC, Xen and UML (Daniel P. Berrange)
- Re-write virsh console to use streams (Daniel P. Berrange)
- Convert daemon/events.c to use virMutex and virThread (Daniel P. Berrange)
- Introduce portability APIs for creating threads (Daniel P. Berrange)
- Support virDomainOpenConsole with QEMU (Daniel P. Berrange)
- Add a generic internal API for handling any FD based stream (Daniel P. Berrange)
- Lower logging level in remote driver streams (Daniel P. Berrange)
- Remote driver client and server for virDomainOpenConsole (Daniel P. Berrange)
- Support callbacks on virStream APIs in remote driver client (Daniel P. Berrange)
- virsh: supply long option for -V (Eric Blake)
- qemu: Add flag to force a CDROM eject (Cole Robinson)
- Allow non-file disk backingStores (Adam Litke)
- bye to close(), welcome to VIR_(FORCE_)CLOSE() (Stefan Berger)
- esx: Add support for memtune/min_guarantee (Matthias Bolte)
- schema: Move timer element inside clock (Jiri Denemark)
- Misc test case fixes for SPICE (Daniel P. Berrange)
- virsh: Add .xml suffix to tmp files used in *edit commands (Jiri Denemark)
- Support SPICE channel security options (Daniel P. Berrange)
- Support multiple QXL video cards (Daniel P. Berrange)
- Define XML syntax for password expiry (Daniel P. Berrange)
- Add SPICE support for QEMU driver configuration file (Daniel P. Berrange)
- Support automatic port number allocation for SPICE (Daniel P. Berrange)
- Implement QEMU/KVM QXL video card support in QEMU driver (Daniel P. Berrange)
- Add a <graphics> type for SPICE protocol (Daniel P. Berrange)
- Add a QXL graphics card type to domain XML schema (Daniel P. Berrange)
- Show compiled in options in virsh -V (Daniel Veillard)
- lxc: Exit on first error in lxcDomainGetMemoryParameters (Matthias Bolte)
- Allow virDomainGetMemoryParameters on read-only connections (Matthias Bolte)
- Add a new test for sysinfo and smbios handling (Daniel Veillard)
- Add sysinfo/smbios support to the QEmu driver (Daniel Veillard)
- Read the host sysinfo for the QEmu driver (Daniel Veillard)
- Add smbios element to schema and configuration to HVM os (Daniel Veillard)
- Sysinfo parsing and saving to/from configuration files (Daniel Veillard)
- Sysinfo extension to relax-ng schemas (Daniel Veillard)
- Change calling conventions in remote driver client internals (Daniel P. Berrange)
- util: Add helper function to build timestamp string (Osier Yang)
- misc: encode the Emacs suggstions from HACKING into a .dir-locals.el file (Diego Elio Pettenò)
- add compression support for "virsh dump" (KAMEZAWA Hiroyuki)
- qemu_driver: add virCgroupMounted (Lai Jiangshan)
Cleanups:
- tests: Fix detection of expected errors (Jiri Denemark)
- Remove bogus check for Xen in example program (Daniel P. Berrange)
- build: enforce files.h usage (Eric Blake)
- maint: sort exports (Eric Blake)
- Remove bogus port handling code in virsh (Daniel P. Berrange)
- Remove trailing ':' from timestamp (Daniel P. Berrange)
- Log all errors at level INFO to stop polluting syslog (Daniel P. Berrange)
- daemon: use safer memory growth macros (Eric Blake)
- maint: avoid remaining sprintf uses (Eric Blake)
- maint: use gnulib configmake rather than open-coding things (Eric Blake)
- replace last instances of close() (Stefan Berger)
- daemon: fix indention problem in daemon/libvirt.c (Osier Yang)
- qemu: fix typos in qemu_monitor_text.c (Osier Yang)
- re-indent network.rng following structural change (Laine Stump)
- Put network.rng contents inside <grammar> for uniformity with other RNGs (Laine Stump)
- maint: Commit .gitignore sorting done by bootstrap (Jiri Denemark)
- xen-proxy: Remove it entirely and use libvirtd instead (Matthias Bolte)
- qemu: Remove redundant slash in save directory path (Matthias Bolte)
- virterror: supply missing spaces (Eric Blake)
- Fix several warnings about a non-literal format string (Jiri Denemark)
- build: avoid compiler warning in xen code (Eric Blake)
Thanks everybody for their input, ideas, patches or documentation
used in this release !
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel(a)veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
14 years
[libvirt] [PATCHv2 0/8] virCommand: next round
by Eric Blake
This should address some of the review comments from the first round
(https://www.redhat.com/archives/libvir-list/2010-November/msg00803.html).
Daniel P. Berrange (5):
Introduce new APIs for spawning processes
virCommand: docs for usage of new command APIs
Port hooks and iptables code to new command execution APIs
uml: convert to virCommand
Remove bogus includes
Eric Blake (3):
util: add virVasprintf
util: fix saferead type
qemu: convert to virCommand
.x-sc_avoid_write | 1 +
.x-sc_prohibit_asprintf | 4 +-
cfg.mk | 3 +-
docs/Makefile.am | 11 +-
docs/internals.html.in | 9 +
docs/internals/command.html.in | 550 +++++++++++++++++++
docs/sitemap.html.in | 4 +
docs/subsite.xsl | 25 +
po/POTFILES.in | 1 +
src/Makefile.am | 1 +
src/conf/domain_conf.c | 1 -
src/libvirt_private.syms | 36 ++
src/qemu/qemu_conf.c | 710 ++++++++++---------------
src/qemu/qemu_conf.h | 10 +-
src/qemu/qemu_driver.c | 190 ++------
src/uml/uml_conf.c | 163 ++-----
src/uml/uml_conf.h | 10 +-
src/uml/uml_driver.c | 68 +--
src/util/command.c | 1138 ++++++++++++++++++++++++++++++++++++++++
src/util/command.h | 260 +++++++++
src/util/hooks.c | 217 +--------
src/util/iptables.c | 73 +---
src/util/util.c | 85 ++--
src/util/util.h | 8 +-
src/util/virtaudit.c | 2 +-
tests/.gitignore | 4 +
tests/Makefile.am | 18 +-
tests/commanddata/test10.log | 14 +
tests/commanddata/test11.log | 14 +
tests/commanddata/test12.log | 12 +
tests/commanddata/test13.log | 12 +
tests/commanddata/test14.log | 12 +
tests/commanddata/test15.log | 12 +
tests/commanddata/test16.log | 1 +
tests/commanddata/test2.log | 12 +
tests/commanddata/test3.log | 14 +
tests/commanddata/test4.log | 12 +
tests/commanddata/test5.log | 10 +
tests/commanddata/test6.log | 6 +
tests/commanddata/test7.log | 11 +
tests/commanddata/test8.log | 7 +
tests/commanddata/test9.log | 18 +
tests/commandhelper.c | 137 +++++
tests/commandtest.c | 630 ++++++++++++++++++++++
tests/qemuxml2argvtest.c | 68 +--
45 files changed, 3461 insertions(+), 1143 deletions(-)
create mode 100644 docs/internals/command.html.in
create mode 100644 docs/subsite.xsl
create mode 100644 src/util/command.c
create mode 100644 src/util/command.h
create mode 100644 tests/commanddata/test10.log
create mode 100644 tests/commanddata/test11.log
create mode 100644 tests/commanddata/test12.log
create mode 100644 tests/commanddata/test13.log
create mode 100644 tests/commanddata/test14.log
create mode 100644 tests/commanddata/test15.log
create mode 100644 tests/commanddata/test16.log
create mode 100644 tests/commanddata/test2.log
create mode 100644 tests/commanddata/test3.log
create mode 100644 tests/commanddata/test4.log
create mode 100644 tests/commanddata/test5.log
create mode 100644 tests/commanddata/test6.log
create mode 100644 tests/commanddata/test7.log
create mode 100644 tests/commanddata/test8.log
create mode 100644 tests/commanddata/test9.log
create mode 100644 tests/commandhelper.c
create mode 100644 tests/commandtest.c
--
1.7.3.2
14 years