[libvirt] [PATCH 03/18] virpcimock: Create driver_override file in device dirs

Daniel Henrique Barboza danielhb413 at gmail.com
Fri Aug 16 21:06:45 UTC 2019


Reviewed-by: Daniel Henrique Barboza <danielhb413 at gmail.com>

On 8/14/19 8:57 AM, Michal Privoznik wrote:
> Newer kernels (v3.16-rc1~29^2~6^4) have 'driver_override' file
> which simplifies way of binding a PCI device to desired driver.
> Libvirt has support for this for some time too (v2.3.0-rc1~236),
> but not our virpcimock. So far we did not care because our code
> is designed to deal with this situation. Except for one.
> hypothetical case: binding a device to the vfio-pci driver can be
> successful only via driver_override. Any attempt to bind a PCI
> device to vfio-pci driver using old method (new_id + unbind +
> bind) will fail because of b803b29c1a5. While on vanilla kernel
> I'm able to use the old method successfully, it's failing on RHEL
> kernels (not sure why).
>
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
>   tests/virpcimock.c | 52 ++++++++++++++++++++++++++++++++++++++++------
>   1 file changed, 46 insertions(+), 6 deletions(-)
>
> diff --git a/tests/virpcimock.c b/tests/virpcimock.c
> index 6865f992dc..1c21e4e045 100644
> --- a/tests/virpcimock.c
> +++ b/tests/virpcimock.c
> @@ -87,6 +87,11 @@ char *fakesysfspcidir;
>    *   Probe for a driver that handles the specified device.
>    *   Data in format "DDDD:BB:DD.F" (Domain:Bus:Device.Function).
>    *
> + * /sys/bus/pci/devices/<device>/driver_override
> + *   Name of a driver that overrides preferred driver can be written
> + *   here. The device will be attached to it on drivers_probe event.
> + *   Writing an empty string (or "\n") clears the override.
> + *
>    * As a little hack, we are not mocking write to these files, but close()
>    * instead. The advantage is we don't need any self growing array to hold the
>    * partial writes and construct them back. We can let all the writes finish,
> @@ -147,6 +152,7 @@ static struct pciDevice *pci_device_find_by_content(const char *path);
>   static void pci_driver_new(const char *name, int fail, ...);
>   static struct pciDriver *pci_driver_find_by_dev(struct pciDevice *dev);
>   static struct pciDriver *pci_driver_find_by_path(const char *path);
> +static struct pciDriver *pci_driver_find_by_driver_override(struct pciDevice *dev);
>   static int pci_driver_bind(struct pciDriver *driver, struct pciDevice *dev);
>   static int pci_driver_unbind(struct pciDriver *driver, struct pciDevice *dev);
>   static int pci_driver_handle_change(int fd, const char *path);
> @@ -202,7 +208,8 @@ make_symlink(const char *path,
>   static int
>   pci_read_file(const char *path,
>                 char *buf,
> -              size_t buf_size)
> +              size_t buf_size,
> +              bool truncate)
>   {
>       int ret = -1;
>       int fd = -1;
> @@ -224,7 +231,8 @@ pci_read_file(const char *path,
>           goto cleanup;
>       }
>   
> -    if (ftruncate(fd, 0) < 0)
> +    if (truncate &&
> +        ftruncate(fd, 0) < 0)
>           goto cleanup;
>   
>       ret = 0;
> @@ -398,6 +406,8 @@ pci_device_new_from_stub(const struct pciDevice *data)
>           ABORT("@tmp overflow");
>       make_file(devpath, "class", tmp, -1);
>   
> +    make_file(devpath, "driver_override", NULL, -1);
> +
>       if (snprintf(tmp, sizeof(tmp),
>                    "%s/../../../kernel/iommu_groups/%d",
>                    devpath, dev->iommuGroup) < 0) {
> @@ -441,7 +451,7 @@ pci_device_find_by_content(const char *path)
>   {
>       char tmp[32];
>   
> -    if (pci_read_file(path, tmp, sizeof(tmp)) < 0)
> +    if (pci_read_file(path, tmp, sizeof(tmp), true) < 0)
>           return NULL;
>   
>       return pci_device_find_by_id(tmp);
> @@ -450,7 +460,10 @@ pci_device_find_by_content(const char *path)
>   static int
>   pci_device_autobind(struct pciDevice *dev)
>   {
> -    struct pciDriver *driver = pci_driver_find_by_dev(dev);
> +    struct pciDriver *driver = pci_driver_find_by_driver_override(dev);
> +
> +    if (!driver)
> +        driver = pci_driver_find_by_dev(dev);
>   
>       if (!driver) {
>           /* No driver found. Nothing to do */
> @@ -544,6 +557,31 @@ pci_driver_find_by_path(const char *path)
>       return NULL;
>   }
>   
> +static struct pciDriver *
> +pci_driver_find_by_driver_override(struct pciDevice *dev)
> +{
> +    VIR_AUTOFREE(char *) path = NULL;
> +    char tmp[32];
> +    size_t i;
> +
> +    if (virAsprintfQuiet(&path,
> +                         SYSFS_PCI_PREFIX "devices/%s/driver_override",
> +                         dev->id) < 0)
> +        return NULL;
> +
> +    if (pci_read_file(path, tmp, sizeof(tmp), false) < 0)
> +        return NULL;
> +
> +    for (i = 0; i < nPCIDrivers; i++) {
> +        struct pciDriver *driver = pciDrivers[i];
> +
> +        if (STREQ(tmp, driver->name))
> +            return driver;
> +    }
> +
> +    return NULL;
> +}
> +
>   static int
>   pci_driver_bind(struct pciDriver *driver,
>                   struct pciDevice *dev)
> @@ -657,6 +695,8 @@ pci_driver_handle_change(int fd ATTRIBUTE_UNUSED, const char *path)
>           ret = pci_driver_handle_remove_id(path);
>       else if (STREQ(file, "drivers_probe"))
>           ret = pci_driver_handle_drivers_probe(path);
> +    else if (STREQ(file, "driver_override"))
> +        ret = 0; /* nada */
>       else
>           ABORT("Not handled write to: %s", path);
>       return ret;
> @@ -711,7 +751,7 @@ pci_driver_handle_new_id(const char *path)
>           goto cleanup;
>       }
>   
> -    if (pci_read_file(path, buf, sizeof(buf)) < 0)
> +    if (pci_read_file(path, buf, sizeof(buf), true) < 0)
>           goto cleanup;
>   
>       if (sscanf(buf, "%x %x", &vendor, &device) < 2) {
> @@ -766,7 +806,7 @@ pci_driver_handle_remove_id(const char *path)
>           goto cleanup;
>       }
>   
> -    if (pci_read_file(path, buf, sizeof(buf)) < 0)
> +    if (pci_read_file(path, buf, sizeof(buf), true) < 0)
>           goto cleanup;
>   
>       if (sscanf(buf, "%x %x", &vendor, &device) < 2) {




More information about the libvir-list mailing list