373
374
static int vfio_query_precopy_size(VFIOMigration *migration)
375
{
376
+ VFIODevice *vbasedev = migration->vbasedev;
377
struct vfio_precopy_info precopy = {
378
.argsz = sizeof(precopy),
379
};
380
+ bool reinit = false;
381
int ret = 0;
382
383
if (ioctl(migration->data_fd, VFIO_MIG_GET_PRECOPY_INFO, &precopy)) {
385
migration->precopy_dirty_size = 0;
386
ret = -errno;
387
warn_report_once("VFIO device %s ioctl(VFIO_MIG_GET_PRECOPY_INFO) "
386
- "failed (%d)", migration->vbasedev->name, ret);
388
+ "failed (%d)", vbasedev->name, ret);
389
} else {
390
bool overflow;
391
392
migration->precopy_init_size = precopy.initial_bytes;
393
migration->precopy_dirty_size = precopy.dirty_bytes;
394
+ /*
395
+ * struct vfio_precopy_info.flags is valid only if
396
+ * VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2 is used.
397
+ */
398
+ if (migration->precopy_info_v2_used) {
399
+ reinit = precopy.flags & VFIO_PRECOPY_INFO_REINIT;
400
+ }
401
393
- overflow = vfio_migration_check_overflow(migration->vbasedev,
402
+ overflow = vfio_migration_check_overflow(vbasedev,
403
migration->precopy_init_size, "precopy init size");
395
- overflow |= vfio_migration_check_overflow(migration->vbasedev,
404
+ overflow |= vfio_migration_check_overflow(vbasedev,
405
migration->precopy_dirty_size, "precopy dirty size");
406
if (overflow) {
407
ret = -ERANGE;
408
}
409
}
410
402
- trace_vfio_query_precopy_size(migration->vbasedev->name,
403
- migration->precopy_init_size,
404
- migration->precopy_dirty_size, ret);
411
+ trace_vfio_query_precopy_size(vbasedev->name, migration->precopy_init_size,
412
+ migration->precopy_dirty_size, reinit, ret);
413
+
414
+ /*
415
+ * If we got new initial_bytes after previous initial_bytes were
416
+ * transferred, request a new switchover ACK. Don't request if legacy
417
+ * switchover-ack is used.
418
+ */
419
+ if (reinit && migration->initial_data_sent &&
420
+ !migrate_switchover_ack_legacy()) {
421
+ migration->initial_data_sent = false;
422
+ migration->request_switchover_ack = true;
423
+ trace_vfio_query_precopy_size_request_switchover_ack(vbasedev->name);
424
+ }
425
426
return ret;
427
}
1074
return 0;
1075
}
1076
1077
+/* Returns 1 on success, 0 if not supported and negative errno on failure */
1078
+static int vfio_migration_set_precopy_info_v2(VFIODevice *vbasedev)
1079
+{
1080
+ uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature),
1081
+ sizeof(uint64_t))] = {};
1082
+ struct vfio_device_feature *feature = (struct vfio_device_feature *)buf;
1083
+
1084
+ feature->argsz = sizeof(buf);
1085
+ feature->flags =
1086
+ VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2;
1087
+ if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) {
1088
+ if (errno == ENOTTY) {
1089
+ return 0;
1090
+ }
1091
+
1092
+ return -errno;
1093
+ }
1094
+
1095
+ return 1;
1096
+}
1097
+
1098
static bool vfio_dma_logging_supported(VFIODevice *vbasedev)
1099
{
1100
uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature),
1116
char id[256] = "";
1117
g_autofree char *path = NULL, *oid = NULL;
1118
uint64_t mig_flags = 0;
1119
+ bool precopy_info_v2_used = false;
1120
VMChangeStateHandler *prepare_cb;
1121
1122
if (!vbasedev->ops->vfio_get_object) {
1148
return false;
1149
}
1150
1151
+ if (mig_flags & VFIO_MIGRATION_PRE_COPY) {
1152
+ ret = vfio_migration_set_precopy_info_v2(vbasedev);
1153
+ if (ret < 0) {
1154
+ error_setg_errno(errp, -ret, "failed to set precopy info v2");
1155
+ return false;
1156
+ }
1157
+ precopy_info_v2_used = ret;
1158
+ }
1159
+
1160
vbasedev->migration = g_new0(VFIOMigration, 1);
1161
migration = vbasedev->migration;
1162
migration->vbasedev = vbasedev;
1163
migration->device_state = VFIO_DEVICE_STATE_RUNNING;
1164
migration->data_fd = -1;
1165
migration->mig_flags = mig_flags;
1166
+ migration->precopy_info_v2_used = precopy_info_v2_used;
1167
1168
vbasedev->dirty_pages_supported = vfio_dma_logging_supported(vbasedev);
1169
1186
migration_add_notifier(&migration->migration_state,
1187
vfio_migration_state_notifier);
1188
1189
+ trace_vfio_migration_init(vbasedev->name, migration->mig_flags,
1190
+ migration->precopy_info_v2_used,
1191
+ vbasedev->dirty_pages_supported);
1192
+
1193
return true;
1194
}
1195