This introduces a hash table for qemu driver, to store the shared
disk's info as (@disk_path, @ref_count). @ref_count is the number
of domains which shares the disk.
Since we only care about the disk's cdbfilter (see later patch)
setting for shared disk currently, and cdbfilter is only valid for
block disk, this patch only manages (add/remove hash entry) the
shared disk for block disk.
* src/qemu/qemu_conf.h: (Add member 'sharedDisks' of type
virHashTablePtr; Declare helpers
qemuGetSharedDiskKey, qemuAddSharedDisk
and qemuRemoveSharedDisk)
* src/qemu/qemu_conf.c (Implement the 3 helpers)
* src/qemu/qemu_process.c (Update 'sharedDisks' when domain
starting and shutdown)
* src/qemu/qemu_driver.c (Update 'sharedDisks' when attaching
or detaching disk).
---
src/qemu/qemu_conf.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_conf.h | 12 ++++++
src/qemu/qemu_driver.c | 22 ++++++++++++
src/qemu/qemu_process.c | 15 ++++++++
4 files changed, 135 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index a1b1d04..e25376d 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -553,3 +553,89 @@ qemuDriverCloseCallbackRunAll(virQEMUDriverPtr driver,
virHashForEach(driver->closeCallbacks, qemuDriverCloseCallbackRun, &data);
}
+
+/* Construct the hash key for sharedDisks as "major:minor" */
+char *
+qemuGetSharedDiskKey(const char *disk_path)
+{
+ int major, minor;
+ char *key = NULL;
+ int rc;
+
+ if ((rc = virGetDeviceID(disk_path, &major, &minor)) < 0) {
+ virReportSystemError(-rc,
+ _("Unable to get minor number of device
'%s'"),
+ disk_path);
+ return NULL;
+ }
+
+ if (virAsprintf(&key, "%d:%d", major, minor) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ return key;
+}
+
+/* Increase ref count if the entry already exists, otherwise
+ * add a new entry.
+ */
+int
+qemuAddSharedDisk(virHashTablePtr sharedDisks,
+ const char *disk_path)
+{
+ size_t *ref = NULL;
+ char *key = NULL;
+
+ if (!(key = qemuGetSharedDiskKey(disk_path)))
+ return -1;
+
+ if ((ref = virHashLookup(sharedDisks, key))) {
+ if (virHashUpdateEntry(sharedDisks, key, ++ref) < 0) {
+ VIR_FREE(key);
+ return -1;
+ }
+ } else {
+ if (virHashAddEntry(sharedDisks, key, (void *)0x1)) {
+ VIR_FREE(key);
+ return -1;
+ }
+ }
+
+ VIR_FREE(key);
+ return 0;
+}
+
+/* Decrease the ref count if the entry already exists, otherwise
+ * remove the entry.
+ */
+int
+qemuRemoveSharedDisk(virHashTablePtr sharedDisks,
+ const char *disk_path)
+{
+ size_t *ref = NULL;
+ char *key = NULL;
+
+ if (!(key = qemuGetSharedDiskKey(disk_path)))
+ return -1;
+
+ if (!(ref = virHashLookup(sharedDisks, key))) {
+ VIR_FREE(key);
+ return -1;
+ }
+
+ if (ref != (void *)0x1) {
+ if (virHashUpdateEntry(sharedDisks, key, --ref) < 0) {
+ VIR_FREE(key);
+ return -1;
+ }
+ } else {
+ if (virHashRemoveEntry(sharedDisks, key) < 0) {
+ VIR_FREE(key);
+ return -1;
+ }
+ }
+
+ VIR_FREE(key);
+ return 0;
+}
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 1a39946..225ba55 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -148,6 +148,8 @@ struct _virQEMUDriver {
/* The devices which is are not in use by the host or any guest. */
pciDeviceList *inactivePciHostdevs;
+ virHashTablePtr sharedDisks;
+
virBitmapPtr reservedRemotePorts;
virSysinfoDefPtr hostsysinfo;
@@ -212,4 +214,14 @@ qemuDriverCloseCallback qemuDriverCloseCallbackGet(virQEMUDriverPtr
driver,
void qemuDriverCloseCallbackRunAll(virQEMUDriverPtr driver,
virConnectPtr conn);
+int qemuAddSharedDisk(virHashTablePtr sharedDisks,
+ const char *disk_path)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int qemuRemoveSharedDisk(virHashTablePtr sharedDisks,
+ const char *disk_path)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+char * qemuGetSharedDiskKey(const char *disk_path)
+ ATTRIBUTE_NONNULL(1);
+
#endif /* __QEMUD_CONF_H */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6f0849c..a2700de 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -844,6 +844,9 @@ qemuStartup(bool privileged,
if ((qemu_driver->inactivePciHostdevs = pciDeviceListNew()) == NULL)
goto error;
+ if (!(qemu_driver->sharedDisks = virHashCreate(30, NULL)))
+ goto error;
+
if (privileged) {
if (chown(qemu_driver->libDir, qemu_driver->user, qemu_driver->group)
< 0) {
virReportSystemError(errno,
@@ -1097,6 +1100,7 @@ qemuShutdown(void) {
pciDeviceListFree(qemu_driver->activePciHostdevs);
pciDeviceListFree(qemu_driver->inactivePciHostdevs);
usbDeviceListFree(qemu_driver->activeUsbHostdevs);
+ virHashFree(qemu_driver->sharedDisks);
virCapabilitiesFree(qemu_driver->caps);
qemuCapsCacheFree(qemu_driver->capsCache);
@@ -6041,6 +6045,15 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
VIR_WARN("Failed to teardown cgroup for disk path %s",
NULLSTR(disk->src));
}
+
+ if (ret == 0 &&
+ disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
+ disk->shared) {
+ if (qemuAddSharedDisk(driver->sharedDisks, disk->src) < 0)
+ VIR_WARN("Failed to add disk '%s' to shared disk table",
+ disk->src);
+ }
+
end:
if (cgroup)
virCgroupFree(&cgroup);
@@ -6155,6 +6168,15 @@ qemuDomainDetachDeviceDiskLive(virQEMUDriverPtr driver,
virDomainDiskDeviceTypeToString(disk->type));
break;
}
+
+ if (ret == 0 &&
+ disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
+ disk->shared) {
+ if (qemuRemoveSharedDisk(driver->sharedDisks, disk->src) < 0)
+ VIR_WARN("Failed to remove disk '%s' from shared disk
table",
+ disk->src);
+ }
+
return ret;
}
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index cc0e947..c3ecf6f 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3720,6 +3720,8 @@ int qemuProcessStart(virConnectPtr conn,
/* in case a certain disk is desirous of CAP_SYS_RAWIO, add this */
for (i = 0; i < vm->def->ndisks; i++) {
+ virDomainDiskDefPtr disk = vm->def->disks[i];
+
if (vm->def->disks[i]->rawio == 1)
#ifdef CAP_SYS_RAWIO
virCommandAllowCap(cmd, CAP_SYS_RAWIO);
@@ -3727,6 +3729,11 @@ int qemuProcessStart(virConnectPtr conn,
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Raw I/O is not supported on this platform"));
#endif
+
+ if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK && disk->shared) {
+ if (qemuAddSharedDisk(driver->sharedDisks, disk->src) < 0)
+ goto cleanup;
+ }
}
virCommandSetPreExecHook(cmd, qemuProcessHook, &hookData);
@@ -4123,6 +4130,14 @@ void qemuProcessStop(virQEMUDriverPtr driver,
flags & VIR_QEMU_PROCESS_STOP_MIGRATED);
virSecurityManagerReleaseLabel(driver->securityManager, vm->def);
+ for (i = 0; i < vm->def->ndisks; i++) {
+ virDomainDiskDefPtr disk = vm->def->disks[i];
+
+ if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK && disk->shared) {
+ ignore_value(qemuRemoveSharedDisk(driver->sharedDisks, disk->src));
+ }
+ }
+
/* Clear out dynamically assigned labels */
for (i = 0; i < vm->def->nseclabels; i++) {
if (vm->def->seclabels[i]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
--
1.7.7.6