@@ -65,11 +65,13 @@ typedef struct VFIOMigration {
uint32_t device_state_v1;
int vm_running;
Notifier migration_state;
+ NotifierWithReturn migration_data;
uint64_t pending_bytes;
enum vfio_device_mig_state device_state;
int data_fd;
void *data_buffer;
size_t data_buffer_size;
+ uint64_t stop_copy_size;
bool v2;
} VFIOMigration;
@@ -655,29 +655,19 @@ static void vfio_v1_save_cleanup(void *opaque)
trace_vfio_save_cleanup(vbasedev->name);
}
-/*
- * Migration size of VFIO devices can be as little as a few KBs or as big as
- * many GBs. This value should be big enough to cover the worst case.
- */
-#define VFIO_MIG_STOP_COPY_SIZE (100 * GiB)
static void vfio_save_pending(void *opaque, uint64_t threshold_size,
uint64_t *res_precopy_only,
uint64_t *res_compatible,
uint64_t *res_postcopy_only)
{
VFIODevice *vbasedev = opaque;
- uint64_t stop_copy_size = VFIO_MIG_STOP_COPY_SIZE;
+ VFIOMigration *migration = vbasedev->migration;
- /*
- * If getting pending migration size fails, VFIO_MIG_STOP_COPY_SIZE is
- * reported so downtime limit won't be violated.
- */
- vfio_query_stop_copy_size(vbasedev, &stop_copy_size);
- *res_precopy_only += stop_copy_size;
+ *res_precopy_only += migration->stop_copy_size;
trace_vfio_save_pending(vbasedev->name, *res_precopy_only,
*res_postcopy_only, *res_compatible,
- stop_copy_size);
+ migration->stop_copy_size);
}
static void vfio_v1_save_pending(void *opaque, uint64_t threshold_size,
@@ -1104,6 +1094,40 @@ static void vfio_migration_state_notifier(Notifier *notifier, void *data)
}
}
+/*
+ * Migration size of VFIO devices can be as little as a few KBs or as big as
+ * many GBs. This value should be big enough to cover the worst case.
+ */
+#define VFIO_MIG_STOP_COPY_SIZE (100 * GiB)
+static int vfio_migration_data_notifier(NotifierWithReturn *n, void *data)
+{
+ VFIOMigration *migration = container_of(n, VFIOMigration, migration_data);
+ VFIODevice *vbasedev = migration->vbasedev;
+ PrecopyNotifyData *pnd = data;
+
+ if (pnd->reason != PRECOPY_NOTIFY_AFTER_BITMAP_SYNC) {
+ return 0;
+ }
+
+ /* No need to get pending size when finishing migration */
+ if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
+ return 0;
+ }
+
+ if (vfio_query_stop_copy_size(vbasedev, &migration->stop_copy_size)) {
+ /*
+ * Failed to get pending migration size. Report big pending size so
+ * downtime limit won't be violated.
+ */
+ migration->stop_copy_size = VFIO_MIG_STOP_COPY_SIZE;
+ }
+
+ trace_vfio_migration_data_notifier(vbasedev->name,
+ migration->stop_copy_size);
+
+ return 0;
+}
+
static void vfio_migration_exit(VFIODevice *vbasedev)
{
VFIOMigration *migration = vbasedev->migration;
@@ -1225,6 +1249,9 @@ static int vfio_migration_init(VFIODevice *vbasedev)
migration->vm_state = qdev_add_vm_change_state_handler(
vbasedev->dev, vfio_vmstate_change, vbasedev);
+
+ migration->migration_data.notify = vfio_migration_data_notifier;
+ precopy_add_notifier(&migration->migration_data);
} else {
register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1,
&savevm_vfio_v1_handlers, vbasedev);
@@ -1283,6 +1310,9 @@ void vfio_migration_finalize(VFIODevice *vbasedev)
if (vbasedev->migration) {
VFIOMigration *migration = vbasedev->migration;
+ if (migration->v2) {
+ precopy_remove_notifier(&migration->migration_data);
+ }
remove_migration_state_change_notifier(&migration->migration_state);
qemu_del_vm_change_state_handler(migration->vm_state);
unregister_savevm(VMSTATE_IF(vbasedev->dev), "vfio", vbasedev);
@@ -173,3 +173,4 @@ vfio_load_cleanup(const char *name) " (%s)"
vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64
vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64
vfio_save_block(const char *name, int data_size) " (%s) data_size %d"
+vfio_migration_data_notifier(const char *name, uint64_t stopcopy_size) " (%s) stopcopy size 0x%"PRIx64