Blame SOURCES/libvirt-qemu-Don-t-fail-if-the-SCSI-host-device-is-shareable-between-domains.patch

c401cc
From b92cd9e9659798b885b9cf0c83c29b1ae6bc699d Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <b92cd9e9659798b885b9cf0c83c29b1ae6bc699d@dist-git>
c401cc
From: Osier Yang <jyang@redhat.com>
c401cc
Date: Sun, 2 Feb 2014 23:09:39 +0800
c401cc
Subject: [PATCH] qemu: Don't fail if the SCSI host device is shareable between
c401cc
 domains
c401cc
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=957292
c401cc
c401cc
It doesn't make sense to fail if the SCSI host device is specified
c401cc
as "shareable" explicitly between domains (NB, it works if and only
c401cc
if the device is specified as "shareable" for *all* domains,
c401cc
otherwise it fails).
c401cc
c401cc
To fix the problem, this patch introduces an array for virSCSIDevice
c401cc
struct, which records all the names of domain which are using the
c401cc
device (note that the recorded domains must specify the device as
c401cc
shareable).  And the change on the data struct brings on many
c401cc
subsequent changes in the code.
c401cc
c401cc
Prior to this patch, the "shareable" tag didn't work as expected,
c401cc
it actually work like "non-shareable".  So this patch also added notes
c401cc
in formatdomain.html to declare the fact.
c401cc
c401cc
* src/util/virscsi.h:
c401cc
  - Remove virSCSIDeviceGetUsedBy
c401cc
  - Change definition of virSCSIDeviceGetUsedBy and virSCSIDeviceListDel
c401cc
  - Add virSCSIDeviceIsAvailable
c401cc
c401cc
* src/util/virscsi.c:
c401cc
  - struct virSCSIDevice: Change "used_by" to be an array; Add
c401cc
    "n_used_by" as the array count
c401cc
  - virSCSIDeviceGetUsedBy: Removed
c401cc
  - virSCSIDeviceFree: frees the "used_by" array
c401cc
  - virSCSIDeviceSetUsedBy: Copy the domain name to avoid potential
c401cc
    memory corruption
c401cc
  - virSCSIDeviceIsAvailable: New
c401cc
  - virSCSIDeviceListDel: Change the logic, for device which is already
c401cc
    in the list, just remove the corresponding entry in "used_by". And
c401cc
    since it's only used in one place, we can safely removing the code
c401cc
    to find out the dev in the list first.
c401cc
  - Copyright updating
c401cc
c401cc
* src/libvirt_private.sys:
c401cc
  - virSCSIDeviceGetUsedBy: Remove
c401cc
  - virSCSIDeviceIsAvailable: New
c401cc
c401cc
* src/qemu/qemu_hostdev.c:
c401cc
  - qemuUpdateActiveScsiHostdevs: Check if the device existing before
c401cc
    adding it to the list;
c401cc
  - qemuPrepareHostdevSCSIDevices: Error out if the not all domains
c401cc
    use the device as "shareable"; Also don't try to add the device
c401cc
    to the activeScsiHostdevs list if it already there; And make
c401cc
    more sensible error w.r.t the current "shareable" value in
c401cc
    driver->activeScsiHostdevs.
c401cc
  - qemuDomainReAttachHostScsiDevices: Change the logic according
c401cc
    to the changes on helpers.
c401cc
c401cc
Signed-off-by: Osier Yang <jyang@redhat.com>
c401cc
(cherry picked from commit fd243fc4ad542b6f9b47615b569f8073dbd1bcea)
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 docs/formatdomain.html.in |  5 +++
c401cc
 src/libvirt_private.syms  |  2 +-
c401cc
 src/qemu/qemu_hostdev.c   | 77 ++++++++++++++++++++++++++---------------------
c401cc
 src/util/virscsi.c        | 44 +++++++++++++++++++++------
c401cc
 src/util/virscsi.h        |  7 +++--
c401cc
 5 files changed, 88 insertions(+), 47 deletions(-)
c401cc
c401cc
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
c401cc
index 994ebed..28cee29 100644
c401cc
--- a/docs/formatdomain.html.in
c401cc
+++ b/docs/formatdomain.html.in
c401cc
@@ -2749,6 +2749,11 @@
c401cc
         between domains (assuming the hypervisor and OS support this).
c401cc
         Only supported by SCSI host device.
c401cc
         Since 1.0.6
c401cc
+        

c401cc
+          Note: Although shareable was introduced
c401cc
+          in 1.0.6, it did not work as
c401cc
+          as expected until 1.2.2.
c401cc
+        

