On Wed, Oct 23, 2024, 2:02 p.m. Peter Xu <pet...@redhat.com> wrote:

> Migration object can be freed (e.g. after migration_shutdown()) before some
> other device codes can still run, while we do have a bunch of migration
> helpers exported in migration/misc.h that logically can be invoked at any
> time of QEMU, even during destruction of a VM.
>
> Make all these functions safe to be called, especially, not crashing after
> the migration object is unreferenced from the main context.
>
> To achieve it, only reference global_migration variable in the exported
> functions.  The variable is only reset with BQL, so it's safe to access.
>
> Add a comment in the header explaining how to guarantee thread safe on
> using these functions, and we choose BQL because fundamentally that's how
> it's working now.  We can move to other things (e.g. RCU) whenever
> necessary in the future but it's an overkill if we have BQL anyway in
> most/all existing callers.
>
> When at it, update some comments, e.g. migrate_announce_params() is
> exported from options.c now.
>

Err I wrongly fetched the list email then lost my local English fix with
s/when/while/.  I'll make sure it's fixed ultimately when repost.


> Cc: Cédric Le Goater <c...@redhat.com>
> Cc: Avihai Horon <avih...@nvidia.com>
> Cc: Fabiano Rosas <faro...@suse.de>
> Cc: Dr. David Alan Gilbert <d...@treblig.org>
> Signed-off-by: Peter Xu <pet...@redhat.com>
> ---
>  include/migration/misc.h | 26 +++++++++++++++++++++-----
>  migration/migration.c    | 32 ++++++++++++++++++++++++++------
>  2 files changed, 47 insertions(+), 11 deletions(-)
>
> diff --git a/include/migration/misc.h b/include/migration/misc.h
> index df57be6b5e..48892f9672 100644
> --- a/include/migration/misc.h
> +++ b/include/migration/misc.h
> @@ -19,8 +19,19 @@
>  #include "qapi/qapi-types-net.h"
>  #include "migration/client-options.h"
>
> -/* migration/ram.c */
> +/*
> + * Misc migration functions exported to be used in QEMU generic system
> + * code outside migration/.
> + *
> + * By default, BQL is recommended before using below functions to avoid
> + * race conditions (concurrent updates to global_migration variable).
> It's
> + * caller's responsibility to make sure it's thread safe otherwise when
> + * below helpers are used without BQL held.  When unsure, take BQL always.
> + */
>
> +/*
> + * migration/ram.c
> + */
>  typedef enum PrecopyNotifyReason {
>      PRECOPY_NOTIFY_SETUP = 0,
>      PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC = 1,
> @@ -43,14 +54,19 @@ void ram_mig_init(void);
>  void qemu_guest_free_page_hint(void *addr, size_t len);
>  bool migrate_ram_is_ignored(RAMBlock *block);
>
> -/* migration/block.c */
> -
> +/*
> + * migration/options.c
> + */
>  AnnounceParameters *migrate_announce_params(void);
> -/* migration/savevm.c */
>
> +/*
> + * migration/savevm.c
> + */
>  void dump_vmstate_json_to_file(FILE *out_fp);
>
> -/* migration/migration.c */
> +/*
> + * migration/migration.c
> + */
>  void migration_object_init(void);
>  void migration_shutdown(void);
>  bool migration_is_idle(void);
> diff --git a/migration/migration.c b/migration/migration.c
> index c4adad7972..667816cc65 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -1157,7 +1157,11 @@ void
> migrate_send_rp_resume_ack(MigrationIncomingState *mis, uint32_t value)
>   */
>  bool migration_is_setup_or_active(void)
>  {
> -    MigrationState *s = current_migration;
> +    MigrationState *s = global_migration;
> +
> +    if (!s) {
> +        return false;
> +    }
>
>      switch (s->state) {
>      case MIGRATION_STATUS_ACTIVE:
> @@ -1174,7 +1178,6 @@ bool migration_is_setup_or_active(void)
>
>      default:
>          return false;
> -
>      }
>  }
>
> @@ -1721,7 +1724,11 @@ bool migration_is_idle(void)
>
>  bool migration_is_active(void)
>  {
> -    MigrationState *s = current_migration;
> +    MigrationState *s = global_migration;
> +
> +    if (!s) {
> +        return false;
> +    }
>
>      return (s->state == MIGRATION_STATUS_ACTIVE ||
>              s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE);
> @@ -1729,14 +1736,23 @@ bool migration_is_active(void)
>
>  bool migration_is_device(void)
>  {
> -    MigrationState *s = current_migration;
> +    MigrationState *s = global_migration;
> +
> +    if (!s) {
> +        return false;
> +    }
>
>      return s->state == MIGRATION_STATUS_DEVICE;
>  }
>
>  bool migration_thread_is_self(void)
>  {
> -    MigrationState *s = current_migration;
> +    MigrationState *s = global_migration;
> +
> +    /* If no migration object, must not be the migration thread */
> +    if (!s) {
> +        return false;
> +    }
>
>      return qemu_thread_is_self(&s->thread);
>  }
> @@ -3113,7 +3129,11 @@ static MigThrError postcopy_pause(MigrationState *s)
>
>  void migration_file_set_error(int ret, Error *err)
>  {
> -    MigrationState *s = current_migration;
> +    MigrationState *s = global_migration;
> +
> +    if (!s) {
> +        return;
> +    }
>
>      WITH_QEMU_LOCK_GUARD(&s->qemu_file_lock) {
>          if (s->to_dst_file) {
> --
> 2.45.0
>
>

Reply via email to