diff mbox series

[11/11] vfio: unplug failover primary device before migration

Message ID 20191018202040.30349-12-jfreimann@redhat.com
State New
Headers show
Series add failover feature for assigned network devices | expand

Commit Message

Jens Freimann Oct. 18, 2019, 8:20 p.m. UTC
As usual block all vfio-pci devices from being migrated, but make an
exception for failover primary devices. This is achieved by setting
unmigratable to 0 but also add a migration blocker for all vfio-pci
devices except failover primary devices. These will be unplugged before
migration happens by the migration handler of the corresponding
virtio-net standby device.

Signed-off-by: Jens Freimann <jfreimann@redhat.com>
---
 hw/vfio/pci.c | 31 +++++++++++++++++++++++++------
 hw/vfio/pci.h |  1 +
 2 files changed, 26 insertions(+), 6 deletions(-)

Comments

Cornelia Huck Oct. 21, 2019, 1:45 p.m. UTC | #1
On Fri, 18 Oct 2019 22:20:40 +0200
Jens Freimann <jfreimann@redhat.com> wrote:

> As usual block all vfio-pci devices from being migrated, but make an
> exception for failover primary devices. This is achieved by setting
> unmigratable to 0 but also add a migration blocker for all vfio-pci
> devices except failover primary devices. These will be unplugged before
> migration happens by the migration handler of the corresponding
> virtio-net standby device.
> 
> Signed-off-by: Jens Freimann <jfreimann@redhat.com>
> ---
>  hw/vfio/pci.c | 31 +++++++++++++++++++++++++------
>  hw/vfio/pci.h |  1 +
>  2 files changed, 26 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index 12fac39804..a15b83c6b6 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -40,6 +40,9 @@
>  #include "pci.h"
>  #include "trace.h"
>  #include "qapi/error.h"
> +#include "migration/blocker.h"
> +#include "qemu/option.h"
> +#include "qemu/option_int.h"
>  
>  #define TYPE_VFIO_PCI "vfio-pci"
>  #define PCI_VFIO(obj)    OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI)
> @@ -2712,12 +2715,26 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
>      int i, ret;
>      bool is_mdev;
>  
> +    if (!pdev->net_failover_pair_id) {
> +        error_setg(&vdev->migration_blocker,
> +                "VFIO device doesn't support migration");
> +        ret = migrate_add_blocker(vdev->migration_blocker, &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            goto error;

This looks wrong, you haven't set up vbasedev.name yet.

> +        }
> +    } else {
> +            pdev->qdev.allow_unplug_during_migration = true;
> +    }
> +
>      if (!vdev->vbasedev.sysfsdev) {
>          if (!(~vdev->host.domain || ~vdev->host.bus ||
>                ~vdev->host.slot || ~vdev->host.function)) {
>              error_setg(errp, "No provided host device");
>              error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
>                                "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
> +            migrate_del_blocker(vdev->migration_blocker);
> +            error_free(vdev->migration_blocker);
>              return;
>          }
>          vdev->vbasedev.sysfsdev =
> @@ -2729,6 +2746,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
>      if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
>          error_setg_errno(errp, errno, "no such host device");
>          error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev);
> +        migrate_del_blocker(vdev->migration_blocker);
> +        error_free(vdev->migration_blocker);
>          return;
>      }

Might be a bit easier cleanup-wise if you set up the blocker resp.
allow unplug during migration only here. The only difference is that
you'll get a different error message when trying to set up a
non-failover device with invalid specs on a migratable-only setup.

>  
> @@ -3008,6 +3027,8 @@ out_teardown:
>      vfio_bars_exit(vdev);
>  error:
>      error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> +    migrate_del_blocker(vdev->migration_blocker);
> +    error_free(vdev->migration_blocker);

Shouldn't you check whether migration_block has been set up, like in
the finalize routine?

