Commit 3b52726e authored by Vladimir Sementsov-Ogievskiy's avatar Vladimir Sementsov-Ogievskiy Committed by Eric Blake
Browse files

migration/block-dirty-bitmap: refactor state global variables



Move all state variables into one global struct. Reduce global
variable usage, utilizing opaque pointer where possible.

Signed-off-by: default avatarVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: default avatarAndrey Shinkevich <andrey.shinkevich@virtuozzo.com>
Message-Id: <20200727194236.19551-12-vsementsov@virtuozzo.com>
Signed-off-by: default avatarEric Blake <eblake@redhat.com>
parent d0cccbd1
Loading
Loading
Loading
Loading
+99 −80
Original line number Diff line number Diff line
@@ -128,6 +128,12 @@ typedef struct DBMSaveState {
    BdrvDirtyBitmap *prev_bitmap;
} DBMSaveState;

typedef struct LoadBitmapState {
    BlockDriverState *bs;
    BdrvDirtyBitmap *bitmap;
    bool migrated;
} LoadBitmapState;

/* State of the dirty bitmap migration (DBM) during load process */
typedef struct DBMLoadState {
    uint32_t flags;
@@ -135,18 +141,17 @@ typedef struct DBMLoadState {
    char bitmap_name[256];
    BlockDriverState *bs;
    BdrvDirtyBitmap *bitmap;

    GSList *enabled_bitmaps;
    QemuMutex finish_lock;
} DBMLoadState;

static DBMSaveState dirty_bitmap_mig_state;
typedef struct DBMState {
    DBMSaveState save;
    DBMLoadState load;
} DBMState;

/* State of one bitmap during load process */
typedef struct LoadBitmapState {
    BlockDriverState *bs;
    BdrvDirtyBitmap *bitmap;
    bool migrated;
} LoadBitmapState;
static GSList *enabled_bitmaps;
QemuMutex finish_lock;
static DBMState dbm_state;

static uint32_t qemu_get_bitmap_flags(QEMUFile *f)
{
@@ -169,21 +174,21 @@ static void qemu_put_bitmap_flags(QEMUFile *f, uint32_t flags)
    qemu_put_byte(f, flags);
}

static void send_bitmap_header(QEMUFile *f, SaveBitmapState *dbms,
                               uint32_t additional_flags)
static void send_bitmap_header(QEMUFile *f, DBMSaveState *s,
                               SaveBitmapState *dbms, uint32_t additional_flags)
{
    BlockDriverState *bs = dbms->bs;
    BdrvDirtyBitmap *bitmap = dbms->bitmap;
    uint32_t flags = additional_flags;
    trace_send_bitmap_header_enter();

    if (bs != dirty_bitmap_mig_state.prev_bs) {
        dirty_bitmap_mig_state.prev_bs = bs;
    if (bs != s->prev_bs) {
        s->prev_bs = bs;
        flags |= DIRTY_BITMAP_MIG_FLAG_DEVICE_NAME;
    }

    if (bitmap != dirty_bitmap_mig_state.prev_bitmap) {
        dirty_bitmap_mig_state.prev_bitmap = bitmap;
    if (bitmap != s->prev_bitmap) {
        s->prev_bitmap = bitmap;
        flags |= DIRTY_BITMAP_MIG_FLAG_BITMAP_NAME;
    }

@@ -198,19 +203,22 @@ static void send_bitmap_header(QEMUFile *f, SaveBitmapState *dbms,
    }
}

static void send_bitmap_start(QEMUFile *f, SaveBitmapState *dbms)
static void send_bitmap_start(QEMUFile *f, DBMSaveState *s,
                              SaveBitmapState *dbms)
{
    send_bitmap_header(f, dbms, DIRTY_BITMAP_MIG_FLAG_START);
    send_bitmap_header(f, s, dbms, DIRTY_BITMAP_MIG_FLAG_START);
    qemu_put_be32(f, bdrv_dirty_bitmap_granularity(dbms->bitmap));
    qemu_put_byte(f, dbms->flags);
}

static void send_bitmap_complete(QEMUFile *f, SaveBitmapState *dbms)
static void send_bitmap_complete(QEMUFile *f, DBMSaveState *s,
                                 SaveBitmapState *dbms)
{
    send_bitmap_header(f, dbms, DIRTY_BITMAP_MIG_FLAG_COMPLETE);
    send_bitmap_header(f, s, dbms, DIRTY_BITMAP_MIG_FLAG_COMPLETE);
}

static void send_bitmap_bits(QEMUFile *f, SaveBitmapState *dbms,
static void send_bitmap_bits(QEMUFile *f, DBMSaveState *s,
                             SaveBitmapState *dbms,
                             uint64_t start_sector, uint32_t nr_sectors)
{
    /* align for buffer_is_zero() */
@@ -235,7 +243,7 @@ static void send_bitmap_bits(QEMUFile *f, SaveBitmapState *dbms,

    trace_send_bitmap_bits(flags, start_sector, nr_sectors, buf_size);

    send_bitmap_header(f, dbms, flags);
    send_bitmap_header(f, s, dbms, flags);

    qemu_put_be64(f, start_sector);
    qemu_put_be32(f, nr_sectors);
@@ -254,12 +262,12 @@ static void send_bitmap_bits(QEMUFile *f, SaveBitmapState *dbms,
}

/* Called with iothread lock taken.  */
static void dirty_bitmap_do_save_cleanup(void)
static void dirty_bitmap_do_save_cleanup(DBMSaveState *s)
{
    SaveBitmapState *dbms;

    while ((dbms = QSIMPLEQ_FIRST(&dirty_bitmap_mig_state.dbms_list)) != NULL) {
        QSIMPLEQ_REMOVE_HEAD(&dirty_bitmap_mig_state.dbms_list, entry);
    while ((dbms = QSIMPLEQ_FIRST(&s->dbms_list)) != NULL) {
        QSIMPLEQ_REMOVE_HEAD(&s->dbms_list, entry);
        bdrv_dirty_bitmap_set_busy(dbms->bitmap, false);
        bdrv_unref(dbms->bs);
        g_free(dbms);
@@ -267,7 +275,8 @@ static void dirty_bitmap_do_save_cleanup(void)
}

/* Called with iothread lock taken. */
static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name)
static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs,
                               const char *bs_name)
{
    BdrvDirtyBitmap *bitmap;
    SaveBitmapState *dbms;
@@ -322,25 +331,24 @@ static int add_bitmaps_to_list(BlockDriverState *bs, const char *bs_name)
            dbms->flags |= DIRTY_BITMAP_MIG_START_FLAG_PERSISTENT;
        }

        QSIMPLEQ_INSERT_TAIL(&dirty_bitmap_mig_state.dbms_list,
                             dbms, entry);
        QSIMPLEQ_INSERT_TAIL(&s->dbms_list, dbms, entry);
    }

    return 0;
}

/* Called with iothread lock taken. */
static int init_dirty_bitmap_migration(void)
static int init_dirty_bitmap_migration(DBMSaveState *s)
{
    BlockDriverState *bs;
    SaveBitmapState *dbms;
    GHashTable *handled_by_blk = g_hash_table_new(NULL, NULL);
    BlockBackend *blk;

    dirty_bitmap_mig_state.bulk_completed = false;
    dirty_bitmap_mig_state.prev_bs = NULL;
    dirty_bitmap_mig_state.prev_bitmap = NULL;
    dirty_bitmap_mig_state.no_bitmaps = false;
    s->bulk_completed = false;
    s->prev_bs = NULL;
    s->prev_bitmap = NULL;
    s->no_bitmaps = false;

    /*
     * Use blockdevice name for direct (or filtered) children of named block
@@ -369,7 +377,7 @@ static int init_dirty_bitmap_migration(void)
        }

        if (bs && bs->drv && !bs->drv->is_filter) {
            if (add_bitmaps_to_list(bs, name)) {
            if (add_bitmaps_to_list(s, bs, name)) {
                goto fail;
            }
            g_hash_table_add(handled_by_blk, bs);
@@ -381,18 +389,18 @@ static int init_dirty_bitmap_migration(void)
            continue;
        }

        if (add_bitmaps_to_list(bs, bdrv_get_node_name(bs))) {
        if (add_bitmaps_to_list(s, bs, bdrv_get_node_name(bs))) {
            goto fail;
        }
    }

    /* unset migration flags here, to not roll back it */
    QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) {
    QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) {
        bdrv_dirty_bitmap_skip_store(dbms->bitmap, true);
    }

    if (QSIMPLEQ_EMPTY(&dirty_bitmap_mig_state.dbms_list)) {
        dirty_bitmap_mig_state.no_bitmaps = true;
    if (QSIMPLEQ_EMPTY(&s->dbms_list)) {
        s->no_bitmaps = true;
    }

    g_hash_table_destroy(handled_by_blk);
@@ -401,18 +409,19 @@ static int init_dirty_bitmap_migration(void)

fail:
    g_hash_table_destroy(handled_by_blk);
    dirty_bitmap_do_save_cleanup();
    dirty_bitmap_do_save_cleanup(s);

    return -1;
}

/* Called with no lock taken.  */
static void bulk_phase_send_chunk(QEMUFile *f, SaveBitmapState *dbms)
static void bulk_phase_send_chunk(QEMUFile *f, DBMSaveState *s,
                                  SaveBitmapState *dbms)
{
    uint32_t nr_sectors = MIN(dbms->total_sectors - dbms->cur_sector,
                             dbms->sectors_per_chunk);

    send_bitmap_bits(f, dbms, dbms->cur_sector, nr_sectors);
    send_bitmap_bits(f, s, dbms, dbms->cur_sector, nr_sectors);

    dbms->cur_sector += nr_sectors;
    if (dbms->cur_sector >= dbms->total_sectors) {
@@ -421,61 +430,66 @@ static void bulk_phase_send_chunk(QEMUFile *f, SaveBitmapState *dbms)
}

/* Called with no lock taken.  */
static void bulk_phase(QEMUFile *f, bool limit)
static void bulk_phase(QEMUFile *f, DBMSaveState *s, bool limit)
{
    SaveBitmapState *dbms;

    QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) {
    QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) {
        while (!dbms->bulk_completed) {
            bulk_phase_send_chunk(f, dbms);
            bulk_phase_send_chunk(f, s, dbms);
            if (limit && qemu_file_rate_limit(f)) {
                return;
            }
        }
    }

    dirty_bitmap_mig_state.bulk_completed = true;
    s->bulk_completed = true;
}

/* for SaveVMHandlers */
static void dirty_bitmap_save_cleanup(void *opaque)
{
    dirty_bitmap_do_save_cleanup();
    DBMSaveState *s = &((DBMState *)opaque)->save;

    dirty_bitmap_do_save_cleanup(s);
}

static int dirty_bitmap_save_iterate(QEMUFile *f, void *opaque)
{
    DBMSaveState *s = &((DBMState *)opaque)->save;

    trace_dirty_bitmap_save_iterate(migration_in_postcopy());

    if (migration_in_postcopy() && !dirty_bitmap_mig_state.bulk_completed) {
        bulk_phase(f, true);
    if (migration_in_postcopy() && !s->bulk_completed) {
        bulk_phase(f, s, true);
    }

    qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS);

    return dirty_bitmap_mig_state.bulk_completed;
    return s->bulk_completed;
}

/* Called with iothread lock taken.  */

static int dirty_bitmap_save_complete(QEMUFile *f, void *opaque)
{
    DBMSaveState *s = &((DBMState *)opaque)->save;
    SaveBitmapState *dbms;
    trace_dirty_bitmap_save_complete_enter();

    if (!dirty_bitmap_mig_state.bulk_completed) {
        bulk_phase(f, false);
    if (!s->bulk_completed) {
        bulk_phase(f, s, false);
    }

    QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) {
        send_bitmap_complete(f, dbms);
    QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) {
        send_bitmap_complete(f, s, dbms);
    }

    qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS);

    trace_dirty_bitmap_save_complete_finish();

    dirty_bitmap_do_save_cleanup();
    dirty_bitmap_save_cleanup(opaque);
    return 0;
}

@@ -485,12 +499,13 @@ static void dirty_bitmap_save_pending(QEMUFile *f, void *opaque,
                                      uint64_t *res_compatible,
                                      uint64_t *res_postcopy_only)
{
    DBMSaveState *s = &((DBMState *)opaque)->save;
    SaveBitmapState *dbms;
    uint64_t pending = 0;

    qemu_mutex_lock_iothread();

    QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) {
    QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) {
        uint64_t gran = bdrv_dirty_bitmap_granularity(dbms->bitmap);
        uint64_t sectors = dbms->bulk_completed ? 0 :
                           dbms->total_sectors - dbms->cur_sector;
@@ -549,7 +564,7 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s)
        b->bs = s->bs;
        b->bitmap = s->bitmap;
        b->migrated = false;
        enabled_bitmaps = g_slist_prepend(enabled_bitmaps, b);
        s->enabled_bitmaps = g_slist_prepend(s->enabled_bitmaps, b);
    }

    return 0;
@@ -557,11 +572,12 @@ static int dirty_bitmap_load_start(QEMUFile *f, DBMLoadState *s)

void dirty_bitmap_mig_before_vm_start(void)
{
    DBMLoadState *s = &dbm_state.load;
    GSList *item;

    qemu_mutex_lock(&finish_lock);
    qemu_mutex_lock(&s->finish_lock);

    for (item = enabled_bitmaps; item; item = g_slist_next(item)) {
    for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) {
        LoadBitmapState *b = item->data;

        if (b->migrated) {
@@ -573,10 +589,10 @@ void dirty_bitmap_mig_before_vm_start(void)
        g_free(b);
    }

    g_slist_free(enabled_bitmaps);
    enabled_bitmaps = NULL;
    g_slist_free(s->enabled_bitmaps);
    s->enabled_bitmaps = NULL;

    qemu_mutex_unlock(&finish_lock);
    qemu_mutex_unlock(&s->finish_lock);
}

static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s)
@@ -585,9 +601,9 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s)
    trace_dirty_bitmap_load_complete();
    bdrv_dirty_bitmap_deserialize_finish(s->bitmap);

    qemu_mutex_lock(&finish_lock);
    qemu_mutex_lock(&s->finish_lock);

    for (item = enabled_bitmaps; item; item = g_slist_next(item)) {
    for (item = s->enabled_bitmaps; item; item = g_slist_next(item)) {
        LoadBitmapState *b = item->data;

        if (b->bitmap == s->bitmap) {
@@ -598,7 +614,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s)

    if (bdrv_dirty_bitmap_has_successor(s->bitmap)) {
        bdrv_dirty_bitmap_lock(s->bitmap);
        if (enabled_bitmaps == NULL) {
        if (s->enabled_bitmaps == NULL) {
            /* in postcopy */
            bdrv_reclaim_dirty_bitmap_locked(s->bitmap, &error_abort);
            bdrv_enable_dirty_bitmap_locked(s->bitmap);
@@ -617,7 +633,7 @@ static void dirty_bitmap_load_complete(QEMUFile *f, DBMLoadState *s)
        bdrv_dirty_bitmap_unlock(s->bitmap);
    }

    qemu_mutex_unlock(&finish_lock);
    qemu_mutex_unlock(&s->finish_lock);
}

static int dirty_bitmap_load_bits(QEMUFile *f, DBMLoadState *s)
@@ -714,7 +730,7 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s)

static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id)
{
    static DBMLoadState s;
    DBMLoadState *s = &((DBMState *)opaque)->load;
    int ret = 0;

    trace_dirty_bitmap_load_enter();
@@ -724,17 +740,17 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id)
    }

    do {
        ret = dirty_bitmap_load_header(f, &s);
        ret = dirty_bitmap_load_header(f, s);
        if (ret < 0) {
            return ret;
        }

        if (s.flags & DIRTY_BITMAP_MIG_FLAG_START) {
            ret = dirty_bitmap_load_start(f, &s);
        } else if (s.flags & DIRTY_BITMAP_MIG_FLAG_COMPLETE) {
            dirty_bitmap_load_complete(f, &s);
        } else if (s.flags & DIRTY_BITMAP_MIG_FLAG_BITS) {
            ret = dirty_bitmap_load_bits(f, &s);
        if (s->flags & DIRTY_BITMAP_MIG_FLAG_START) {
            ret = dirty_bitmap_load_start(f, s);
        } else if (s->flags & DIRTY_BITMAP_MIG_FLAG_COMPLETE) {
            dirty_bitmap_load_complete(f, s);
        } else if (s->flags & DIRTY_BITMAP_MIG_FLAG_BITS) {
            ret = dirty_bitmap_load_bits(f, s);
        }

        if (!ret) {
@@ -744,7 +760,7 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id)
        if (ret) {
            return ret;
        }
    } while (!(s.flags & DIRTY_BITMAP_MIG_FLAG_EOS));
    } while (!(s->flags & DIRTY_BITMAP_MIG_FLAG_EOS));

    trace_dirty_bitmap_load_success();
    return 0;
@@ -752,13 +768,14 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id)