c401cc
       
c401cc
     
c401cc
 
c401cc
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
c401cc
index f5ee380..cda024e 100644
c401cc
--- a/src/libvirt_private.syms
c401cc
+++ b/src/libvirt_private.syms
c401cc
@@ -1855,7 +1855,7 @@ virSCSIDeviceGetSgName;
c401cc
 virSCSIDeviceGetShareable;
c401cc
 virSCSIDeviceGetTarget;
c401cc
 virSCSIDeviceGetUnit;
c401cc
-virSCSIDeviceGetUsedBy;
c401cc
+virSCSIDeviceIsAvailable;
c401cc
 virSCSIDeviceListAdd;
c401cc
 virSCSIDeviceListCount;
c401cc
 virSCSIDeviceListDel;
c401cc
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
c401cc
index 4d613b8..7282b15 100644
c401cc
--- a/src/qemu/qemu_hostdev.c
c401cc
+++ b/src/qemu/qemu_hostdev.c
c401cc
@@ -250,13 +250,14 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
c401cc
     virDomainHostdevDefPtr hostdev = NULL;
c401cc
     size_t i;
c401cc
     int ret = -1;
c401cc
+    virSCSIDevicePtr scsi = NULL;
c401cc
+    virSCSIDevicePtr tmp = NULL;
c401cc
 
c401cc
     if (!def->nhostdevs)
c401cc
         return 0;
c401cc
 
c401cc
     virObjectLock(driver->activeScsiHostdevs);
c401cc
     for (i = 0; i < def->nhostdevs; i++) {
c401cc
-        virSCSIDevicePtr scsi = NULL;
c401cc
         hostdev = def->hostdevs[i];
c401cc
 
c401cc
         if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
c401cc
@@ -271,11 +272,18 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
c401cc
                                       hostdev->shareable)))
c401cc
             goto cleanup;
c401cc
 
c401cc
-        virSCSIDeviceSetUsedBy(scsi, def->name);
c401cc
-
c401cc
-        if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) {
c401cc
+        if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) {
c401cc
+            if (virSCSIDeviceSetUsedBy(tmp, def->name) < 0) {
c401cc
+                virSCSIDeviceFree(scsi);
c401cc
+                goto cleanup;
c401cc
+            }
c401cc
             virSCSIDeviceFree(scsi);
c401cc
-            goto cleanup;
c401cc
+        } else {
c401cc
+            if (virSCSIDeviceSetUsedBy(scsi, def->name) < 0 ||
c401cc
+                virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) {
c401cc
+                virSCSIDeviceFree(scsi);
c401cc
+                goto cleanup;
c401cc
+            }
c401cc
         }
c401cc
     }
c401cc
     ret = 0;
c401cc
@@ -1117,24 +1125,29 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
c401cc
     for (i = 0; i < count; i++) {
c401cc
         virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
c401cc
         if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) {
c401cc
-            const char *other_name = virSCSIDeviceGetUsedBy(tmp);
c401cc
+            bool scsi_shareable = virSCSIDeviceGetShareable(scsi);
c401cc
+            bool tmp_shareable = virSCSIDeviceGetShareable(tmp);
c401cc
 
c401cc
-            if (other_name)
c401cc
-                virReportError(VIR_ERR_OPERATION_INVALID,
c401cc
-                               _("SCSI device %s is in use by domain %s"),
c401cc
-                               virSCSIDeviceGetName(tmp), other_name);
c401cc
-            else
c401cc
+            if (!(scsi_shareable && tmp_shareable)) {
c401cc
                 virReportError(VIR_ERR_OPERATION_INVALID,
c401cc
-                               _("SCSI device %s is already in use"),
c401cc
+                               _("SCSI device %s is already in use by "
c401cc
+                                 "other domain(s) as '%s'"),
c401cc
+                               tmp_shareable ? "shareable" : "non-shareable",
c401cc
                                virSCSIDeviceGetName(tmp));
c401cc
-            goto error;
c401cc
-        }
c401cc
+                goto error;
c401cc
+            }
c401cc
 
c401cc
-        virSCSIDeviceSetUsedBy(scsi, name);
c401cc
-        VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi));
c401cc
+            if (virSCSIDeviceSetUsedBy(tmp, name) < 0)
c401cc
+                goto error;
c401cc
+        } else {
c401cc
+            if (virSCSIDeviceSetUsedBy(scsi, name) < 0)
c401cc
+                goto error;
c401cc
 
c401cc
-        if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0)
c401cc
-            goto error;
c401cc
+            VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi));
c401cc
+
c401cc
+            if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0)
c401cc
+                goto error;
c401cc
+        }
c401cc
     }
