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

John Ferlan jferlan at redhat.com
Mon Nov 14 22:02:48 UTC 2016



On 11/14/2016 09:08 AM, Eric Farman wrote:
> 
> 
> On 11/11/2016 04:47 PM, John Ferlan wrote:
>>
>> 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?
> 
> (jumping out of order in my replies...  You brought this up earlier, but
> there's less to digest in this one...)
> 
> What's visible in the guest is one or more /dev/sdX devices and their
> /dev/sgX counterparts, just as there would be if using virtio-scsi.  The
> difference is that there'd be one <hostdev> tag for each disk for
> virtio, but here a single <hostdev> can contain many disks within it.
> 

Ah - OK. I hadn't got around to "seeing" this working on my test system
yet (it's still out of commission). Your explanation makes sense.

> Now, the question of why the check has to be made twice?  Er, well,
> uh...  I don't have an answer for that.
> 

yeah well I do this too... It's easy to get lost in what you've done or
haven't done


John
> 
>>
>>> +
>>> +    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.
> 
> Okay.
> 
>>
>> 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"
> 
> I see that I started this from the net code that has both tapfd and
> vhostfd, but calls Monitor via qemuMonitorAddNetdev instead of how
> configfd handles things.  So I presumed that the string was meant to be
> more descriptive, than following a particular naming convention. Will
> change with suggestions below.
> 
>  - Eric
> 
>>
>>> +        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