static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque)
{
    DBMSaveState *s = &((DBMState *)opaque)->save;
    SaveBitmapState *dbms = NULL;
    if (init_dirty_bitmap_migration() < 0) {
    if (init_dirty_bitmap_migration(s) < 0) {
        return -1;
    }

    QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) {
        send_bitmap_start(f, dbms);
    QSIMPLEQ_FOREACH(dbms, &s->dbms_list, entry) {
        send_bitmap_start(f, s, dbms);
    }
    qemu_put_bitmap_flags(f, DIRTY_BITMAP_MIG_FLAG_EOS);

@@ -767,7 +784,9 @@ static int dirty_bitmap_save_setup(QEMUFile *f, void *opaque)

static bool dirty_bitmap_is_active(void *opaque)
{
    return migrate_dirty_bitmaps() && !dirty_bitmap_mig_state.no_bitmaps;
    DBMSaveState *s = &((DBMState *)opaque)->save;

    return migrate_dirty_bitmaps() && !s->no_bitmaps;
}

static bool dirty_bitmap_is_active_iterate(void *opaque)
@@ -795,10 +814,10 @@ static SaveVMHandlers savevm_dirty_bitmap_handlers = {

void dirty_bitmap_mig_init(void)
{
    QSIMPLEQ_INIT(&dirty_bitmap_mig_state.dbms_list);
    qemu_mutex_init(&finish_lock);
    QSIMPLEQ_INIT(&dbm_state.save.dbms_list);
    qemu_mutex_init(&dbm_state.load.finish_lock);

    register_savevm_live("dirty-bitmap", 0, 1,
                         &savevm_dirty_bitmap_handlers,
                         &dirty_bitmap_mig_state);
                         &dbm_state);
}