[libvirt] [PATCH 09/10] qemu: Add hotplug support for scsi host device

Osier Yang jyang at redhat.com
Fri Apr 26 20:15:33 UTC 2013


From: Han Cheng <hanc.fnst at cn.fujitsu.com>

This adds both attachment and detachment support for scsi host
device.

Signed-off-by: Han Cheng <hanc.fnst at cn.fujitsu.com>
Signed-off-by: Osier Yang <jyang at redhat>

---
v2.5 - v3:
  * Rebase and small changes.
---
 src/qemu/qemu_hotplug.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 145 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index eb3ac52..4e17e19 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1153,7 +1153,7 @@ int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver,
         goto cleanup;
 
     if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
-        virUSBDevicePtr tmp_usb;
+        virUSBDevicePtr tmp_usb = NULL;
 
         if ((usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                                    hostdev->source.subsys.u.usb.device,
@@ -1193,6 +1193,93 @@ cleanup:
     return ret;
 }
 
+static int
+qemuDomainAttachHostScsiDevice(virQEMUDriverPtr driver,
+                               virDomainObjPtr vm,
+                               virDomainHostdevDefPtr hostdev)
+{
+    int ret = -1;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    char *devstr = NULL;
+    char *drvstr = NULL;
+
+    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE) ||
+        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) ||
+        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("SCSI passthrough is not supported by this version of qemu"));
+        return -1;
+    }
+
+    if (qemuPrepareHostdevSCSIDevices(driver, vm->def->name,
+                                      &hostdev, 1)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unable to prepare scsi hostdev: %s:%d:%d:%d"),
+                       hostdev->source.subsys.u.scsi.adapter,
+                       hostdev->source.subsys.u.scsi.bus,
+                       hostdev->source.subsys.u.scsi.target,
+                       hostdev->source.subsys.u.scsi.unit);
+        return -1;
+    }
+
+    if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, 0) < 0)
+        goto cleanup;
+
+    if (!(drvstr = qemuBuildSCSIHostdevDrvStr(hostdev, priv->qemuCaps)))
+        goto cleanup;
+
+    if (!(devstr = qemuBuildSCSIHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
+        goto cleanup;
+
+    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) {
+        virSCSIDevicePtr scsi;
+
+        if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
+                                      hostdev->source.subsys.u.scsi.bus,
+                                      hostdev->source.subsys.u.scsi.target,
+                                      hostdev->source.subsys.u.scsi.unit,
+                                      hostdev->readonly)))
+            goto cleanup;
+
+        if (virSCSIDeviceFileIterate(scsi, qemuSetupHostScsiDeviceCgroup,
+                                     vm) < 0) {
+            virSCSIDeviceFree(scsi);
+            goto cleanup;
+        }
+
+        virSCSIDeviceFree(scsi);
+    }
+
+    qemuDomainObjEnterMonitor(driver, vm);
+    if ((ret = qemuMonitorAddDrive(priv->mon, drvstr)) == 0) {
+        if ((ret = qemuMonitorAddDevice(priv->mon, devstr)) < 0) {
+            VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
+                     drvstr, devstr);
+            qemuMonitorDriveDel(priv->mon, drvstr);
+        }
+    }
+    qemuDomainObjExitMonitor(driver, vm);
+
+    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
+    if (ret < 0)
+        goto cleanup;
+
+    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
+
+    ret = 0;
+cleanup:
+    if (ret < 0)
+        qemuDomainReAttachHostScsiDevices(driver, vm->def->name, &hostdev, 1);
+    VIR_FREE(drvstr);
+    VIR_FREE(devstr);
+    return ret;
+}
+
 int qemuDomainAttachHostDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainHostdevDefPtr hostdev)
@@ -1221,6 +1308,12 @@ int qemuDomainAttachHostDevice(virQEMUDriverPtr driver,
             goto error;
         break;
 
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
+        if (qemuDomainAttachHostScsiDevice(driver, vm,
+                                           hostdev) < 0)
+            goto error;
+        break;
+
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("hostdev subsys type '%s' not supported"),
@@ -2433,6 +2526,48 @@ qemuDomainDetachHostUsbDevice(virQEMUDriverPtr driver,
     return ret;
 }
 
+static int
+qemuDomainDetachHostScsiDevice(virQEMUDriverPtr driver,
+                               virDomainObjPtr vm,
+                               virDomainHostdevDefPtr detach)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    char *drvstr = NULL;
+    char *devstr = NULL;
+    int ret = -1;
+
+    if (!detach->info->alias) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       "%s", _("device cannot be detached without a device alias"));
+        return -1;
+    }
+
+    if (!(drvstr = qemuBuildSCSIHostdevDrvStr(detach, priv->qemuCaps)))
+        goto cleanup;
+    if (!(devstr = qemuBuildSCSIHostdevDevStr(vm->def, detach, priv->qemuCaps)))
+        goto cleanup;
+
+    qemuDomainObjEnterMonitor(driver, vm);
+    if ((ret = qemuMonitorDelDevice(priv->mon, detach->info->alias)) == 0) {
+        if ((ret = qemuMonitorDriveDel(priv->mon, drvstr)) < 0) {
+            VIR_WARN("qemuMonitorDriveDel failed on %s (%s)",
+                     detach->info->alias, drvstr);
+            qemuMonitorAddDevice(priv->mon, devstr);
+        }
+    }
+    qemuDomainObjExitMonitor(driver, vm);
+
+    virDomainAuditHostdev(vm, detach, "detach", ret == 0);
+
+    if (ret == 0)
+        qemuDomainReAttachHostScsiDevices(driver, vm->def->name, &detach, 1);
+
+cleanup:
+    VIR_FREE(drvstr);
+    VIR_FREE(devstr);
+    return ret;
+}
+
 static
 int qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver,
                                    virDomainObjPtr vm,
@@ -2464,6 +2599,9 @@ int qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver,
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
         ret = qemuDomainDetachHostUsbDevice(driver, vm, detach);
         break;
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
+        ret = qemuDomainDetachHostScsiDevice(driver, vm, detach);
+        break;
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("hostdev subsys type '%s' not supported"),
@@ -2520,6 +2658,12 @@ int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,
                                subsys->u.usb.vendor, subsys->u.usb.product);
             }
             break;
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("host scsi device %s:%d:%d.%d not found"),
+                           subsys->u.scsi.adapter, subsys->u.scsi.bus,
+                           subsys->u.scsi.target, subsys->u.scsi.unit);
+            break;
         default:
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("unexpected hostdev type %d"), subsys->type);
-- 
1.8.1.4




More information about the libvir-list mailing list