Signed-off-by: Luyao Huang <lhuang(a)redhat.com>
---
src/qemu/qemu_conf.h | 3 +
src/qemu/qemu_driver.c | 4 ++
src/qemu/qemu_process.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 164 insertions(+)
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index ed9cd46..67a5c61 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -46,6 +46,7 @@
# include "virclosecallbacks.h"
# include "virhostdev.h"
# include "virfile.h"
+# include "virshm.h"
# ifdef CPU_SETSIZE /* Linux */
# define QEMUD_CPUMASK_LEN CPU_SETSIZE
@@ -235,6 +236,8 @@ struct _virQEMUDriver {
/* Immutable pointer. Unsafe APIs. XXX */
virHashTablePtr sharedDevices;
+ virShmObjectListPtr shmlist;
+
/* Immutable pointer, self-locking APIs */
virPortAllocatorPtr remotePorts;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b263ce0..f698ef8 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -776,6 +776,9 @@ qemuStateInitialize(bool privileged,
if (qemuMigrationErrorInit(qemu_driver) < 0)
goto error;
+ if (!(qemu_driver->shmlist = virShmObjectListGetDefault()))
+ goto error;
+
if (privileged) {
char *channeldir;
@@ -1085,6 +1088,7 @@ qemuStateCleanup(void)
virObjectUnref(qemu_driver->config);
virObjectUnref(qemu_driver->hostdevMgr);
virHashFree(qemu_driver->sharedDevices);
+ virObjectUnref(qemu_driver->shmlist);
virObjectUnref(qemu_driver->caps);
virQEMUCapsCacheFree(qemu_driver->qemuCapsCache);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index f7eb2b6..7b266e9 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4323,6 +4323,153 @@ qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
}
+static int
+qemuPrepareShmemDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainShmemDefPtr shmem)
+{
+ int ret = -1;
+ virShmObjectPtr tmp;
+ virShmObjectListPtr list = driver->shmlist;
+ bool othercreate = false;
+ char *path = NULL;
+ bool teardownshm = false;
+ int type, fd;
+
+ virObjectLock(list);
+
+ if ((tmp = virShmObjectFindByName(list, shmem->name))) {
+ if (shmem->size != virShmObjectGetSize(tmp)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Shmem object %s is already exists and "
+ "size is not equal require size"),
+ virShmObjectGetName(tmp));
+ goto cleanup;
+ }
+ if (!shmem->shareable) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot use a already exist shmem"
+ " device in a private way"));
+ goto cleanup;
+ } else if (!virShmObjectGetShareable(tmp)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot use a already exist private shmem"
+ " device in a shareable way"));
+ goto cleanup;
+ }
+
+ if (virShmSetUsedDomain(tmp, QEMU_DRIVER_NAME, vm->def->name) < 0)
+ goto cleanup;
+
+ if (virShmObjectSaveState(tmp, virShmObjectListGetStateFilePath(list)) < 0)
+ goto cleanup;
+
+ virObjectUnlock(list);
+ return 0;
+ }
+
+ if (!shmem->server.enabled) {
+ if ((fd = virShmCreate(shmem->name, shmem->size,
+ false, &othercreate, 0600)) < 0)
+ goto cleanup;
+ VIR_FORCE_CLOSE(fd);
+
+ if (virShmBuildPath(shmem->name, &path) < 0)
+ goto cleanup;
+
+ type = VIR_SHM_TYPE_SHM;
+ } else {
+ if (!virFileExists(shmem->server.chr.data.nix.path)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Shmem device server socket is not exist"));
+ goto cleanup;
+ } else {
+ othercreate = true;
+ }
+ type = VIR_SHM_TYPE_SERVER;
+ }
+ teardownshm = true;
+
+ if (!(tmp = virShmObjectNew(shmem->name, shmem->size, path, type, othercreate,
+ shmem->shareable, QEMU_DRIVER_NAME,
vm->def->name)))
+ goto cleanup;
+
+ if (virShmObjectSaveState(tmp, virShmObjectListGetStateFilePath(list)) < 0) {
+ virShmObjectFree(tmp);
+ goto cleanup;
+ }
+
+ if (virShmObjectListAdd(list, tmp) < 0) {
+ virShmObjectFree(tmp);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (ret < 0) {
+ if (teardownshm && !shmem->server.enabled &&
+ !othercreate && virShmUnlink(shmem->name) < 0)
+ VIR_WARN("Unable to unlink shared memory object");
+ }
+ VIR_FREE(path);
+ virObjectUnlock(list);
+ return ret;
+}
+
+
+static int
+qemuCleanUpShmemDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainShmemDefPtr shmem)
+{
+ virShmObjectPtr tmp;
+ virShmObjectListPtr list = driver->shmlist;
+ int ret = -1;
+
+ virObjectLock(list);
+
+ if (!(tmp = virShmObjectFindByName(list, shmem->name))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot find share memory named '%s'"),
+ shmem->name);
+ goto cleanup;
+ }
+ if ((shmem->server.enabled &&
+ virShmObjectGetType(tmp) != VIR_SHM_TYPE_SERVER) ||
+ (!shmem->server.enabled &&
+ virShmObjectGetType(tmp) != VIR_SHM_TYPE_SHM)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Shmem object and shmem device type is not equal"));
+ goto cleanup;
+ }
+
+ if (virShmRemoveUsedDomain(tmp, QEMU_DRIVER_NAME, vm->def->name) < 0)
+ goto cleanup;
+
+ if (virShmObjectSaveState(tmp, virShmObjectListGetStateFilePath(list)) < 0)
+ goto cleanup;
+
+ if (virShmObjectGetUsedDomainNumber(tmp) == 0) {
+ if (!shmem->server.enabled) {
+ if (!virShmObjectGetOtherCreate(tmp) &&
+ virShmUnlink(virShmObjectGetName(tmp)) < 0)
+ VIR_WARN("Unable to unlink shared memory object");
+ }
+
+ if (virShmObjectRemoveStateFile(list, virShmObjectGetName(tmp)) < 0)
+ goto cleanup;
+ virShmObjectListDel(list, tmp);
+ virShmObjectFree(tmp);
+ }
+
+ ret = 0;
+ cleanup:
+ virObjectUnlock(list);
+ return ret;
+}
+
+
static void
qemuLogOperation(virDomainObjPtr vm,
const char *msg,
@@ -4786,6 +4933,11 @@ int qemuProcessStart(virConnectPtr conn,
if (cfg->clearEmulatorCapabilities)
virCommandClearCaps(cmd);
+ for (i = 0; i < vm->def->nshmems; i++) {
+ if (qemuPrepareShmemDevice(driver, vm, vm->def->shmems[i]) < 0)
+ goto cleanup;
+ }
+
/* in case a certain disk is desirous of CAP_SYS_RAWIO, add this */
for (i = 0; i < vm->def->ndisks; i++) {
virDomainDeviceDef dev;
@@ -5438,6 +5590,11 @@ void qemuProcessStop(virQEMUDriverPtr driver,
}
}
+ for (i = 0; i < vm->def->nshmems; i++) {
+ ignore_value(qemuCleanUpShmemDevice(driver, vm,
+ vm->def->shmems[i]));
+ }
+
vm->taint = 0;
vm->pid = -1;
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
--
1.8.3.1