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

Osier Yang jyang at redhat.com
Tue Dec 18 14:46:05 UTC 2012


This introduces a hash table for qemu driver, to store the shared
disk's info as (@major:minor, @ref_count). @ref_count is the number
of domains which shares the disk.

Since we only care about if the disk support unprivileged SG_IO
commands, and the SG_IO commands only make sense 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 2dd6922..a313f5e 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..a84df07 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