[libvirt] [PATCH v3 06/10] qemu: Allow hotplug of vhost-scsi device

John Ferlan jferlan at redhat.com
Fri Nov 11 21:47:57 UTC 2016



On 11/08/2016 01:26 PM, Eric Farman wrote:
> Adjust the device string that is built for vhost-scsi devices so that it
> can be invoked from hotplug.
> 
>>From the QEMU command line, the file descriptors are expect to be numeric only.

s/>//

Looks like a cut-n-paste carryover

> However, for hotplug, the file descriptors are expected to begin with at least
> one alphabetic character else this error occurs:
> 
>   # virsh attach-device guest_0001 ~/vhost.xml
>   error: Failed to attach device from /root/vhost.xml
>   error: internal error: unable to execute QEMU command 'getfd':
>   Parameter 'fdname' expects a name not starting with a digit
> 
> We also close the file descriptor in this case, so that shutting down the
> guest cleans up the host cgroup entries and allows future guests to use
> vhost-scsi devices.  (Otherwise the guest will silently end.)

See you're following the lead of qemuDomainAttachHostPCIDevice for the
'configfd' processing

> 
> Signed-off-by: Eric Farman <farman at linux.vnet.ibm.com>
> ---
>  src/qemu/qemu_hotplug.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 158 insertions(+)
> 
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 2d6b086..d503212 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -2425,6 +2425,120 @@ qemuDomainAttachHostSCSIDevice(virConnectPtr conn,
>      goto cleanup;
>  }
>  
> +static int
> +qemuDomainAttachHostSCSIHostDevice(virQEMUDriverPtr driver,
> +                                   virDomainObjPtr vm,
> +                                   virDomainHostdevDefPtr hostdev)
> +{
> +    int ret = -1;
> +    qemuDomainObjPrivatePtr priv = vm->privateData;

    virErrorPtr orig_err;

> +    virDomainCCWAddressSetPtr ccwaddrs = NULL;
> +    char *vhostfdName = NULL;
> +    int vhostfd = -1;
> +    char *devstr = NULL;
> +    bool teardowncgroup = false;
> +    bool teardownlabel = false;
> +    bool releaseaddr = false;
> +
> +    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("SCSI passthrough is not supported by this version of qemu"));
> +        goto cleanup;
> +    }

Still not clear why SCSI_GENERIC is required - what is the guest device?

> +
> +    if (qemuHostdevPrepareHostDevices(driver, vm->def->name, &hostdev, 1) < 0) {
> +        virDomainHostdevSubsysHostPtr hostsrc = &hostdev->source.subsys.u.host;
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Unable to prepare scsi_host hostdev: %s"),
> +                       hostsrc->wwpn);
> +        goto cleanup;
> +    }
> +
> +    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
> +        goto cleanup;
> +    teardowncgroup = true;
> +
> +    if (virSecurityManagerSetHostdevLabel(driver->securityManager,
> +                                          vm->def, hostdev, NULL) < 0)
> +        goto cleanup;
> +    teardownlabel = true;
> +
> +    if (virHostOpenVhostSCSI(&vhostfd) < 0)
> +        goto cleanup;
> +
> +    if (virAsprintf(&vhostfdName, "vhostfd-%d", vhostfd) < 0)
> +        goto cleanup;
> +
> +    if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
> +        if (qemuDomainMachineIsS390CCW(vm->def) &&
> +            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW))
> +            hostdev->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
> +    }
> +
> +    if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
> +        hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
> +        if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, hostdev->info) < 0)

Here we are doing the PCI address thing, but I don't see patch7
addressing that... That is - no address is defined on the command line
(as seen the the patch9 .args file)

> +            goto cleanup;
> +    } else if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
> +        if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
> +            goto cleanup;
> +        if (virDomainCCWAddressAssign(hostdev->info, ccwaddrs,
> +                                      !hostdev->info->addr.ccw.assigned) < 0)
> +            goto cleanup;
> +    }
> +    releaseaddr = true;
> +
> +    if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
> +        goto cleanup;
> +
> +    if (!(devstr = qemuBuildHostHostdevDevStr(vm->def,
> +                                              hostdev,
> +                                              priv->qemuCaps,
> +                                              vhostfdName)))

If I look at the only other caller of qemuMonitorAddDeviceWithFd I note
that it does this slightly differently...  You may want to check that
out as they should be consistent.

In particular, the configfd_name is a combination of "fd-%s" where %s is
the alias (e.g. perhaps "fd-hostdev4"; whereas, this would seem to
generate "vhostfd-hostdev4"

> +        goto cleanup;
> +
> +    qemuDomainObjEnterMonitor(driver, vm);
> +
> +    ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr, vhostfd, vhostfdName);

    if (qemuMonitorAddDeviceWithFd(...) < 0)
        goto exit_monitor;
