[libvirt] [PATCH v2 4/5] qemu: Allow hotplug of vhost-scsi device

John Ferlan jferlan at redhat.com
Mon Sep 12 22:36:35 UTC 2016



On 09/06/2016 08:58 AM, 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.
> 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.)
> 
> Signed-off-by: Eric Farman <farman at linux.vnet.ibm.com>
> ---
>  src/conf/domain_conf.c  |   6 ++
>  src/qemu/qemu_hotplug.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 154 insertions(+)
> 
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 45b643b..123bbcb 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -13720,6 +13720,12 @@ virDomainHostdevMatchSubsys(virDomainHostdevDefPtr a,
>              return virDomainHostdevMatchSubsysSCSIiSCSI(a, b);
>          else
>              return virDomainHostdevMatchSubsysSCSIHost(a, b);
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST:
> +        if (a->source.subsys.u.host.protocol !=
> +            b->source.subsys.u.host.protocol)
> +            return 0;
> +        if (STREQ(a->source.subsys.u.host.wwpn, b->source.subsys.u.host.wwpn))
> +            return 1;
>      }
>      return 0;
>  }

This hunk seems to be out of place in this patch...  Although I assume
this is because of the remove device searches.

> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index e9140a9..5f8d411 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -2165,6 +2165,119 @@ qemuDomainAttachHostSCSIDevice(virConnectPtr conn,
>      goto cleanup;
>  }
>  
> +static int
> +qemuDomainAttachHostSCSIHostDevice(virQEMUDriverPtr driver,
> +                                   virDomainObjPtr vm,
> +                                   virDomainHostdevDefPtr hostdev)
> +{
> +    int ret = -1;
> +    qemuDomainObjPrivatePtr priv = vm->privateData;
> +    virDomainCCWAddressSetPtr ccwaddrs = NULL;
> +    char *vhostfdName = NULL;
> +    int vhostfd = -1;
> +    size_t vhostfdSize = 1;
> +    char *devstr = NULL;
> +    bool teardowncgroup = false;
> +    bool teardownlabel = false;
> +    bool releaseaddr = false;
> +
> +    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {

Here again the capabilities conundrum.

> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("SCSI passthrough is not supported by this version of qemu"));
> +        goto cleanup;
> +    }
> +
> +    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
> +        goto cleanup;

Oh, um, didn't I comment on this in patch 1 - there's no
VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST in qemuSetupHostdevCgroup


> +    teardowncgroup = true;
> +
> +    if (virSecurityManagerSetHostdevLabel(driver->securityManager,
> +                                          vm->def, hostdev, NULL) < 0)
> +        goto cleanup;
> +    teardownlabel = true;

Likewise there's really not much going on...

> +
> +    if (virSCSIOpenVhost(&vhostfd, &vhostfdSize) < 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)

'info' is already a virDomainDeviceInfoPtr (unlike where you
cut-n-paste'd from), so no need for the '&' here (besides it induces a
build failure).

> +            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;
> +
> +    qemuDomainObjEnterMonitor(driver, vm);
> +
> +    if (hostdev->source.subsys.u.host.protocol == VIR_DOMAIN_HOSTDEV_HOST_PROTOCOL_TYPE_VHOST) {

Long line > 80 cols

Ironically we do nothing if the protocol isn't VHOST...

> +        if (!(devstr = qemuBuildHostHostdevDevStr(vm->def,
> +                                                  hostdev,
> +                                                  priv->qemuCaps,
> +                                                  vhostfdName,
> +                                                  vhostfdSize)))

This can be done outside holding the monitor lock

> +            goto exit_monitor;
> +
> +        if ((ret = qemuMonitorAddDeviceWithFd(priv->mon,
> +                                              devstr,
> +                                              vhostfd,
> +                                              vhostfdName)) < 0) {
> +            goto exit_monitor;
> +        }
> +    }
> +
> +    if (qemuDomainObjExitMonitor(driver, vm) < 0)
> +        goto cleanup;
> +
> +    virDomainAuditHostdev(vm, hostdev, "attach", true);

s/true/(ret == 0)/

Since we've set up the addresses above - the auditing code should print
more than "?"

Here should be a "if (ret < 0) goto cleanup;" (on two lines).

> +
> +    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
> +        goto cleanup;
> +
> +    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;

Other code will increase the size of hostdevs before the monitor calls,
then just insert.
> +
> +    virDomainCCWAddressSetFree(ccwaddrs);
> +
> +    VIR_FORCE_CLOSE(vhostfd);

This I would think would only be done on *failure* to AddDeviceWithFd,
but I see you're following qemuDomainAttachHostPCIDevice

> +    VIR_FREE(vhostfdName);
> +    VIR_FREE(devstr);
> +    return 0;
> +
> + exit_monitor:
> +    ignore_value(qemuDomainObjExitMonitor(driver, vm)); 
> +
> + cleanup:
> +    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);
> +
> +    VIR_FORCE_CLOSE(vhostfd);
> +    VIR_FREE(vhostfdName);
> +    VIR_FREE(devstr);
> +    return ret;
> +}
> +
>  
>  int
>  qemuDomainAttachHostDevice(virConnectPtr conn,
> @@ -2198,6 +2311,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"),
> @@ -3960,6 +4078,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)
> @@ -3981,6 +4124,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"),
> @@ -4058,6 +4204,8 @@ int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,

Ah - and this is where that pesky virDomainHostdevFind causes the need
for the domain_conf.c code above...

>              }
>              break;
>          }
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_HOST:

But we need an error here otherwise we get a generic failed with some
error message.

John
> +            break;
>          default:
>              virReportError(VIR_ERR_INTERNAL_ERROR,
>                             _("unexpected hostdev type %d"), subsys->type);
> 




More information about the libvir-list mailing list