* Kirti Wankhede (kwankhede@nvidia.com) wrote:
> VM state change handler gets called on change in VM's state. This is used to set
> VFIO device state to _RUNNING.
> VM state change handler, migration state change handler and log_sync listener
> are called asynchronously, which sometimes lead to data corruption in migration
> region. Initialised mutex that is used to serialize operations on migration data
> region during saving state.
>
> Signed-off-by: Kirti Wankhede <kwankhede@nvidia.com>
> Reviewed-by: Neo Jia <cjia@nvidia.com>
> ---
> hw/vfio/migration.c | 45 +++++++++++++++++++++++++++++++++++++++++++
> include/hw/vfio/vfio-common.h | 4 ++++
> 2 files changed, 49 insertions(+)
>
> diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
> index ba58d9253d26..15af218c23d1 100644
> --- a/hw/vfio/migration.c
> +++ b/hw/vfio/migration.c
> @@ -77,6 +77,41 @@ err:
> return ret;
> }
>
> +static int vfio_migration_set_state(VFIODevice *vbasedev, uint32_t state)
> +{
> + VFIOMigration *migration = vbasedev->migration;
> + VFIORegion *region = &migration->region.buffer;
> + int ret = 0;
> +
> + ret = pwrite(vbasedev->fd, &state, sizeof(state),
> + region->fd_offset + offsetof(struct vfio_device_migration_info,
> + device_state));
> + if (ret < 0) {
> + error_report("Failed to set migration state %d %s",
> + ret, strerror(errno));
Please include the device name/id in errors; it just makes it easier to
figure out the cause when someone sends me a log.
Other than that;
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
> + return ret;
> + }
> +
> + vbasedev->device_state = state;
> + return 0;
> +}
> +
> +static void vfio_vmstate_change(void *opaque, int running, RunState state)
> +{
> + VFIODevice *vbasedev = opaque;
> +
> + if ((vbasedev->vm_running != running) && running) {
> + int ret;
> +
> + ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_RUNNING);
> + if (ret) {
> + error_report("Failed to set state RUNNING");
> + }
> + }
> +
> + vbasedev->vm_running = running;
> +}
> +
> static int vfio_migration_init(VFIODevice *vbasedev,
> struct vfio_region_info *info)
> {
> @@ -91,6 +126,11 @@ static int vfio_migration_init(VFIODevice *vbasedev,
> return ret;
> }
>
> + qemu_mutex_init(&vbasedev->migration->lock);
> +
> + vbasedev->vm_state = qemu_add_vm_change_state_handler(vfio_vmstate_change,
> + vbasedev);
> +
> return 0;
> }
>
> @@ -127,11 +167,16 @@ void vfio_migration_finalize(VFIODevice *vbasedev)
> return;
> }
>
> + if (vbasedev->vm_state) {
> + qemu_del_vm_change_state_handler(vbasedev->vm_state);
> + }
> +
> if (vbasedev->migration_blocker) {
> migrate_del_blocker(vbasedev->migration_blocker);
> error_free(vbasedev->migration_blocker);
> }
>
> + qemu_mutex_destroy(&vbasedev->migration->lock);
> vfio_migration_region_exit(vbasedev);
> g_free(vbasedev->migration);
> }
> diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
> index 1374a03470d8..f2392e97fa57 100644
> --- a/include/hw/vfio/vfio-common.h
> +++ b/include/hw/vfio/vfio-common.h
> @@ -29,6 +29,7 @@
> #ifdef CONFIG_LINUX
> #include <linux/vfio.h>
> #endif
> +#include "sysemu/sysemu.h"
>
> #define VFIO_MSG_PREFIX "vfio %s: "
>
> @@ -129,6 +130,9 @@ typedef struct VFIODevice {
> unsigned int flags;
> VFIOMigration *migration;
> Error *migration_blocker;
> + uint32_t device_state;
> + VMChangeStateEntry *vm_state;
> + int vm_running;
> } VFIODevice;
>
> struct VFIODeviceOps {
> --
> 2.7.0
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK