[libvirt] [PATCH 2/8] qemu: Add a hash table for the shared disks

Osier Yang jyang at redhat.com
Thu Dec 13 19:05:37 UTC 2012


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    |   92 +++++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_conf.h    |   12 ++++++
 src/qemu/qemu_driver.c  |   22 +++++++++++
 src/qemu/qemu_process.c |   15 ++++++++
 4 files changed, 141 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index a1b1d04..5126a0f 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -553,3 +553,95 @@ 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;
+
+    if ((major = virGetDeviceMajor(disk_path)) < 0) {
+        virReportSystemError(-major,
+                             _("Unable to get major number of device '%s'"),
+                             disk_path);
+        return NULL;
+    }
+
+    if ((minor = virGetDeviceMinor(disk_path)) < 0) {
+        virReportSystemError(-minor,
+                             _("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 *)1) {
+        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




More information about the libvir-list mailing list