c401cc
 
c401cc
     virObjectUnlock(driver->activeScsiHostdevs);
c401cc
@@ -1379,8 +1392,8 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
c401cc
     virObjectLock(driver->activeScsiHostdevs);
c401cc
     for (i = 0; i < nhostdevs; i++) {
c401cc
         virDomainHostdevDefPtr hostdev = hostdevs[i];
c401cc
-        virSCSIDevicePtr scsi, tmp;
c401cc
-        const char *used_by = NULL;
c401cc
+        virSCSIDevicePtr scsi;
c401cc
+        virSCSIDevicePtr tmp;
c401cc
         virDomainDeviceDef dev;
c401cc
 
c401cc
         dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
c401cc
@@ -1410,30 +1423,26 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
c401cc
         /* Only delete the devices which are marked as being used by @name,
c401cc
          * because qemuProcessStart could fail on the half way. */
c401cc
 
c401cc
-        tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi);
c401cc
-        virSCSIDeviceFree(scsi);
c401cc
-
c401cc
-        if (!tmp) {
c401cc
+        if (!(tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) {
c401cc
             VIR_WARN("Unable to find device %s:%d:%d:%d "
c401cc
                      "in list of active SCSI devices",
c401cc
                      hostdev->source.subsys.u.scsi.adapter,
c401cc
                      hostdev->source.subsys.u.scsi.bus,
c401cc
                      hostdev->source.subsys.u.scsi.target,
c401cc
                      hostdev->source.subsys.u.scsi.unit);
c401cc
+            virSCSIDeviceFree(scsi);
c401cc
             continue;
c401cc
         }
c401cc
 
c401cc
-        used_by = virSCSIDeviceGetUsedBy(tmp);
c401cc
-        if (STREQ_NULLABLE(used_by, name)) {
c401cc
-            VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs",
c401cc
-                      hostdev->source.subsys.u.scsi.adapter,
c401cc
-                      hostdev->source.subsys.u.scsi.bus,
c401cc
-                      hostdev->source.subsys.u.scsi.target,
c401cc
-                      hostdev->source.subsys.u.scsi.unit,
c401cc
-                      name);
c401cc
+        VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs",
c401cc
+                   hostdev->source.subsys.u.scsi.adapter,
c401cc
+                   hostdev->source.subsys.u.scsi.bus,
c401cc
+                   hostdev->source.subsys.u.scsi.target,
c401cc
+                   hostdev->source.subsys.u.scsi.unit,
c401cc
+                   name);
c401cc
 
c401cc
-            virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp);
c401cc
-        }
c401cc
+        virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp, name);
c401cc
+        virSCSIDeviceFree(scsi);
c401cc
     }
c401cc
     virObjectUnlock(driver->activeScsiHostdevs);
c401cc
 }
c401cc
diff --git a/src/util/virscsi.c b/src/util/virscsi.c
c401cc
index 23b2890..0d496ae 100644
c401cc
--- a/src/util/virscsi.c
c401cc
+++ b/src/util/virscsi.c
c401cc
@@ -1,6 +1,7 @@
c401cc
 /*
c401cc
  * virscsi.c: helper APIs for managing host SCSI devices
c401cc
  *
c401cc
+ * Copyright (C) 2013-2014 Red Hat, Inc.
c401cc
  * Copyright (C) 2013 Fujitsu, Inc.
c401cc
  *
c401cc
  * This library is free software; you can redistribute it and/or
c401cc
@@ -19,6 +20,7 @@
c401cc
  *
c401cc
  * Authors:
c401cc
  *     Han Cheng <hanc.fnst@cn.fujitsu.com>
c401cc
+ *     Osier Yang <jyang@redhat.com>
c401cc
  */
c401cc
 
c401cc
 #include <config.h>
c401cc
@@ -55,7 +57,8 @@ struct _virSCSIDevice {
c401cc
     char *name; /* adapter:bus:target:unit */
c401cc
     char *id;   /* model:vendor */
c401cc
     char *sg_path; /* e.g. /dev/sg2 */
c401cc
-    const char *used_by; /* name of the domain using this dev */
c401cc
+    char **used_by; /* name of the domains using this dev */
c401cc
+    size_t n_used_by; /* how many domains are using this dev */
c401cc
 
c401cc
     bool readonly;
c401cc
     bool shareable;
c401cc
@@ -256,26 +259,36 @@ cleanup:
c401cc
 void
c401cc
 virSCSIDeviceFree(virSCSIDevicePtr dev)
c401cc
 {
c401cc
+    size_t i;
c401cc
+
c401cc
     if (!dev)
c401cc
         return;
c401cc
 
c401cc
     VIR_FREE(dev->id);
c401cc
     VIR_FREE(dev->name);
c401cc
     VIR_FREE(dev->sg_path);
c401cc
+    for (i = 0; i < dev->n_used_by; i++)
c401cc
+        VIR_FREE(dev->used_by[i]);
c401cc
+    VIR_FREE(dev->used_by);
c401cc
     VIR_FREE(dev);
c401cc
 }
c401cc
 
c401cc
-void
c401cc
+int
c401cc
 virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev,
c401cc
                        const char *name)
