mirror of https://github.com/xemu-project/xemu.git
migration: disallow migrate_add_blocker during migration
If a migration is already in progress and somebody attempts to add a migration blocker, this should rightly fail. Add an errp parameter and a retcode return value to migrate_add_blocker. Signed-off-by: John Snow <jsnow@redhat.com> Signed-off-by: Ashijeet Acharya <ashijeetacharya@gmail.com> Message-Id: <1484566314-3987-5-git-send-email-ashijeetacharya@gmail.com> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Acked-by: Greg Kurz <groug@kaod.org> Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Merged with recent 'Allow invtsc migration' change
This commit is contained in:
parent
a3a3d8c738
commit
fe44dc9180
|
@ -104,6 +104,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
unsigned int len, i, shift;
|
unsigned int len, i, shift;
|
||||||
int ret;
|
int ret;
|
||||||
QCowHeader header;
|
QCowHeader header;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -252,7 +253,12 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
|
error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
|
||||||
"does not support live migration",
|
"does not support live migration",
|
||||||
bdrv_get_device_or_node_name(bs));
|
bdrv_get_device_or_node_name(bs));
|
||||||
migrate_add_blocker(s->migration_blocker);
|
ret = migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_co_mutex_init(&s->lock);
|
qemu_co_mutex_init(&s->lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -361,6 +361,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
VdiHeader header;
|
VdiHeader header;
|
||||||
size_t bmap_size;
|
size_t bmap_size;
|
||||||
int ret;
|
int ret;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
logout("\n");
|
logout("\n");
|
||||||
|
|
||||||
|
@ -471,7 +472,12 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
error_setg(&s->migration_blocker, "The vdi format used by node '%s' "
|
error_setg(&s->migration_blocker, "The vdi format used by node '%s' "
|
||||||
"does not support live migration",
|
"does not support live migration",
|
||||||
bdrv_get_device_or_node_name(bs));
|
bdrv_get_device_or_node_name(bs));
|
||||||
migrate_add_blocker(s->migration_blocker);
|
ret = migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
goto fail_free_bmap;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_co_mutex_init(&s->write_lock);
|
qemu_co_mutex_init(&s->write_lock);
|
||||||
|
|
||||||
|
|
17
block/vhdx.c
17
block/vhdx.c
|
@ -991,6 +991,17 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disable migration when VHDX images are used */
|
||||||
|
error_setg(&s->migration_blocker, "The vhdx format used by node '%s' "
|
||||||
|
"does not support live migration",
|
||||||
|
bdrv_get_device_or_node_name(bs));
|
||||||
|
ret = migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & BDRV_O_RDWR) {
|
if (flags & BDRV_O_RDWR) {
|
||||||
ret = vhdx_update_headers(bs, s, false, NULL);
|
ret = vhdx_update_headers(bs, s, false, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -1000,12 +1011,6 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
|
|
||||||
/* TODO: differencing files */
|
/* TODO: differencing files */
|
||||||
|
|
||||||
/* Disable migration when VHDX images are used */
|
|
||||||
error_setg(&s->migration_blocker, "The vhdx format used by node '%s' "
|
|
||||||
"does not support live migration",
|
|
||||||
bdrv_get_device_or_node_name(bs));
|
|
||||||
migrate_add_blocker(s->migration_blocker);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
vhdx_close(bs);
|
vhdx_close(bs);
|
||||||
|
|
|
@ -941,6 +941,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
int ret;
|
int ret;
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
buf = vmdk_read_desc(bs->file, 0, errp);
|
buf = vmdk_read_desc(bs->file, 0, errp);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
|
@ -976,7 +977,13 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
error_setg(&s->migration_blocker, "The vmdk format used by node '%s' "
|
error_setg(&s->migration_blocker, "The vmdk format used by node '%s' "
|
||||||
"does not support live migration",
|
"does not support live migration",
|
||||||
bdrv_get_device_or_node_name(bs));
|
bdrv_get_device_or_node_name(bs));
|
||||||
migrate_add_blocker(s->migration_blocker);
|
ret = migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
g_free(buf);
|
g_free(buf);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
11
block/vpc.c
11
block/vpc.c
|
@ -422,13 +422,18 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_co_mutex_init(&s->lock);
|
|
||||||
|
|
||||||
/* Disable migration when VHD images are used */
|
/* Disable migration when VHD images are used */
|
||||||
error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
|
error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
|
||||||
"does not support live migration",
|
"does not support live migration",
|
||||||
bdrv_get_device_or_node_name(bs));
|
bdrv_get_device_or_node_name(bs));
|
||||||
migrate_add_blocker(s->migration_blocker);
|
ret = migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_co_mutex_init(&s->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -1185,20 +1185,25 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||||
|
|
||||||
s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
|
s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
|
||||||
|
|
||||||
if (s->first_sectors_number == 0x40) {
|
|
||||||
init_mbr(s, cyls, heads, secs);
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_co_mutex_init(&s->lock);
|
|
||||||
|
|
||||||
/* Disable migration when vvfat is used rw */
|
/* Disable migration when vvfat is used rw */
|
||||||
if (s->qcow) {
|
if (s->qcow) {
|
||||||
error_setg(&s->migration_blocker,
|
error_setg(&s->migration_blocker,
|
||||||
"The vvfat (rw) format used by node '%s' "
|
"The vvfat (rw) format used by node '%s' "
|
||||||
"does not support live migration",
|
"does not support live migration",
|
||||||
bdrv_get_device_or_node_name(bs));
|
bdrv_get_device_or_node_name(bs));
|
||||||
migrate_add_blocker(s->migration_blocker);
|
ret = migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->first_sectors_number == 0x40) {
|
||||||
|
init_mbr(s, cyls, heads, secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_co_mutex_init(&s->lock);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
|
|
33
hw/9pfs/9p.c
33
hw/9pfs/9p.c
|
@ -979,6 +979,7 @@ static void coroutine_fn v9fs_attach(void *opaque)
|
||||||
size_t offset = 7;
|
size_t offset = 7;
|
||||||
V9fsQID qid;
|
V9fsQID qid;
|
||||||
ssize_t err;
|
ssize_t err;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
v9fs_string_init(&uname);
|
v9fs_string_init(&uname);
|
||||||
v9fs_string_init(&aname);
|
v9fs_string_init(&aname);
|
||||||
|
@ -1007,26 +1008,36 @@ static void coroutine_fn v9fs_attach(void *opaque)
|
||||||
clunk_fid(s, fid);
|
clunk_fid(s, fid);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* disable migration if we haven't done already.
|
||||||
|
* attach could get called multiple times for the same export.
|
||||||
|
*/
|
||||||
|
if (!s->migration_blocker) {
|
||||||
|
error_setg(&s->migration_blocker,
|
||||||
|
"Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
|
||||||
|
s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
|
||||||
|
err = migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_free(local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
s->migration_blocker = NULL;
|
||||||
|
clunk_fid(s, fid);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
s->root_fid = fid;
|
||||||
|
}
|
||||||
|
|
||||||
err = pdu_marshal(pdu, offset, "Q", &qid);
|
err = pdu_marshal(pdu, offset, "Q", &qid);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
clunk_fid(s, fid);
|
clunk_fid(s, fid);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
err += offset;
|
err += offset;
|
||||||
|
|
||||||
memcpy(&s->root_qid, &qid, sizeof(qid));
|
memcpy(&s->root_qid, &qid, sizeof(qid));
|
||||||
trace_v9fs_attach_return(pdu->tag, pdu->id,
|
trace_v9fs_attach_return(pdu->tag, pdu->id,
|
||||||
qid.type, qid.version, qid.path);
|
qid.type, qid.version, qid.path);
|
||||||
/*
|
|
||||||
* disable migration if we haven't done already.
|
|
||||||
* attach could get called multiple times for the same export.
|
|
||||||
*/
|
|
||||||
if (!s->migration_blocker) {
|
|
||||||
s->root_fid = fid;
|
|
||||||
error_setg(&s->migration_blocker,
|
|
||||||
"Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
|
|
||||||
s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
|
|
||||||
migrate_add_blocker(s->migration_blocker);
|
|
||||||
}
|
|
||||||
out:
|
out:
|
||||||
put_fid(pdu, fidp);
|
put_fid(pdu, fidp);
|
||||||
out_nofid:
|
out_nofid:
|
||||||
|
|
|
@ -1136,6 +1136,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||||
VirtIOGPU *g = VIRTIO_GPU(qdev);
|
VirtIOGPU *g = VIRTIO_GPU(qdev);
|
||||||
bool have_virgl;
|
bool have_virgl;
|
||||||
|
Error *local_err = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) {
|
if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) {
|
||||||
|
@ -1143,14 +1144,6 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g->config_size = sizeof(struct virtio_gpu_config);
|
|
||||||
g->virtio_config.num_scanouts = g->conf.max_outputs;
|
|
||||||
virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
|
|
||||||
g->config_size);
|
|
||||||
|
|
||||||
g->req_state[0].width = 1024;
|
|
||||||
g->req_state[0].height = 768;
|
|
||||||
|
|
||||||
g->use_virgl_renderer = false;
|
g->use_virgl_renderer = false;
|
||||||
#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
|
#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
|
||||||
have_virgl = false;
|
have_virgl = false;
|
||||||
|
@ -1161,6 +1154,24 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||||
g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
|
g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virtio_gpu_virgl_enabled(g->conf)) {
|
||||||
|
error_setg(&g->migration_blocker, "virgl is not yet migratable");
|
||||||
|
migrate_add_blocker(g->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(g->migration_blocker);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g->config_size = sizeof(struct virtio_gpu_config);
|
||||||
|
g->virtio_config.num_scanouts = g->conf.max_outputs;
|
||||||
|
virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
|
||||||
|
g->config_size);
|
||||||
|
|
||||||
|
g->req_state[0].width = 1024;
|
||||||
|
g->req_state[0].height = 768;
|
||||||
|
|
||||||
if (virtio_gpu_virgl_enabled(g->conf)) {
|
if (virtio_gpu_virgl_enabled(g->conf)) {
|
||||||
/* use larger control queue in 3d mode */
|
/* use larger control queue in 3d mode */
|
||||||
g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
|
g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
|
||||||
|
@ -1187,11 +1198,6 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
|
||||||
dpy_gfx_replace_surface(g->scanout[i].con, NULL);
|
dpy_gfx_replace_surface(g->scanout[i].con, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virtio_gpu_virgl_enabled(g->conf)) {
|
|
||||||
error_setg(&g->migration_blocker, "virgl is not yet migratable");
|
|
||||||
migrate_add_blocker(g->migration_blocker);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_gpu_device_unrealize(DeviceState *qdev, Error **errp)
|
static void virtio_gpu_device_unrealize(DeviceState *qdev, Error **errp)
|
||||||
|
|
|
@ -510,6 +510,17 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!kvm_arm_gic_can_save_restore(s)) {
|
||||||
|
error_setg(&s->migration_blocker, "This operating system kernel does "
|
||||||
|
"not support vGICv2 migration");
|
||||||
|
migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL);
|
gic_init_irqs_and_mmio(s, kvm_arm_gicv2_set_irq, NULL);
|
||||||
|
|
||||||
for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
|
for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
|
||||||
|
@ -558,12 +569,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||||
KVM_VGIC_V2_ADDR_TYPE_CPU,
|
KVM_VGIC_V2_ADDR_TYPE_CPU,
|
||||||
s->dev_fd);
|
s->dev_fd);
|
||||||
|
|
||||||
if (!kvm_arm_gic_can_save_restore(s)) {
|
|
||||||
error_setg(&s->migration_blocker, "This operating system kernel does "
|
|
||||||
"not support vGICv2 migration");
|
|
||||||
migrate_add_blocker(s->migration_blocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kvm_has_gsi_routing()) {
|
if (kvm_has_gsi_routing()) {
|
||||||
/* set up irq routing */
|
/* set up irq routing */
|
||||||
kvm_init_irq_routing(kvm_state);
|
kvm_init_irq_routing(kvm_state);
|
||||||
|
|
|
@ -56,6 +56,19 @@ static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
|
||||||
static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Block migration of a KVM GICv3 ITS device: the API for saving and
|
||||||
|
* restoring the state in the kernel is not yet available
|
||||||
|
*/
|
||||||
|
error_setg(&s->migration_blocker, "vITS migration is not implemented");
|
||||||
|
migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false);
|
s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false);
|
||||||
if (s->dev_fd < 0) {
|
if (s->dev_fd < 0) {
|
||||||
|
@ -73,13 +86,6 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
||||||
|
|
||||||
gicv3_its_init_mmio(s, NULL);
|
gicv3_its_init_mmio(s, NULL);
|
||||||
|
|
||||||
/*
|
|
||||||
* Block migration of a KVM GICv3 ITS device: the API for saving and
|
|
||||||
* restoring the state in the kernel is not yet available
|
|
||||||
*/
|
|
||||||
error_setg(&s->migration_blocker, "vITS migration is not implemented");
|
|
||||||
migrate_add_blocker(s->migration_blocker);
|
|
||||||
|
|
||||||
kvm_msi_use_devid = true;
|
kvm_msi_use_devid = true;
|
||||||
kvm_gsi_direct_mapping = false;
|
kvm_gsi_direct_mapping = false;
|
||||||
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
||||||
|
|
|
@ -103,6 +103,18 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
||||||
|
|
||||||
gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
|
gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL);
|
||||||
|
|
||||||
|
/* Block migration of a KVM GICv3 device: the API for saving and restoring
|
||||||
|
* the state in the kernel is not yet finalised in the kernel or
|
||||||
|
* implemented in QEMU.
|
||||||
|
*/
|
||||||
|
error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
|
||||||
|
migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to create the device via the device control API */
|
/* Try to create the device via the device control API */
|
||||||
s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false);
|
s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false);
|
||||||
if (s->dev_fd < 0) {
|
if (s->dev_fd < 0) {
|
||||||
|
@ -122,13 +134,6 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
||||||
kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
|
kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd);
|
KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd);
|
||||||
|
|
||||||
/* Block migration of a KVM GICv3 device: the API for saving and restoring
|
|
||||||
* the state in the kernel is not yet finalised in the kernel or
|
|
||||||
* implemented in QEMU.
|
|
||||||
*/
|
|
||||||
error_setg(&s->migration_blocker, "vGICv3 migration is not implemented");
|
|
||||||
migrate_add_blocker(s->migration_blocker);
|
|
||||||
|
|
||||||
if (kvm_has_gsi_routing()) {
|
if (kvm_has_gsi_routing()) {
|
||||||
/* set up irq routing */
|
/* set up irq routing */
|
||||||
kvm_init_irq_routing(kvm_state);
|
kvm_init_irq_routing(kvm_state);
|
||||||
|
|
|
@ -840,6 +840,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||||
uint8_t *pci_conf;
|
uint8_t *pci_conf;
|
||||||
uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
|
uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
|
||||||
PCI_BASE_ADDRESS_MEM_PREFETCH;
|
PCI_BASE_ADDRESS_MEM_PREFETCH;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
/* IRQFD requires MSI */
|
/* IRQFD requires MSI */
|
||||||
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
|
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
|
||||||
|
@ -903,9 +904,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vmstate_register_ram(s->ivshmem_bar2, DEVICE(s));
|
|
||||||
pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2);
|
|
||||||
|
|
||||||
if (s->master == ON_OFF_AUTO_AUTO) {
|
if (s->master == ON_OFF_AUTO_AUTO) {
|
||||||
s->master = s->vm_id == 0 ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
|
s->master = s->vm_id == 0 ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
|
||||||
}
|
}
|
||||||
|
@ -913,10 +911,18 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||||
if (!ivshmem_is_master(s)) {
|
if (!ivshmem_is_master(s)) {
|
||||||
error_setg(&s->migration_blocker,
|
error_setg(&s->migration_blocker,
|
||||||
"Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
|
"Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
|
||||||
migrate_add_blocker(s->migration_blocker);
|
migrate_add_blocker(s->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vmstate_register_ram(s->ivshmem_bar2, DEVICE(s));
|
||||||
|
pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2);
|
||||||
|
}
|
||||||
|
|
||||||
static void ivshmem_exit(PCIDevice *dev)
|
static void ivshmem_exit(PCIDevice *dev)
|
||||||
{
|
{
|
||||||
IVShmemState *s = IVSHMEM_COMMON(dev);
|
IVShmemState *s = IVSHMEM_COMMON(dev);
|
||||||
|
|
|
@ -238,8 +238,16 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||||
vhost_dummy_handle_output);
|
vhost_dummy_handle_output);
|
||||||
if (err != NULL) {
|
if (err != NULL) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
close(vhostfd);
|
goto close_fd;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
error_setg(&s->migration_blocker,
|
||||||
|
"vhost-scsi does not support migration");
|
||||||
|
migrate_add_blocker(s->migration_blocker, &err);
|
||||||
|
if (err) {
|
||||||
|
error_propagate(errp, err);
|
||||||
|
error_free(s->migration_blocker);
|
||||||
|
goto close_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
|
s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
|
||||||
|
@ -252,7 +260,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
|
error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
|
||||||
strerror(-ret));
|
strerror(-ret));
|
||||||
return;
|
goto free_vqs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At present, channel and lun both are 0 for bootable vhost-scsi disk */
|
/* At present, channel and lun both are 0 for bootable vhost-scsi disk */
|
||||||
|
@ -261,9 +269,14 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||||
/* Note: we can also get the minimum tpgt from kernel */
|
/* Note: we can also get the minimum tpgt from kernel */
|
||||||
s->target = vs->conf.boot_tpgt;
|
s->target = vs->conf.boot_tpgt;
|
||||||
|
|
||||||
error_setg(&s->migration_blocker,
|
return;
|
||||||
"vhost-scsi does not support migration");
|
|
||||||
migrate_add_blocker(s->migration_blocker);
|
free_vqs:
|
||||||
|
migrate_del_blocker(s->migration_blocker);
|
||||||
|
g_free(s->dev.vqs);
|
||||||
|
close_fd:
|
||||||
|
close(vhostfd);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
|
static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
|
||||||
|
|
|
@ -1176,6 +1176,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||||
{
|
{
|
||||||
uint64_t features;
|
uint64_t features;
|
||||||
int i, r, n_initialized_vqs = 0;
|
int i, r, n_initialized_vqs = 0;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
hdev->vdev = NULL;
|
hdev->vdev = NULL;
|
||||||
hdev->migration_blocker = NULL;
|
hdev->migration_blocker = NULL;
|
||||||
|
@ -1256,7 +1257,12 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdev->migration_blocker != NULL) {
|
if (hdev->migration_blocker != NULL) {
|
||||||
migrate_add_blocker(hdev->migration_blocker);
|
r = migrate_add_blocker(hdev->migration_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report_err(local_err);
|
||||||
|
error_free(hdev->migration_blocker);
|
||||||
|
goto fail_busyloop;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
|
hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
|
||||||
|
|
|
@ -243,6 +243,7 @@ void remove_migration_state_change_notifier(Notifier *notify);
|
||||||
MigrationState *migrate_init(const MigrationParams *params);
|
MigrationState *migrate_init(const MigrationParams *params);
|
||||||
bool migration_is_blocked(Error **errp);
|
bool migration_is_blocked(Error **errp);
|
||||||
bool migration_in_setup(MigrationState *);
|
bool migration_in_setup(MigrationState *);
|
||||||
|
bool migration_is_idle(MigrationState *s);
|
||||||
bool migration_has_finished(MigrationState *);
|
bool migration_has_finished(MigrationState *);
|
||||||
bool migration_has_failed(MigrationState *);
|
bool migration_has_failed(MigrationState *);
|
||||||
/* True if outgoing migration has entered postcopy phase */
|
/* True if outgoing migration has entered postcopy phase */
|
||||||
|
@ -287,8 +288,12 @@ int ram_postcopy_incoming_init(MigrationIncomingState *mis);
|
||||||
* @migrate_add_blocker - prevent migration from proceeding
|
* @migrate_add_blocker - prevent migration from proceeding
|
||||||
*
|
*
|
||||||
* @reason - an error to be returned whenever migration is attempted
|
* @reason - an error to be returned whenever migration is attempted
|
||||||
|
*
|
||||||
|
* @errp - [out] The reason (if any) we cannot block migration right now.
|
||||||
|
*
|
||||||
|
* @returns - 0 on success, -EBUSY on failure, with errp set.
|
||||||
*/
|
*/
|
||||||
void migrate_add_blocker(Error *reason);
|
int migrate_add_blocker(Error *reason, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @migrate_del_blocker - remove a blocking error from migration
|
* @migrate_del_blocker - remove a blocking error from migration
|
||||||
|
|
|
@ -1044,6 +1044,31 @@ bool migration_in_postcopy_after_devices(MigrationState *s)
|
||||||
return migration_in_postcopy(s) && s->postcopy_after_devices;
|
return migration_in_postcopy(s) && s->postcopy_after_devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool migration_is_idle(MigrationState *s)
|
||||||
|
{
|
||||||
|
if (!s) {
|
||||||
|
s = migrate_get_current();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (s->state) {
|
||||||
|
case MIGRATION_STATUS_NONE:
|
||||||
|
case MIGRATION_STATUS_CANCELLED:
|
||||||
|
case MIGRATION_STATUS_COMPLETED:
|
||||||
|
case MIGRATION_STATUS_FAILED:
|
||||||
|
return true;
|
||||||
|
case MIGRATION_STATUS_SETUP:
|
||||||
|
case MIGRATION_STATUS_CANCELLING:
|
||||||
|
case MIGRATION_STATUS_ACTIVE:
|
||||||
|
case MIGRATION_STATUS_POSTCOPY_ACTIVE:
|
||||||
|
case MIGRATION_STATUS_COLO:
|
||||||
|
return false;
|
||||||
|
case MIGRATION_STATUS__MAX:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MigrationState *migrate_init(const MigrationParams *params)
|
MigrationState *migrate_init(const MigrationParams *params)
|
||||||
{
|
{
|
||||||
MigrationState *s = migrate_get_current();
|
MigrationState *s = migrate_get_current();
|
||||||
|
@ -1086,9 +1111,17 @@ MigrationState *migrate_init(const MigrationParams *params)
|
||||||
|
|
||||||
static GSList *migration_blockers;
|
static GSList *migration_blockers;
|
||||||
|
|
||||||
void migrate_add_blocker(Error *reason)
|
int migrate_add_blocker(Error *reason, Error **errp)
|
||||||
{
|
{
|
||||||
|
if (migration_is_idle(NULL)) {
|
||||||
migration_blockers = g_slist_prepend(migration_blockers, reason);
|
migration_blockers = g_slist_prepend(migration_blockers, reason);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_propagate(errp, error_copy(reason));
|
||||||
|
error_prepend(errp, "disallowing migration blocker (migration in "
|
||||||
|
"progress) for: ");
|
||||||
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void migrate_del_blocker(Error *reason)
|
void migrate_del_blocker(Error *reason)
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "migration/migration.h"
|
#include "migration/migration.h"
|
||||||
|
|
||||||
void migrate_add_blocker(Error *reason)
|
int migrate_add_blocker(Error *reason, Error **errp)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void migrate_del_blocker(Error *reason)
|
void migrate_del_blocker(Error *reason)
|
||||||
|
|
|
@ -710,6 +710,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
||||||
uint32_t signature[3];
|
uint32_t signature[3];
|
||||||
int kvm_base = KVM_CPUID_SIGNATURE;
|
int kvm_base = KVM_CPUID_SIGNATURE;
|
||||||
int r;
|
int r;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
memset(&cpuid_data, 0, sizeof(cpuid_data));
|
memset(&cpuid_data, 0, sizeof(cpuid_data));
|
||||||
|
|
||||||
|
@ -970,7 +971,12 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
||||||
error_setg(&invtsc_mig_blocker,
|
error_setg(&invtsc_mig_blocker,
|
||||||
"State blocked by non-migratable CPU device"
|
"State blocked by non-migratable CPU device"
|
||||||
" (invtsc flag)");
|
" (invtsc flag)");
|
||||||
migrate_add_blocker(invtsc_mig_blocker);
|
r = migrate_add_blocker(invtsc_mig_blocker, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_report_err(local_err);
|
||||||
|
error_free(invtsc_mig_blocker);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
/* for savevm */
|
/* for savevm */
|
||||||
vmstate_x86_cpu.unmigratable = 1;
|
vmstate_x86_cpu.unmigratable = 1;
|
||||||
}
|
}
|
||||||
|
@ -979,12 +985,12 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
||||||
cpuid_data.cpuid.padding = 0;
|
cpuid_data.cpuid.padding = 0;
|
||||||
r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data);
|
r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data);
|
||||||
if (r) {
|
if (r) {
|
||||||
return r;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = kvm_arch_set_tsc_khz(cs);
|
r = kvm_arch_set_tsc_khz(cs);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vcpu's TSC frequency is either specified by user, or following
|
/* vcpu's TSC frequency is either specified by user, or following
|
||||||
|
@ -1011,6 +1017,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
migrate_del_blocker(invtsc_mig_blocker);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_arch_reset_vcpu(X86CPU *cpu)
|
void kvm_arch_reset_vcpu(X86CPU *cpu)
|
||||||
|
|
Loading…
Reference in New Issue