>  }
>  
>  static void vfio_instance_finalize(Object *obj)
> @@ -3019,6 +3040,10 @@ static void vfio_instance_finalize(Object *obj)
>      vfio_bars_finalize(vdev);
>      g_free(vdev->emulated_config_bits);
>      g_free(vdev->rom);
> +    if (vdev->migration_blocker) {
> +        migrate_del_blocker(vdev->migration_blocker);
> +        error_free(vdev->migration_blocker);
> +    }
>      /*
>       * XXX Leaking igd_opregion is not an oversight, we can't remove the
>       * fw_cfg entry therefore leaking this allocation seems like the safest
Jens Freimann Oct. 21, 2019, 2:09 p.m. UTC | #2
On Mon, Oct 21, 2019 at 03:45:04PM +0200, Cornelia Huck wrote:
>On Fri, 18 Oct 2019 22:20:40 +0200
>Jens Freimann <jfreimann@redhat.com> wrote:
>
>> As usual block all vfio-pci devices from being migrated, but make an
>> exception for failover primary devices. This is achieved by setting
>> unmigratable to 0 but also add a migration blocker for all vfio-pci
>> devices except failover primary devices. These will be unplugged before
>> migration happens by the migration handler of the corresponding
>> virtio-net standby device.
>>
>> Signed-off-by: Jens Freimann <jfreimann@redhat.com>
>> ---
>>  hw/vfio/pci.c | 31 +++++++++++++++++++++++++------
>>  hw/vfio/pci.h |  1 +
>>  2 files changed, 26 insertions(+), 6 deletions(-)
>>
>> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
>> index 12fac39804..a15b83c6b6 100644
>> --- a/hw/vfio/pci.c
>> +++ b/hw/vfio/pci.c
>> @@ -40,6 +40,9 @@
>>  #include "pci.h"
>>  #include "trace.h"
>>  #include "qapi/error.h"
>> +#include "migration/blocker.h"
>> +#include "qemu/option.h"
>> +#include "qemu/option_int.h"
>>
>>  #define TYPE_VFIO_PCI "vfio-pci"
>>  #define PCI_VFIO(obj)    OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI)
>> @@ -2712,12 +2715,26 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
>>      int i, ret;
>>      bool is_mdev;
>>
>> +    if (!pdev->net_failover_pair_id) {
>> +        error_setg(&vdev->migration_blocker,
>> +                "VFIO device doesn't support migration");
>> +        ret = migrate_add_blocker(vdev->migration_blocker, &err);
>> +        if (err) {
>> +            error_propagate(errp, err);
>> +            goto error;
>
>This looks wrong, you haven't set up vbasedev.name yet.

You're right.

>> +        }
>> +    } else {
>> +            pdev->qdev.allow_unplug_during_migration = true;
>> +    }
>> +
>>      if (!vdev->vbasedev.sysfsdev) {
>>          if (!(~vdev->host.domain || ~vdev->host.bus ||
>>                ~vdev->host.slot || ~vdev->host.function)) {
>>              error_setg(errp, "No provided host device");
>>              error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
>>                                "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
>> +            migrate_del_blocker(vdev->migration_blocker);
>> +            error_free(vdev->migration_blocker);
>>              return;
>>          }
>>          vdev->vbasedev.sysfsdev =
>> @@ -2729,6 +2746,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
>>      if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
>>          error_setg_errno(errp, errno, "no such host device");
>>          error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev);
>> +        migrate_del_blocker(vdev->migration_blocker);
>> +        error_free(vdev->migration_blocker);
>>          return;
>>      }
>
>Might be a bit easier cleanup-wise if you set up the blocker resp.
>allow unplug during migration only here. The only difference is that
>you'll get a different error message when trying to set up a
>non-failover device with invalid specs on a migratable-only setup.

Yes, so I moved it to this place now. This saves me cleanup up the
migration blocker in the above two cases. I don't jump to error if
adding the migration blocker failed, I just have to free the blocker
Error and can return.
>
>>
>> @@ -3008,6 +3027,8 @@ out_teardown:
>>      vfio_bars_exit(vdev);
>>  error:
>>      error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
>> +    migrate_del_blocker(vdev->migration_blocker);
>> +    error_free(vdev->migration_blocker);
>
>Shouldn't you check whether migration_block has been set up, like in
>the finalize routine?

yes, added the same check here.

Thanks Conny!

regards,
Jens
Alex Williamson Oct. 21, 2019, 3:19 p.m. UTC | #3
On Fri, 18 Oct 2019 22:20:40 +0200
Jens Freimann <jfreimann@redhat.com> wrote:

> As usual block all vfio-pci devices from being migrated, but make an
> exception for failover primary devices. This is achieved by setting
> unmigratable to 0 but also add a migration blocker for all vfio-pci
> devices except failover primary devices. These will be unplugged before
> migration happens by the migration handler of the corresponding
> virtio-net standby device.
> 
> Signed-off-by: Jens Freimann <jfreimann@redhat.com>
> ---
>  hw/vfio/pci.c | 31 +++++++++++++++++++++++++------
>  hw/vfio/pci.h |  1 +
>  2 files changed, 26 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index 12fac39804..a15b83c6b6 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -40,6 +40,9 @@
>  #include "pci.h"
>  #include "trace.h"
>  #include "qapi/error.h"
> +#include "migration/blocker.h"
> +#include "qemu/option.h"
> +#include "qemu/option_int.h"
>  
>  #define TYPE_VFIO_PCI "vfio-pci"
>  #define PCI_VFIO(obj)    OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI)
> @@ -2712,12 +2715,26 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
>      int i, ret;
>      bool is_mdev;
>  
> +    if (!pdev->net_failover_pair_id) {
> +        error_setg(&vdev->migration_blocker,
> +                "VFIO device doesn't support migration");
> +        ret = migrate_add_blocker(vdev->migration_blocker, &err);
> +        if (err) {
> +            error_propagate(errp, err);
> +            goto error;
> +        }
> +    } else {
> +            pdev->qdev.allow_unplug_during_migration = true;

Why is this unique to vfio-pci, shouldn't any device set as the primary
for a failover allow unplug during migration, and therefore should it
be done in the core code rather than device driver?  With the
net_failover_pair_id set in PCIDevice, I should be able to test with an
e1000e NIC as primary, but this suggests they wouldn't be handled
identically elsewhere.  Thanks,

Alex

> +    }
> +
>      if (!vdev->vbasedev.sysfsdev) {
>          if (!(~vdev->host.domain || ~vdev->host.bus ||
>                ~vdev->host.slot || ~vdev->host.function)) {
>              error_setg(errp, "No provided host device");
>              error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
>                                "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
> +            migrate_del_blocker(vdev->migration_blocker);
> +            error_free(vdev->migration_blocker);
>              return;
>          }
>          vdev->vbasedev.sysfsdev =
> @@ -2729,6 +2746,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
>      if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
>          error_setg_errno(errp, errno, "no such host device");
>          error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev);
> +        migrate_del_blocker(vdev->migration_blocker);
> +        error_free(vdev->migration_blocker);
>          return;
>      }
>  
> @@ -3008,6 +3027,8 @@ out_teardown:
>      vfio_bars_exit(vdev);
>  error:
>      error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> +    migrate_del_blocker(vdev->migration_blocker);
> +    error_free(vdev->migration_blocker);
>  }
>  
>  static void vfio_instance_finalize(Object *obj)
> @@ -3019,6 +3040,10 @@ static void vfio_instance_finalize(Object *obj)
>      vfio_bars_finalize(vdev);
>      g_free(vdev->emulated_config_bits);
>      g_free(vdev->rom);
> +    if (vdev->migration_blocker) {
> +        migrate_del_blocker(vdev->migration_blocker);
> +        error_free(vdev->migration_blocker);
> +    }
>      /*
>       * XXX Leaking igd_opregion is not an oversight, we can't remove the
>       * fw_cfg entry therefore leaking this allocation seems like the safest
> @@ -3151,11 +3176,6 @@ static Property vfio_pci_dev_properties[] = {
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> -static const VMStateDescription vfio_pci_vmstate = {
> -    .name = "vfio-pci",
> -    .unmigratable = 1,
> -};
> -
>  static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -3163,7 +3183,6 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
>  
>      dc->reset = vfio_pci_reset;
>      dc->props = vfio_pci_dev_properties;
> -    dc->vmsd = &vfio_pci_vmstate;
>      dc->desc = "VFIO-based PCI device assignment";
>      set_bit(DEVICE_CATEGORY_MISC, dc->categories);
>      pdc->realize = vfio_realize;
> diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
> index 834a90d646..b329d50338 100644
> --- a/hw/vfio/pci.h
> +++ b/hw/vfio/pci.h
> @@ -168,6 +168,7 @@ typedef struct VFIOPCIDevice {
>      bool no_vfio_ioeventfd;
>      bool enable_ramfb;
>      VFIODisplay *dpy;
> +    Error *migration_blocker;
>  } VFIOPCIDevice;
>  
>  uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
Jens Freimann Oct. 21, 2019, 7:16 p.m. UTC | #4
On Mon, Oct 21, 2019 at 09:19:20AM -0600, Alex Williamson wrote:
>On Fri, 18 Oct 2019 22:20:40 +0200
>Jens Freimann <jfreimann@redhat.com> wrote:
[...]
>> +    if (!pdev->net_failover_pair_id) {
>> +        error_setg(&vdev->migration_blocker,
>> +                "VFIO device doesn't support migration");
>> +        ret = migrate_add_blocker(vdev->migration_blocker, &err);
>> +        if (err) {
>> +            error_propagate(errp, err);
>> +            goto error;
>> +        }
>> +    } else {
>> +            pdev->qdev.allow_unplug_during_migration = true;
>
>Why is this unique to vfio-pci, shouldn't any device set as the primary
>for a failover allow unplug during migration, and therefore should it
>be done in the core code rather than device driver?  With the
>net_failover_pair_id set in PCIDevice, I should be able to test with an
>e1000e NIC as primary, but this suggests they wouldn't be handled
>identically elsewhere.  Thanks,

I assume you're talking about pci core code not qdev core. Failover is
pci specific at this time (only the part to hide devices is more
generic and is in qdev code). I can set the flag to allow migration in
pci_qdev_realize().

regards,
Jens
diff mbox series

Patch

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 12fac39804..a15b83c6b6 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -40,6 +40,9 @@ 
 #include "pci.h"
 #include "trace.h"
 #include "qapi/error.h"
+#include "migration/blocker.h"
+#include "qemu/option.h"
+#include "qemu/option_int.h"
 
 #define TYPE_VFIO_PCI "vfio-pci"
 #define PCI_VFIO(obj)    OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI)
@@ -2712,12 +2715,26 @@  static void vfio_realize(PCIDevice *pdev, Error **errp)
     int i, ret;
     bool is_mdev;
 
+    if (!pdev->net_failover_pair_id) {
+        error_setg(&vdev->migration_blocker,
+                "VFIO device doesn't support migration");
+        ret = migrate_add_blocker(vdev->migration_blocker, &err);
+        if (err) {
+            error_propagate(errp, err);
+            goto error;
+        }
+    } else {
+            pdev->qdev.allow_unplug_during_migration = true;
+    }
+
     if (!vdev->vbasedev.sysfsdev) {
         if (!(~vdev->host.domain || ~vdev->host.bus ||
               ~vdev->host.slot || ~vdev->host.function)) {
             error_setg(errp, "No provided host device");
             error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
                               "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
+            migrate_del_blocker(vdev->migration_blocker);
+            error_free(vdev->migration_blocker);
             return;
         }
         vdev->vbasedev.sysfsdev =
@@ -2729,6 +2746,8 @@  static void vfio_realize(PCIDevice *pdev, Error **errp)
     if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
         error_setg_errno(errp, errno, "no such host device");
         error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev);
+        migrate_del_blocker(vdev->migration_blocker);
+        error_free(vdev->migration_blocker);
         return;
     }
 
@@ -3008,6 +3027,8 @@  out_teardown:
     vfio_bars_exit(vdev);
 error:
     error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
+    migrate_del_blocker(vdev->migration_blocker);
+    error_free(vdev->migration_blocker);
 }
 
 static void vfio_instance_finalize(Object *obj)
@@ -3019,6 +3040,10 @@  static void vfio_instance_finalize(Object *obj)
     vfio_bars_finalize(vdev);
     g_free(vdev->emulated_config_bits);
     g_free(vdev->rom);
+    if (vdev->migration_blocker) {
+        migrate_del_blocker(vdev->migration_blocker);
+        error_free(vdev->migration_blocker);
+    }
     /*
      * XXX Leaking igd_opregion is not an oversight, we can't remove the
      * fw_cfg entry therefore leaking this allocation seems like the safest
@@ -3151,11 +3176,6 @@  static Property vfio_pci_dev_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static const VMStateDescription vfio_pci_vmstate = {
-    .name = "vfio-pci",
-    .unmigratable = 1,
-};
-
 static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -3163,7 +3183,6 @@  static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
 
     dc->reset = vfio_pci_reset;
     dc->props = vfio_pci_dev_properties;
-    dc->vmsd = &vfio_pci_vmstate;
     dc->desc = "VFIO-based PCI device assignment";
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
     pdc->realize = vfio_realize;
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index 834a90d646..b329d50338 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -168,6 +168,7 @@  typedef struct VFIOPCIDevice {
     bool no_vfio_ioeventfd;
     bool enable_ramfb;
     VFIODisplay *dpy;
+    Error *migration_blocker;
 } VFIOPCIDevice;
 
 uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);