> +
> +    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
> +        ret = -1;
> +        goto cleanup;

s/cleanup/audit [1]

The ret = -1 would be pointless and we should just able to alter the
subsequent lines a bit... [1] (see redirdevs for my example)

> +    }
> +
> +    virDomainAuditHostdev(vm, hostdev, "attach", (ret == 0));
> +
> +    if (ret < 0)
> +        goto cleanup;
> +
> +    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
> +        goto cleanup;

Hmmm... so if this fails now, we have the device added to the domain,
but we're failing so we should remove the device... See the problem?

That's why other functions do their REALLOC_N before monitor
interactions... then just add it (as follows) - so move the above 2
lines before the EnterMonitor
> +
> +    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
> +

[1]
    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
    ret = 0;

 audit:
    virDomainAuditHostdev(vm, hostdev, "attach", (ret == 0));

 cleanup:

> +    virDomainCCWAddressSetFree(ccwaddrs);
> +
> +    VIR_FORCE_CLOSE(vhostfd);
> +    VIR_FREE(vhostfdName);
> +    VIR_FREE(devstr);
> +    return 0;
> +
> + cleanup:

s/cleanup/exit_monitor

    orig_err = virSaveLastError();

> +    if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
> +        VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
> +    if (teardownlabel &&
> +        virSecurityManagerRestoreHostdevLabel(driver->securityManager,
> +                                              vm->def, hostdev, NULL) < 0)
> +        VIR_WARN("Unable to restore host device labelling on hotplug fail");
> +    if (releaseaddr)
> +        qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
> +
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }

    goto audit;

Meaning the next 4 aren't necessary.

John

> +    VIR_FORCE_CLOSE(vhostfd);
> +    VIR_FREE(vhostfdName);
> +    VIR_FREE(devstr);
> +    return ret;
> +}
> +
>  
>  int
>  qemuDomainAttachHostDevice(virConnectPtr conn,
> @@ -2458,6 +2572,11 @@ qemuDomainAttachHostDevice(virConnectPtr conn,
>              goto error;
>          break;
>  
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST:
> +        if (qemuDomainAttachHostSCSIHostDevice(driver, vm, hostdev) < 0)
> +            goto error;
> +        break;
> +
>      default:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                         _("hostdev subsys type '%s' not supported"),
> @@ -3549,6 +3668,14 @@ qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver,
>      qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
>  }
>  
> +static void
> +qemuDomainRemoveHostSCSIHostDevice(virQEMUDriverPtr driver,
> +                                   virDomainObjPtr vm,
> +                                   virDomainHostdevDefPtr hostdev)
> +{
> +    qemuHostdevReAttachHostDevices(driver, vm->def->name, &hostdev, 1);
> +}
> +
>  static int
>  qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
>                             virDomainObjPtr vm,
> @@ -3627,6 +3754,7 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
>          qemuDomainRemoveSCSIHostDevice(driver, vm, hostdev);
>          break;
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST:
> +        qemuDomainRemoveHostSCSIHostDevice(driver, vm, hostdev);
>          break;
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          break;
> @@ -4477,6 +4605,31 @@ qemuDomainDetachHostSCSIDevice(virQEMUDriverPtr driver,
>  }
>  
>  static int
> +qemuDomainDetachHostSCSIHostDevice(virQEMUDriverPtr driver,
> +                                   virDomainObjPtr vm,
> +                                   virDomainHostdevDefPtr detach)
> +{
> +    qemuDomainObjPrivatePtr priv = vm->privateData;
> +    int ret = -1;
> +
> +    if (!detach->info->alias) {
> +        virReportError(VIR_ERR_OPERATION_FAILED,
> +                       "%s", _("device cannot be detached without a device alias"));
> +        return -1;
> +    }
> +
> +    qemuDomainMarkDeviceForRemoval(vm, detach->info);
> +
> +    qemuDomainObjEnterMonitor(driver, vm);
> +    ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);
> +
> +    if (qemuDomainObjExitMonitor(driver, vm) < 0)
> +        return -1;
> +
> +    return ret;
> +}
> +
> +static int
>  qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver,
>                                 virDomainObjPtr vm,
>                                 virDomainHostdevDefPtr detach)
> @@ -4498,6 +4651,9 @@ qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver,
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
>          ret = qemuDomainDetachHostSCSIDevice(driver, vm, detach);
>          break;
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST:
> +        ret = qemuDomainDetachHostSCSIHostDevice(driver, vm, detach);
> +        break;
>      default:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                         _("hostdev subsys type '%s' not supported"),
> @@ -4575,6 +4731,8 @@ int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,
>              }
>              break;
>          }
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST:
> +            break;
>          default:
>              virReportError(VIR_ERR_INTERNAL_ERROR,
>                             _("unexpected hostdev type %d"), subsys->type);
> 




More information about the libvir-list mailing list