c401cc
 {
c401cc
-    dev->used_by = name;
c401cc
+    char *copy = NULL;
c401cc
+
c401cc
+    if (VIR_STRDUP(copy, name) < 0)
c401cc
+        return -1;
c401cc
+
c401cc
+    return VIR_APPEND_ELEMENT(dev->used_by, dev->n_used_by, copy);
c401cc
 }
c401cc
 
c401cc
-const char *
c401cc
-virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev)
c401cc
+bool
c401cc
+virSCSIDeviceIsAvailable(virSCSIDevicePtr dev)
c401cc
 {
c401cc
-    return dev->used_by;
c401cc
+    return dev->n_used_by == 0;
c401cc
 }
c401cc
 
c401cc
 const char *
c401cc
@@ -421,10 +434,23 @@ virSCSIDeviceListSteal(virSCSIDeviceListPtr list,
c401cc
 
c401cc
 void
c401cc
 virSCSIDeviceListDel(virSCSIDeviceListPtr list,
c401cc
-                     virSCSIDevicePtr dev)
c401cc
+                     virSCSIDevicePtr dev,
c401cc
+                     const char *name)
c401cc
 {
c401cc
-    virSCSIDevicePtr ret = virSCSIDeviceListSteal(list, dev);
c401cc
-    virSCSIDeviceFree(ret);
c401cc
+    virSCSIDevicePtr tmp = NULL;
c401cc
+    size_t i;
c401cc
+
c401cc
+    for (i = 0; i < dev->n_used_by; i++) {
c401cc
+        if (STREQ_NULLABLE(dev->used_by[i], name)) {
c401cc
+            if (dev->n_used_by > 1) {
c401cc
+                VIR_DELETE_ELEMENT(dev->used_by, i, dev->n_used_by);
c401cc
+            } else {
c401cc
+                tmp = virSCSIDeviceListSteal(list, dev);
c401cc
+                virSCSIDeviceFree(tmp);
c401cc
+            }
c401cc
+            break;
c401cc
+        }
c401cc
+    }
c401cc
 }
c401cc
 
c401cc
 virSCSIDevicePtr
c401cc
diff --git a/src/util/virscsi.h b/src/util/virscsi.h
c401cc
index 84890be..5bb91ed 100644
c401cc
--- a/src/util/virscsi.h
c401cc
+++ b/src/util/virscsi.h
c401cc
@@ -50,8 +50,8 @@ virSCSIDevicePtr virSCSIDeviceNew(const char *adapter,
c401cc
                                   bool shareable);
c401cc
 
c401cc
 void virSCSIDeviceFree(virSCSIDevicePtr dev);
c401cc
-void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name);
c401cc
-const char *virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev);
c401cc
+int virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name);
c401cc
+bool virSCSIDeviceIsAvailable(virSCSIDevicePtr dev);
c401cc
 const char *virSCSIDeviceGetName(virSCSIDevicePtr dev);
c401cc
 unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev);
c401cc
 unsigned int virSCSIDeviceGetBus(virSCSIDevicePtr dev);
c401cc
@@ -83,7 +83,8 @@ int virSCSIDeviceListCount(virSCSIDeviceListPtr list);
c401cc
 virSCSIDevicePtr virSCSIDeviceListSteal(virSCSIDeviceListPtr list,
c401cc
                                         virSCSIDevicePtr dev);
c401cc
 void virSCSIDeviceListDel(virSCSIDeviceListPtr list,
c401cc
-                          virSCSIDevicePtr dev);
c401cc
+                          virSCSIDevicePtr dev,
c401cc
+                          const char *name);
c401cc
 virSCSIDevicePtr virSCSIDeviceListFind(virSCSIDeviceListPtr list,
c401cc
                                        virSCSIDevicePtr dev);
c401cc
 
c401cc
-- 
c401cc
1.8.5.4
c401cc