[libvirt] [PATCH v2] build: silence a clang warning in virsh.c
by Ryota Ozaki
This patch shuts up the following warning of clang
on Mac OS X:
virsh.c:2761:22: error: assigning to 'char *' from 'const char [6]' discards qualifiers
[-Werror,-Wincompatible-pointer-types-discards-qualifiers]
rl_readline_name = "virsh";
^ ~~~~~~~
The warning happens because rl_readline_name on Mac OS X is still
'char *', while it is 'const char *' on most platforms. So adding
a cast to (char *) can suppress the warning, although that is not
necessary for other platforms.
Tested on Mac OS X 10.8.5 (clang-500.2.75) and Fedora 19 (gcc 4.8.1).
Signed-off-by: Ryota Ozaki <ozaki.ryota(a)gmail.com>
---
tools/virsh.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 241c5b8..1edffb3 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2757,8 +2757,12 @@ vshReadlineInit(vshControl *ctl)
int max_history = 500;
const char *histsize_str;
- /* Allow conditional parsing of the ~/.inputrc file. */
- rl_readline_name = "virsh";
+ /* Allow conditional parsing of the ~/.inputrc file.
+ * XXX: the cast is necessary for Mac OS X to slient
+ * clang's warning. On Mac OS X, rl_readline_name is
+ * char * while on most platforms it's const char *.
+ */
+ rl_readline_name = (char *) "virsh";
/* Tell the completer that we want a crack first. */
rl_attempted_completion_function = vshReadlineCompletion;
--
1.8.4
11 years
[libvirt] [PATCH] maint: fix comment typos.
by Eric Blake
* src/qemu/qemu_command.c (qemuBuildVolumeString): Fix typo.
* src/qemu/qemu_monitor.c (qemuMonitorSend): Likewise.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Pushing under the trivial rule.
src/qemu/qemu_command.c | 2 +-
src/qemu/qemu_monitor.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 966aa0d..6668fed 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3823,7 +3823,7 @@ qemuBuildVolumeString(virConnectPtr conn,
}
break;
case VIR_STORAGE_VOL_NETWORK:
- /* Keep the compiler quite, qemuTranslateDiskSourcePool already
+ /* Keep the compiler quiet, qemuTranslateDiskSourcePool already
* reported the unsupported error.
*/
break;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 87a7798..f7bf49a 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -943,7 +943,7 @@ int qemuMonitorSend(qemuMonitorPtr mon,
{
int ret = -1;
- /* Check whether qemu quited unexpectedly */
+ /* Check whether qemu quit unexpectedly */
if (mon->lastError.code != VIR_ERR_OK) {
VIR_DEBUG("Attempt to send command while error is set %s",
NULLSTR(mon->lastError.message));
--
1.8.3.1
11 years
[libvirt] [PATCH] RFC: Support QEMU live uprgade
by Zheng Sheng ZS Zhou
Hi all,
Recently QEMU developers are working on a feature to allow upgrading a live QEMU instance to a new version without restarting the VM. This is implemented as live migration between the old and new QEMU process on the same host [1]. Here is the the use case:
1) Guests are running QEMU release 1.6.1.
2) Admin installs QEMU release 1.6.2 via RPM or deb.
3) Admin starts a new VM using the updated QEMU binary, and asks the old
QEMU process to migrate the VM to the newly started VM.
I think it will be very useful to support QEMU live upgrade in libvirt. After some investigations, I found migrating to the same host breaks the current migration code. I'd like to propose a new work flow for QEMU live migration. It is to implement the above step 3).
I add a new API named virDomainQemuLiveUpgrade, and a new domain command in virsh named qemu-live-upgrade. The work flow of virDomainQemuLiveUpgrade is like following.
newDef = deep copy oldVm definition
newVm = create VM using newDef, start QEMU process with all vCPUs paused
oldVm migrate to newVm using unix socket
shutdown oldVm
newPid = newVm->pid
finalDef = live deep copy of newVm definition
Drop the newVm from qemu domain table without shutting down QEMU process
Assign finalDef to oldVm
oldVm attaches to QEMU process newPid using finalDef
resume all vCPUs in oldVm
I wrote a RFC patch to demo this work flow. To try my patch, you can firstly apply the patch, build and install libvirt, then create and start a KVM virtual machine, at last run the following command
virsh qemu-live-upgrade your_domain_name
Check the output of "virsh list" and "ps aux | grep qemu", you will find the virtual machine gets a new id, and a new QEMU process running with different process id. I tested this patch on a Fedora 19 box with QEMU upgraded to 1.6. I'd like to hear your precious opinions on this upgrading flow. I can improve the flow, after we reach an agreement on this, I can start to write a more formal patch.
After the upgrading work flow becomes mature, I want to add a "page-flipping" flag to this new API. The reason is that migrating to localhost requires twice host memory as the original VM does during the upgrading. Thus comes the ongoing development of using the new system call vmsplice to move memory pages between two QEMU instances, so that the kernel can just perform page re-mapping from source QEMU process to destination QEMU process in a zero-copy manner. This is expected to reduce memory consumption and speedup the whole procedure. This mechanism is based on Unix domain socket, pipes and FD inter-process passing magic[2].
The page re-mapping mechanism is transparent to libvirt, all we need to trigger this magic is (1) set QEMU migration capability to enable page re-mapping, (2) start destination QEMU process with "-incoming unix:/path/to/socket", (3) use "unix:/path/to/socket" URI when issuing QMP migration command to the source QEMU process.
This RFC patch is already using Unix socket to migrate QEMU virtual machine. I'll add code to parse and inspect a "page-flipping" flag, and call QEMU monitor to enable this capability. Thanks very much any comments on this patch!
[1] http://lists.nongnu.org/archive/html/qemu-devel/2013-08/msg02916.html
[2] http://lists.gnu.org/archive/html/qemu-devel/2013-09/msg04043.html
>From 2b659584f2cbe676c843ddeaf198c9a8368ff0ff Mon Sep 17 00:00:00 2001
From: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
Date: Wed, 30 Oct 2013 15:36:49 +0800
Subject: [PATCH] RFC: Support QEMU live uprgade
This patch is to support upgrading QEMU version without restarting the
virtual machine.
Add new API virDomainQemuLiveUpgrade(), and a new virsh command
qemu-live-upgrade. virDomainQemuLiveUpgrade() migrates a running VM to
the same host as a new VM with new name and new UUID. Then it shutdown
the original VM and drop the new VM definition without shutdown the QEMU
process of the new VM. At last it attaches original VM to the new QEMU
process.
Firstly the admin installs new QEMU package, then he runs
virsh qemu-live-upgrade domain_name
to trigger our virDomainQemuLiveUpgrade() upgrading flow.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
include/libvirt/libvirt.h.in | 3 +
src/driver.h | 4 +
src/libvirt.c | 23 +++
src/libvirt_public.syms | 1 +
src/qemu/qemu_driver.c | 339 +++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_migration.c | 2 +-
src/qemu/qemu_migration.h | 3 +
src/remote/remote_driver.c | 1 +
src/remote/remote_protocol.x | 19 ++-
tools/virsh-domain.c | 139 ++++++++++++++++++
10 files changed, 532 insertions(+), 2 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 80b2d78..7c87044 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1331,6 +1331,9 @@ int virDomainMigrateGetMaxSpeed(virDomainPtr domain,
unsigned long *bandwidth,
unsigned int flags);
+virDomainPtr virDomainQemuLiveUpgrade(virDomainPtr domain,
+ unsigned int flags);
+
/**
* VIR_NODEINFO_MAXCPUS:
* @nodeinfo: virNodeInfo instance
diff --git a/src/driver.h b/src/driver.h
index 8cd164a..1bafa98 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -686,6 +686,9 @@ typedef int
const char *args,
char ***models,
unsigned int flags);
+typedef virDomainPtr
+(*virDrvDomainQemuLiveUpgrade)(virDomainPtr domain,
+ unsigned int flags);
typedef int
(*virDrvDomainGetJobInfo)(virDomainPtr domain,
@@ -1339,6 +1342,7 @@ struct _virDriver {
virDrvDomainMigrateFinish3Params domainMigrateFinish3Params;
virDrvDomainMigrateConfirm3Params domainMigrateConfirm3Params;
virDrvConnectGetCPUModelNames connectGetCPUModelNames;
+ virDrvDomainQemuLiveUpgrade domainQemuLiveUpgrade;
};
diff --git a/src/libvirt.c b/src/libvirt.c
index 90608ab..9e5ff8a 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -7524,6 +7524,29 @@ error:
/**
+ * virDomainQemuLiveUpgrade:
+ * @domain: a domain object
+ * @flags: bitwise-OR of flags
+ *
+ * Live upgrade qemu binary version of the domain.
+ *
+ * Returns the new domain object if the upgrade was successful,
+ * or NULL in case of error.
+ */
+virDomainPtr
+virDomainQemuLiveUpgrade(virDomainPtr domain,
+ unsigned int flags)
+{
+ VIR_DEBUG("domain=%p, flags=%x", domain, flags);
+ if (!domain->conn->driver->domainQemuLiveUpgrade) {
+ virLibConnError(VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
+ return NULL;
+ }
+ return domain->conn->driver->domainQemuLiveUpgrade(domain, flags);
+}
+
+
+/**
* virNodeGetInfo:
* @conn: pointer to the hypervisor connection
* @info: pointer to a virNodeInfo structure allocated by the user
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index fe9b497..82f0b37 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -637,6 +637,7 @@ LIBVIRT_1.1.1 {
LIBVIRT_1.1.3 {
global:
virConnectGetCPUModelNames;
+ virDomainQemuLiveUpgrade;
} LIBVIRT_1.1.1;
# .... define new API here using predicted next version number ....
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ef1359c..7cd76e0 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -15705,6 +15705,344 @@ qemuConnectGetCPUModelNames(virConnectPtr conn,
}
+static virDomainDefPtr
+virDomainDefLiveCopy(virDomainDefPtr src,
+ virCapsPtr caps,
+ virDomainXMLOptionPtr xmlopt)
+{
+ char *xml;
+ virDomainDefPtr ret;
+ unsigned int flags = VIR_DOMAIN_XML_SECURE;
+
+ /* Easiest to clone via a round-trip through XML. */
+ if (!(xml = virDomainDefFormat(src, flags)))
+ return NULL;
+
+ ret = virDomainDefParseString(xml, caps, xmlopt, -1, flags);
+
+ VIR_FREE(xml);
+ return ret;
+}
+
+
+static virDomainDefPtr
+qemuLiveUpgradeMiniBegin(virQEMUDriverPtr driver, virDomainObjPtr vm) {
+ virCapsPtr caps = NULL;
+ virDomainDefPtr newDef = NULL;
+ virDomainDefPtr result = NULL;
+ char *newName = NULL;
+
+ if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
+ goto cleanup;
+
+ if (!(newDef = virDomainDefCopy(vm->def, caps, driver->xmlopt, true)))
+ goto cleanup;
+
+ if (virAsprintf(&newName, "%s_qemu_live_upgrade", vm->def->name) < 0)
+ goto cleanup;
+
+ VIR_FREE(newDef->name);
+ newDef->name = newName;
+
+ if (-1 == virUUIDGenerate(newDef->uuid))
+ goto cleanup;
+
+ result = newDef;
+ newDef = NULL;
+
+cleanup:
+ virDomainDefFree(newDef);
+ virObjectUnref(caps);
+
+ return result;
+}
+
+static virDomainObjPtr
+qemuLiveUpgradeMiniPrepare(virQEMUDriverPtr driver, virConnectPtr conn,
+ virDomainDefPtr newDef) {
+ virDomainObjPtr newVm = NULL;
+ virDomainObjPtr result = NULL;
+ char *upgradeUri = NULL;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+
+ newVm = virDomainObjListAdd(driver->domains, newDef, driver->xmlopt,
+ VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+ VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, NULL);
+ if (!newVm)
+ goto cleanup;
+ newDef = NULL;
+
+ if (virAsprintf(&upgradeUri, "unix:%s/qemu.live.upgrade.%s.sock",
+ cfg->libDir, newVm->def->name) < 0)
+ goto cleanup;
+
+ if (qemuProcessStart(conn, driver, newVm, upgradeUri, -1, NULL,
+ NULL, VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START,
+ VIR_QEMU_PROCESS_START_PAUSED |
+ VIR_QEMU_PROCESS_START_AUTODESTROY) < 0)
+ goto cleanup;
+
+ result = newVm;
+ newVm = NULL;
+
+cleanup:
+ if (newVm)
+ qemuDomainRemoveInactive(driver, newVm);
+ VIR_FREE(upgradeUri);
+ virDomainDefFree(newDef);
+ virObjectUnref(cfg);
+
+ if (result)
+ virObjectUnlock(result);
+ return result;
+}
+
+static bool
+qemuLiveUpgradeMiniPerform(virQEMUDriverPtr driver, virDomainObjPtr vm,
+ const char *newName) {
+ char *upgradeSock = NULL;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ bool result = false;
+ bool migrate = false;
+ int r = 0;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+
+ if (virAsprintf(&upgradeSock, "%s/qemu.live.upgrade.%s.sock",
+ cfg->libDir, newName) < 0)
+ goto cleanup;
+
+ if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
+ goto cleanup;
+ r = qemuMonitorMigrateToUnix(priv->mon, 0, upgradeSock);
+ qemuDomainObjExitMonitor(driver, vm);
+ migrate = true;
+ if (r < 0)
+ goto cleanup;
+
+ if (!virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest unexpectedly quit"));
+ goto cleanup;
+ }
+
+ if (qemuMigrationWaitForCompletion(driver, vm, QEMU_ASYNC_JOB_NONE,
+ NULL, true) < 0)
+ goto cleanup;
+
+ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ if (qemuMigrationSetOffline(driver, vm) < 0)
+ goto cleanup;
+ }
+
+ result = true;
+
+cleanup:
+ /* QEMU memory pages has been re-mapped during the migrate, no way to
+ * continue the original VM */
+ if (migrate)
+ qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED,
+ QEMU_ASYNC_JOB_NONE);
+ VIR_FREE(upgradeSock);
+ virObjectUnref(cfg);
+
+ return result;
+}
+
+static bool
+qemuLiveUpgradeMiniFinish(virQEMUDriverPtr driver, virDomainObjPtr newVm,
+ const char *origName, const unsigned char *origUuid,
+ virDomainDefPtr *newDef, bool *newMonJSON,
+ virDomainChrSourceDefPtr *newMonConf,
+ pid_t *newPid, const char **newPidFile) {
+ virCapsPtr caps = NULL;
+ qemuDomainObjPrivatePtr newPriv = newVm->privateData;
+ bool result = false;
+ size_t i = 0;
+
+ virDomainDefPtr tmpDef = NULL;
+ virDomainChrSourceDefPtr tmpMonConf = NULL;
+ char *tmpPidFile = NULL;
+
+ if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
+ goto abort;
+
+ newVm->persistent = 0;
+ qemuProcessAutoDestroyRemove(driver, newVm);
+
+ if (!(tmpDef = virDomainDefLiveCopy(newVm->def, caps, driver->xmlopt)))
+ goto abort;
+
+ VIR_FREE(tmpDef->name);
+ if (VIR_STRDUP(tmpDef->name, origName) < 0) {
+ goto abort;
+ }
+
+ for (i=0; i < VIR_UUID_BUFLEN; ++i) {
+ tmpDef->uuid[i] = origUuid[i];
+ }
+
+ if (VIR_ALLOC(tmpMonConf) < 0)
+ goto abort;
+
+ if (virDomainChrSourceDefCopy(tmpMonConf, newPriv->monConfig) < 0)
+ goto abort;
+
+ if (VIR_STRDUP(tmpPidFile, newPriv->pidfile) < 0)
+ goto abort;
+
+ if (newPriv->mon) {
+ qemuMonitorClose(newPriv->mon);
+ newPriv->mon = NULL;
+ }
+
+ *newPid = newVm->pid;
+ *newPidFile = tmpPidFile;
+ *newDef = tmpDef;
+ *newMonConf = tmpMonConf;
+ *newMonJSON = newPriv->monJSON;
+ result = true;
+
+cleanup:
+ virObjectUnref(caps);
+
+ qemuDomainRemoveInactive(driver, newVm);
+ return result;
+
+abort:
+ VIR_FREE(tmpPidFile);
+ virDomainChrSourceDefFree(tmpMonConf);
+ virDomainDefFree(tmpDef);
+ qemuProcessStop(driver, newVm, VIR_DOMAIN_SHUTOFF_MIGRATED,
+ QEMU_ASYNC_JOB_NONE);
+ goto cleanup;
+}
+
+static virDomainPtr
+qemuLiveUpgradeMiniConfirm(virQEMUDriverPtr driver, virConnectPtr conn,
+ virDomainDefPtr newDef, bool newMonJSON,
+ virDomainChrSourceDefPtr newMonConf,
+ pid_t newPid, const char *newPidFile) {
+ virDomainPtr newDom = NULL;
+ virDomainObjPtr newVm = NULL;
+ int r = 0;
+
+ if (!(newVm = virDomainObjListAdd(driver->domains, newDef, driver->xmlopt,
+ 0, NULL)))
+ goto cleanup;
+ newDef = NULL;
+ newVm->def->id = -1;
+
+ VIR_SHRINK_N(newVm->def->seclabels, newVm->def->nseclabels, newVm->def->nseclabels);
+ if (virSecurityManagerGenLabel(driver->securityManager, newVm->def) < 0)
+ goto cleanup;
+ r = qemuProcessAttach(conn, driver, newVm, newPid,
+ newPidFile, newMonConf, newMonJSON);
+ newMonConf = NULL;
+ if (r < 0)
+ goto cleanup;
+
+ if (qemuProcessStartCPUs(driver, newVm, conn,
+ VIR_DOMAIN_RUNNING_MIGRATED,
+ QEMU_ASYNC_JOB_NONE) < 0) {
+ qemuProcessStop(driver, newVm, VIR_DOMAIN_SHUTOFF_FAILED,
+ VIR_QEMU_PROCESS_STOP_MIGRATED);
+ goto cleanup;
+ }
+ newDom = virGetDomain(conn, newVm->def->name, newVm->def->uuid);
+
+cleanup:
+ VIR_FREE(newPidFile);
+ virDomainChrSourceDefFree(newMonConf);
+ virDomainDefFree(newDef);
+ if (newVm)
+ virObjectUnlock(newVm);
+
+ return newDom;
+}
+
+static virDomainPtr
+qemuDomObjQemuLiveUpgrade(virQEMUDriverPtr driver, virConnectPtr conn,
+ virDomainObjPtr vm, unsigned int flags) {
+ char *origName = NULL;
+ unsigned char origUuid[VIR_UUID_BUFLEN];
+ size_t i = 0;
+ virDomainPtr newDom = NULL;
+ virDomainDefPtr newDef = NULL;
+ virDomainObjPtr newVm = NULL;
+ virDomainChrSourceDefPtr newMonConf = NULL;
+ bool newMonJSON = false;
+ pid_t newPid = -1;
+ const char * newPidFile = NULL;
+ virDomainDefPtr finalDef = NULL;
+
+ VIR_DEBUG("vm=%p, flags=%x", vm, flags);
+
+ if (!(newDef = qemuLiveUpgradeMiniBegin(driver, vm)))
+ goto cleanup;
+
+ virObjectUnlock(vm);
+ newVm = qemuLiveUpgradeMiniPrepare(driver, conn, newDef);
+ virObjectLock(vm);
+ newDef = NULL;
+ if (!newVm) {
+ goto cleanup;
+ }
+
+ if (!qemuLiveUpgradeMiniPerform(driver, vm, newVm->def->name)) {
+ goto cleanup;
+ }
+
+ if (VIR_STRDUP(origName, vm->def->name) < 0)
+ goto cleanup;
+ for (i=0; i < VIR_UUID_BUFLEN; ++i) {
+ origUuid[i] = vm->def->uuid[i];
+ }
+ virObjectUnlock(vm);
+ vm = NULL;
+
+ if (!qemuLiveUpgradeMiniFinish(driver, newVm, origName, origUuid,
+ &finalDef, &newMonJSON, &newMonConf, &newPid,
+ &newPidFile))
+ goto cleanup;
+ newVm = NULL;
+
+ newDom = qemuLiveUpgradeMiniConfirm(driver, conn, finalDef, newMonJSON,
+ newMonConf, newPid, newPidFile);
+ finalDef = NULL;
+ newMonConf = NULL;
+ newPidFile = NULL;
+
+cleanup:
+ VIR_FREE(origName);
+ if (newVm)
+ qemuDomainRemoveInactive(driver, newVm);
+ if (vm)
+ virObjectUnlock(vm);
+
+ return newDom;
+}
+
+static virDomainPtr
+qemuDomainQemuLiveUpgrade(virDomainPtr domain,
+ unsigned int flags)
+{
+ virQEMUDriverPtr driver = domain->conn->privateData;
+ virDomainObjPtr vm = NULL;
+
+ VIR_DEBUG("domain=%p, flags=%x", domain, flags);
+
+ if (!(vm = qemuDomObjFromDomain(domain)))
+ return NULL;
+
+ if (virDomainQemuLiveUpgradeEnsureACL(domain->conn, vm->def) < 0) {
+ virObjectUnlock(vm);
+ return NULL;
+ }
+
+ return qemuDomObjQemuLiveUpgrade(driver, domain->conn, vm, flags);
+}
+
+
static virDriver qemuDriver = {
.no = VIR_DRV_QEMU,
.name = QEMU_DRIVER_NAME,
@@ -15892,6 +16230,7 @@ static virDriver qemuDriver = {
.domainMigrateFinish3Params = qemuDomainMigrateFinish3Params, /* 1.1.0 */
.domainMigrateConfirm3Params = qemuDomainMigrateConfirm3Params, /* 1.1.0 */
.connectGetCPUModelNames = qemuConnectGetCPUModelNames, /* 1.1.3 */
+ .domainQemuLiveUpgrade = qemuDomainQemuLiveUpgrade, /* 1.1.3 */
};
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index a3d986f..f859936 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1686,7 +1686,7 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
}
-static int
+int
qemuMigrationWaitForCompletion(virQEMUDriverPtr driver, virDomainObjPtr vm,
enum qemuDomainAsyncJob asyncJob,
virConnectPtr dconn, bool abort_on_error)
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index cafa2a2..48b2009 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -162,6 +162,9 @@ int qemuMigrationConfirm(virConnectPtr conn,
int cookieinlen,
unsigned int flags,
int cancelled);
+int qemuMigrationWaitForCompletion(virQEMUDriverPtr driver, virDomainObjPtr vm,
+ enum qemuDomainAsyncJob asyncJob,
+ virConnectPtr dconn, bool abort_on_error);
bool qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm,
virDomainDefPtr def, bool remote,
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 7181949..cfa70bd 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -7013,6 +7013,7 @@ static virDriver remote_driver = {
.domainMigrateFinish3Params = remoteDomainMigrateFinish3Params, /* 1.1.0 */
.domainMigrateConfirm3Params = remoteDomainMigrateConfirm3Params, /* 1.1.0 */
.connectGetCPUModelNames = remoteConnectGetCPUModelNames, /* 1.1.3 */
+ .domainQemuLiveUpgrade = remoteDomainQemuLiveUpgrade, /* 1.1.3 */
};
static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index f942670..25f35b2 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2849,6 +2849,15 @@ struct remote_connect_get_cpu_model_names_ret {
int ret;
};
+struct remote_domain_qemu_live_upgrade_args {
+ remote_nonnull_domain dom;
+ unsigned int flags;
+};
+
+struct remote_domain_qemu_live_upgrade_ret {
+ remote_nonnull_domain domUpgraded;
+};
+
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
@@ -5018,5 +5027,13 @@ enum remote_procedure {
* @generate: none
* @acl: connect:read
*/
- REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES = 312
+ REMOTE_PROC_CONNECT_GET_CPU_MODEL_NAMES = 312,
+
+ /**
+ * @generate: both
+ * @acl: domain:migrate
+ * @acl: domain:start
+ * @acl: domain:write
+ */
+ REMOTE_PROC_DOMAIN_QEMU_LIVE_UPGRADE = 313
};
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 60abd3d..e0c7997 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -10451,6 +10451,139 @@ cleanup:
return ret;
}
+/*
+ * "qemu-live-upgrade" command
+ */
+static const vshCmdInfo info_qemu_live_upgrade[] = {
+ {.name = "help",
+ .data = N_("Live upgrade QEMU binary version of a running domain")
+ },
+ {.name = "desc",
+ .data = N_("Let the domain make use of a newly upgraded QEMU binary without restart.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_qemu_live_upgrade[] = {
+ {.name = "domain",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("domain name, id or uuid")
+ },
+ {.name = "page-flipping",
+ .type = VSH_OT_BOOL,
+ .help = N_("enable memory page flipping when upgrading the QEMU binray")
+ },
+ {.name = "timeout",
+ .type = VSH_OT_INT,
+ .help = N_("force guest to suspend if QEMU live upgrade exceeds timeout (in seconds)")
+ },
+ {.name = "verbose",
+ .type = VSH_OT_BOOL,
+ .help = N_("display the progress of uprgade")
+ },
+ {.name = NULL}
+};
+
+static void
+doQemuLiveUpgrade(void *opaque)
+{
+ char ret = '1';
+ virDomainPtr dom = NULL;
+ virDomainPtr domUpgraded = NULL;
+ unsigned int flags = 0;
+ vshCtrlData *data = opaque;
+ vshControl *ctl = data->ctl;
+ const vshCmd *cmd = data->cmd;
+ sigset_t sigmask, oldsigmask;
+
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGINT);
+ if (pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask) < 0)
+ goto out_sig;
+
+ if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+ goto out;
+
+ if ((domUpgraded = virDomainQemuLiveUpgrade(dom, flags))) {
+ ret = '0';
+ }
+
+out:
+ pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
+out_sig:
+ if (domUpgraded)
+ virDomainFree(domUpgraded);
+ if (dom)
+ virDomainFree(dom);
+ ignore_value(safewrite(data->writefd, &ret, sizeof(ret)));
+ return;
+}
+
+static void
+vshQemuLiveUpgradeTimeout(vshControl *ctl,
+ virDomainPtr dom,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ vshDebug(ctl, VSH_ERR_DEBUG, "suspending the domain, "
+ "since QEMU live uprgade timed out\n");
+ virDomainSuspend(dom);
+}
+
+static bool
+cmdQemuLiveUpgrade(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom = NULL;
+ int p[2] = {-1, -1};
+ virThread workerThread;
+ bool verbose = false;
+ bool functionReturn = false;
+ int timeout = 0;
+ vshCtrlData data;
+ int rv;
+
+ if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+ return false;
+
+ if (vshCommandOptBool(cmd, "verbose"))
+ verbose = true;
+
+ if ((rv = vshCommandOptInt(cmd, "timeout", &timeout)) < 0 ||
+ (rv > 0 && timeout < 1)) {
+ vshError(ctl, "%s", _("qemu-live-uprgade: Invalid timeout"));
+ goto cleanup;
+ } else if (rv > 0) {
+ /* Ensure that we can multiply by 1000 without overflowing. */
+ if (timeout > INT_MAX / 1000) {
+ vshError(ctl, "%s", _("qemu-live-uprgade: Timeout is too big"));
+ goto cleanup;
+ }
+ }
+
+ if (pipe(p) < 0)
+ goto cleanup;
+
+ data.ctl = ctl;
+ data.cmd = cmd;
+ data.writefd = p[1];
+
+ if (virThreadCreate(&workerThread,
+ true,
+ doQemuLiveUpgrade,
+ &data) < 0)
+ goto cleanup;
+ functionReturn = vshWatchJob(ctl, dom, verbose, p[0], timeout,
+ vshQemuLiveUpgradeTimeout, NULL, _("Upgrade"));
+
+ virThreadJoin(&workerThread);
+
+cleanup:
+ virDomainFree(dom);
+ VIR_FORCE_CLOSE(p[0]);
+ VIR_FORCE_CLOSE(p[1]);
+ return functionReturn;
+}
+
const vshCmdDef domManagementCmds[] = {
{.name = "attach-device",
.handler = cmdAttachDevice,
@@ -10796,6 +10929,12 @@ const vshCmdDef domManagementCmds[] = {
.info = info_qemu_agent_command,
.flags = 0
},
+ {.name = "qemu-live-upgrade",
+ .handler = cmdQemuLiveUpgrade,
+ .opts = opts_qemu_live_upgrade,
+ .info = info_qemu_live_upgrade,
+ .flags = 0
+ },
{.name = "reboot",
.handler = cmdReboot,
.opts = opts_reboot,
--
1.8.3.1
_____________________________
Zhou Zheng Sheng / 周征晟
Software Engineer
E-mail: zhshzhou(a)cn.ibm.com
Telephone: 86-10-82454397
11 years
[libvirt] [PATCH v2]lxc: don't mount dir if ownership couldn't be known
by Chen Hanxiao
From: Chen Hanxiao <chenhanxiao(a)cn.fujitsu.com>
If we enable userns, we could bind mount
some dirs from host to guest, which don't belong to
the target mapped uid/gid.
Such as we could bind mount root's dirs to guest.
What is worse, we could even modify root's files
in that bind dir inside container.
So if we couldn't know
the dir's ownership(without a proper uid/gid mapping),
don't mount it.
Signed-off-by: Chen Hanxiao <chenhanxiao(a)cn.fujitsu.com>
---
v2: add more description
src/lxc/lxc_container.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 255c711..4cf209e 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -96,6 +96,8 @@
typedef char lxc_message_t;
#define LXC_CONTINUE_MSG 'c'
+#define OVERFLOW_UGID 65534
+
typedef struct __lxc_child_argv lxc_child_argv_t;
struct __lxc_child_argv {
virDomainDefPtr config;
@@ -1073,6 +1075,22 @@ static int lxcContainerMountFSBind(virDomainFSDefPtr fs,
if (virAsprintf(&src, "%s%s", srcprefix, fs->src) < 0)
goto cleanup;
+ if (stat(src, &st) < 0) {
+ virReportSystemError(errno, _("Unable to stat bind source %s"),
+ src);
+ goto cleanup;
+ } else {
+ if (OVERFLOW_UGID == st.st_uid || OVERFLOW_UGID == st.st_gid) {
+ errno = EPERM;
+ VIR_DEBUG("Unknown st_uid %d, st_gid %d for %s",
+ st.st_uid, st.st_gid, fs->src);
+ virReportSystemError(errno,
+ _("Check the permission of src dir '%s' provided for container")
+ ,fs->src);
+ goto cleanup;
+ }
+ }
+
if (stat(fs->dst, &st) < 0) {
if (errno != ENOENT) {
virReportSystemError(errno, _("Unable to stat bind target %s"),
--
1.8.2.1
11 years
[libvirt] [RFC PATCH] storage: add network-dir as new storage volume type
by Eric Blake
In the 'directory' and 'netfs' storage pools, a user can see
both 'file' and 'dir' storage volume types, to know when they
can descend into a subdirectory. But in a network-based storage
pool, such as the upcoming 'gluster' pool, we use 'network'
instead of 'file', and did not have any counterpart for a
directory until this patch. Adding a new volume type
'network-dir' is better than reusing 'dir', because it makes
it clear that the only way to access 'network' volumes within
that container is through the network mounting (leaving 'dir'
for something accessible in the local file system).
* include/libvirt/libvirt.h.in (virStorageVolType): Expand enum.
* src/qemu/qemu_command.c (qemuBuildVolumeString): Fix client.
* src/qemu/qemu_conf.c (qemuTranslateDiskSourcePool): Likewise.
* tools/virsh-volume.c (vshVolumeTypeToString): Likewise.
* src/storage/storage_backend_fs.c
(virStorageBackendFileSystemVolDelete): Likewise.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
If you do 'virsh vol-list $pool --details', you'll see various
types of volumes listed in the output. For 'directory' and
'netfs' pools, telling 'dir' and 'file' apart is important.
For my pending 'gluster' work, seeing 'network' everywhere
hides that distinction, hence my proposal of adding a new type.
But as I prepared this patch for posting, I noticed a bigger
problem: we don't expose this information in volume XML, but
only in virStorageVolGetInfo(). So, I'm wondering if I should
pursue this further by enhancing the <volume> XML to _also_
expose this type (currently 'file', 'dir', 'block', or 'network',
and possibly my addition of 'network-dir'), so that callers
can get the information via a single call to
virStorageVolGetXMLDesc() (which already reports everything else
that you can get from virStorageVolGetInfo, and would thus make
it a full superset instead of needing both calls to get the
full picture).
include/libvirt/libvirt.h.in | 2 ++
src/qemu/qemu_command.c | 6 ++++--
src/qemu/qemu_conf.c | 4 +++-
src/storage/storage_backend_fs.c | 5 +++--
tools/virsh-volume.c | 7 +++++--
5 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 146a59b..5e8cba6 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2951,6 +2951,8 @@ typedef enum {
VIR_STORAGE_VOL_BLOCK = 1, /* Block based volumes */
VIR_STORAGE_VOL_DIR = 2, /* Directory-passthrough based volume */
VIR_STORAGE_VOL_NETWORK = 3, /* Network volumes like RBD (RADOS Block Device) */
+ VIR_STORAGE_VOL_NETWORK_DIR = 4, /* Network accessible directory that can
+ * contain other network volumes */
#ifdef VIR_ENUM_SENTINELS
VIR_STORAGE_VOL_LAST
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 6668fed..bf3533b 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3780,7 +3780,7 @@ qemuBuildVolumeString(virConnectPtr conn,
{
int ret = -1;
- switch (disk->srcpool->voltype) {
+ switch ((virStorageVolType) disk->srcpool->voltype) {
case VIR_STORAGE_VOL_DIR:
if (!disk->readonly) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -3823,10 +3823,12 @@ qemuBuildVolumeString(virConnectPtr conn,
}
break;
case VIR_STORAGE_VOL_NETWORK:
+ case VIR_STORAGE_VOL_NETWORK_DIR:
+ case VIR_STORAGE_VOL_LAST:
/* Keep the compiler quiet, qemuTranslateDiskSourcePool already
* reported the unsupported error.
*/
- break;
+ goto cleanup;
}
ret = 0;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 03c9c7d..c9d03b0 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1331,7 +1331,7 @@ qemuTranslateDiskSourcePool(virConnectPtr conn,
goto cleanup;
}
- switch (info.type) {
+ switch ((virStorageVolType) info.type) {
case VIR_STORAGE_VOL_FILE:
case VIR_STORAGE_VOL_DIR:
if (!(def->src = virStorageVolGetPath(vol)))
@@ -1376,6 +1376,8 @@ qemuTranslateDiskSourcePool(virConnectPtr conn,
break;
case VIR_STORAGE_VOL_NETWORK:
+ case VIR_STORAGE_VOL_NETWORK_DIR:
+ case VIR_STORAGE_VOL_LAST:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Using network volume as disk source is not supported"));
goto cleanup;
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index 510a3d6..2af6faf 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -1137,7 +1137,7 @@ virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
{
virCheckFlags(0, -1);
- switch (vol->type) {
+ switch ((virStorageVolType) vol->type) {
case VIR_STORAGE_VOL_FILE:
if (unlink(vol->target.path) < 0) {
/* Silently ignore failures where the vol has already gone away */
@@ -1159,7 +1159,8 @@ virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
break;
case VIR_STORAGE_VOL_BLOCK:
case VIR_STORAGE_VOL_NETWORK:
- default:
+ case VIR_STORAGE_VOL_NETWORK_DIR:
+ case VIR_STORAGE_VOL_LAST:
virReportError(VIR_ERR_NO_SUPPORT,
_("removing block or network volumes is not supported: %s"),
vol->target.path);
diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c
index 55a99d0..377a73b 100644
--- a/tools/virsh-volume.c
+++ b/tools/virsh-volume.c
@@ -1,7 +1,7 @@
/*
* virsh-volume.c: Commands to manage storage volume
*
- * Copyright (C) 2005, 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2005, 2007-2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -946,7 +946,7 @@ out:
static const char *
vshVolumeTypeToString(int type)
{
- switch (type) {
+ switch ((virStorageVolType) type) {
case VIR_STORAGE_VOL_FILE:
return N_("file");
@@ -959,6 +959,9 @@ vshVolumeTypeToString(int type)
case VIR_STORAGE_VOL_NETWORK:
return N_("network");
+ case VIR_STORAGE_VOL_NETWORK_DIR:
+ return N_("net-dir");
+
case VIR_STORAGE_VOL_LAST:
break;
}
--
1.8.3.1
11 years
Re: [libvirt] Fedora 20: libvirt-guest.service is not working
by Eric Blake
[adding upstream libvirt, as this topic seems to be getting hot lately]
On 11/18/2013 04:34 PM, Mateusz Marzantowicz wrote:
> KMV/QEMU guest are not shut down properly during host shutdown
> procedure. One of 3 running virtual machines needs about 20-30 seconds
> to power off but whole host system (F20) goes off in less than 10
> seconds (at last this works perfectly).
There's a good chance that this may be related to one or both of
https://bugzilla.redhat.com/show_bug.cgi?id=1031696
https://bugzilla.redhat.com/show_bug.cgi?id=906009
>
> Not all guests (chosen randomly) are started again after host system
> reboot despite they are configured to do so.
>
> Because identical configuration worked for me in F17 and F19 I suspect
> some regression in libvirtd or systemd (or maybe some other component?)
Entirely possible. And would be nice to fix.
>
> Running /usr/libexec/libvirt-guests.sh stop|start directly from command
> line works as expected.
>
>
> # systemctl status libvirt-guests.service
> libvirt-guests.service - Suspend Active Libvirt Guests
> Loaded: loaded (/usr/lib/systemd/system/libvirt-guests.service; enabled)
> Active: active (exited) since wto 2013-11-19 00:05:10 CET; 2min 21s ago
> Process: 1616 ExecStart=/usr/libexec/libvirt-guests.sh start
> (code=exited, status=0/SUCCESS)
> Main PID: 1616 (code=exited, status=0/SUCCESS)
> CGroup: /system.slice/libvirt-guests.service
>
> lis 19 00:05:10 hive.local systemd[1]: Starting Suspend Active Libvirt
> Guests...
> lis 19 00:05:10 hive.local systemd[1]: Started Suspend Active Libvirt
> Guests.
>
> # cat /etc/sysconfig/libvirt-guests
> ON_SHUTDOWN=shutdown
> PARALLEL_SHUTDOWN=0
> SHUTDOWN_TIMEOUT=300
>
>
> Thanks for any suggestions,
Alas, I don't have good suggestions on how to fix the problem myself,
but hopefully by adding upstream libvirt we can get more eyes looking at
the problem.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
11 years
[libvirt] [PATCH] Pin guest to memory node on NUMA system
by Shivaprasad G Bhat
The patch contains the fix for defect 1009880 reported at redhat bugzilla.
The root cause is, ever since the subcpusets(vcpu,emulator) were introduced, the paren cpuset cannot be modified to remove the nodes that are in use by the subcpusets.
The fix is to break the memory node modification into three steps as to assign new nodes into the parent first. Change the nodes in the child nodes. Then remove the old nodes on the parent node.
Signed-off-by: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
---
src/qemu/qemu_driver.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c613967..4db692e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8193,7 +8193,11 @@ qemuDomainSetNumaParameters(virDomainPtr dom,
}
} else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) {
virBitmapPtr nodeset = NULL;
+ virBitmapPtr old_nodeset = NULL;
+ virBitmapPtr temp_nodeset = NULL;
char *nodeset_str = NULL;
+ char *old_nodeset_str = NULL;
+ char *temp_nodeset_str = NULL;
if (virBitmapParse(params[i].value.s,
0, &nodeset,
@@ -8203,6 +8207,10 @@ qemuDomainSetNumaParameters(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ size_t j;
+ virCgroupPtr cgroup_vcpu = NULL;
+ virCgroupPtr cgroup_emulator = NULL;
+
if (vm->def->numatune.memory.mode !=
VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
@@ -8222,7 +8230,128 @@ qemuDomainSetNumaParameters(virDomainPtr dom,
continue;
}
+ if (virCgroupGetCpusetMems(priv->cgroup, &old_nodeset_str) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Failed to get current system nodeset values"));
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ ret = -1;
+ continue;
+ }
+
+ if (virBitmapParse(old_nodeset_str, 0, &old_nodeset,
+ VIR_DOMAIN_CPUMASK_LEN) < 0) {
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ VIR_FREE(old_nodeset_str);
+ ret = -1;
+ continue;
+ }
+
+ if ((temp_nodeset = virBitmapNewCopy(old_nodeset)) == NULL) {
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ virBitmapFree(old_nodeset);
+ VIR_FREE(old_nodeset_str);
+ ret = -1;
+ continue;
+ }
+ virBitmapFree(old_nodeset);
+ VIR_FREE(old_nodeset_str);
+
+ for (j = 0; j < caps->host.nnumaCell; j++) {
+ bool result;
+ if (virBitmapGetBit(nodeset, j, &result) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Failed to get cpuset bit values"));
+ ret = -1;
+ break;
+ }
+ if (result && (virBitmapSetBit(temp_nodeset, j) < 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Failed to set temporary cpuset bit values"));
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret) {
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ virBitmapFree(temp_nodeset);
+ continue;
+ }
+
+ if (!(temp_nodeset_str = virBitmapFormat(temp_nodeset))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Failed to format nodeset"));
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ virBitmapFree(temp_nodeset);
+ ret = -1;
+ continue;
+ }
+
+ if (virCgroupSetCpusetMems(priv->cgroup, temp_nodeset_str) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Failed to set cpuset values"));
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ virBitmapFree(temp_nodeset);
+ VIR_FREE(temp_nodeset_str);
+ ret = -1;
+ continue;
+ }
+
+ virBitmapFree(temp_nodeset);
+ VIR_FREE(temp_nodeset_str);
+
+ for (j = 0; j < priv->nvcpupids; j++) {
+ if (virCgroupNewVcpu(priv->cgroup, j, false, &cgroup_vcpu) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to get cpuset values for vcpu%d"), j);
+ ret = -1;
+ break;
+ }
+ if (virCgroupSetCpusetMems(cgroup_vcpu, nodeset_str) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to set cpuset values for vcpu%d"), j);
+ virCgroupFree(&cgroup_vcpu);
+ ret = -1;
+ break;
+ }
+ virCgroupFree(&cgroup_vcpu);
+ }
+
+ if (ret) {
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ continue;
+ }
+
+ if (virCgroupNewEmulator(priv->cgroup, false, &cgroup_emulator) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
+ _("Failed to get cpuset values for emulator"));
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ ret = -1;
+ continue;
+ }
+
+ if (virCgroupSetCpusetMems(cgroup_emulator, nodeset_str) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
+ _("Failed to set cpuset values for emulator"));
+ virBitmapFree(nodeset);
+ VIR_FREE(nodeset_str);
+ virCgroupFree(&cgroup_emulator);
+ ret = -1;
+ continue;
+ }
+ virCgroupFree(&cgroup_emulator);
+
if (virCgroupSetCpusetMems(priv->cgroup, nodeset_str) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s"
+ _("Failed to set cpuset"));
virBitmapFree(nodeset);
VIR_FREE(nodeset_str);
ret = -1;
11 years
[libvirt] [PATCHv3] Macro for testing the version you are compiling with
by Doug Goldstein
Added a macro similar to the GLib's GLIB_CHECK_VERSION so that one can
simply do something like:
#if LIBVIR_CHECK_VERSION(1,1,3)
/* Call function here that appeared in 1.1.3 and newer */
virSomeNewFunction();
#endif
---
v3: rename from LIBVIRT_CHECK_VERSION to LIBVIR_CHECK_VERSION
v2: Change from Linux kernel style macro to GLib style macro
---
include/libvirt/libvirt.h.in | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index d656634..146a59b 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1466,6 +1466,22 @@ VIR_EXPORT_VAR virConnectAuthPtr virConnectAuthPtrDefault;
#define LIBVIR_VERSION_NUMBER @LIBVIRT_VERSION_NUMBER@
+/**
+ * LIBVIR_CHECK_VERSION:
+ * @major: major component of the version number
+ * @minor: minor component of the version number
+ * @micro: micro component of the version number
+ *
+ * Macro for developers to easily check what version of the library
+ * their code is compiling against.
+ * e.g.
+ * #if LIBVIR_CHECK_VERSION(1,1,3)
+ * // some code that only works in 1.1.3 and newer
+ * #endif
+ */
+#define LIBVIR_CHECK_VERSION(major, minor, micro) \
+ ((major) * 1000000 + (minor) * 1000 + (micro) <= LIBVIR_VERSION_NUMBER)
+
int virGetVersion (unsigned long *libVer,
const char *type,
unsigned long *typeVer);
--
1.8.3.2
11 years
[libvirt] [PATCH] Avoid async signal safety problem in glibc's setxid
by Daniel P. Berrange
The glibc setxid is supposed to be async signal safe, but
libc developers confirm that it is not. This causes a problem
when libvirt_lxc starts the FUSE thread and then runs clone()
to start the container. If the clone() was done before the
FUSE thread has completely started up, then the container
will hang in setxid after clone().
The fix is to avoid creating any threads until after the
container has been clone()'d. By avoiding any threads in
the parent, the child is no longer required to run in an
async signal safe context, and we thus avoid the glibc
bug.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/lxc/lxc_controller.c | 11 +++++++++--
src/lxc/lxc_fuse.c | 21 +++++++++++++++------
src/lxc/lxc_fuse.h | 1 +
3 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 232af54..c013147 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1983,6 +1983,12 @@ virLXCControllerSetupFuse(virLXCControllerPtr ctrl)
}
static int
+virLXCControllerStartFuse(virLXCControllerPtr ctrl)
+{
+ return lxcStartFuse(ctrl->fuse);
+}
+
+static int
virLXCControllerSetupConsoles(virLXCControllerPtr ctrl,
char **containerTTYPaths)
{
@@ -2187,6 +2193,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
if (virLXCControllerMoveInterfaces(ctrl) < 0)
goto cleanup;
+ if (virLXCControllerStartFuse(ctrl) < 0)
+ goto cleanup;
+
if (lxcContainerSendContinue(control[0]) < 0) {
virReportSystemError(errno, "%s",
_("Unable to send container continue message"));
@@ -2199,8 +2208,6 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
goto cleanup;
}
- /* Now the container is fully setup... */
-
/* ...and reduce our privileges */
if (lxcControllerClearCapabilities() < 0)
goto cleanup;
diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
index 9d12832..88e122e 100644
--- a/src/lxc/lxc_fuse.c
+++ b/src/lxc/lxc_fuse.c
@@ -322,12 +322,6 @@ int lxcSetupFuse(virLXCFusePtr *f, virDomainDefPtr def)
goto cleanup1;
}
- if (virThreadCreate(&fuse->thread, false, lxcFuseRun,
- (void *)fuse) < 0) {
- lxcFuseDestroy(fuse);
- goto cleanup1;
- }
-
ret = 0;
cleanup:
fuse_opt_free_args(&args);
@@ -341,6 +335,17 @@ cleanup2:
goto cleanup;
}
+int lxcStartFuse(virLXCFusePtr fuse)
+{
+ if (virThreadCreate(&fuse->thread, false, lxcFuseRun,
+ (void *)fuse) < 0) {
+ lxcFuseDestroy(fuse);
+ return -1;
+ }
+
+ return 0;
+}
+
void lxcFreeFuse(virLXCFusePtr *f)
{
virLXCFusePtr fuse = *f;
@@ -364,6 +369,10 @@ int lxcSetupFuse(virLXCFusePtr *f ATTRIBUTE_UNUSED,
return 0;
}
+int lxcStartFuse(virLXCFusePtr f ATTRIBUTE_UNUSED)
+{
+}
+
void lxcFreeFuse(virLXCFusePtr *f ATTRIBUTE_UNUSED)
{
}
diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h
index b3713af..d60492b 100644
--- a/src/lxc/lxc_fuse.h
+++ b/src/lxc/lxc_fuse.h
@@ -58,6 +58,7 @@ struct virLXCFuse {
typedef struct virLXCFuse *virLXCFusePtr;
extern int lxcSetupFuse(virLXCFusePtr *f, virDomainDefPtr def);
+extern int lxcStartFuse(virLXCFusePtr f);
extern void lxcFreeFuse(virLXCFusePtr *f);
#endif /* LXC_FUSE_H */
--
1.8.4.2
11 years