thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone

Blame SOURCES/kvm-dirty-bitmaps-clean-up-bitmaps-loading-and-migration.patch

ae23c9
From ae232c169a5ae37d3989919775332979d4e3b7d5 Mon Sep 17 00:00:00 2001
ae23c9
From: John Snow <jsnow@redhat.com>
ae23c9
Date: Tue, 20 Nov 2018 18:18:26 +0000
ae23c9
Subject: [PATCH 32/35] dirty-bitmaps: clean-up bitmaps loading and migration
ae23c9
 logic
ae23c9
ae23c9
RH-Author: John Snow <jsnow@redhat.com>
ae23c9
Message-id: <20181120181828.15132-23-jsnow@redhat.com>
ae23c9
Patchwork-id: 83074
ae23c9
O-Subject: [RHEL8/rhel qemu-kvm PATCH 22/24] dirty-bitmaps: clean-up bitmaps loading and migration logic
ae23c9
Bugzilla: 1518989
ae23c9
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
ae23c9
RH-Acked-by: Max Reitz <mreitz@redhat.com>
ae23c9
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
ae23c9
ae23c9
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
ae23c9
ae23c9
This patch aims to bring the following behavior:
ae23c9
ae23c9
1. We don't load bitmaps, when started in inactive mode. It's the case
ae23c9
of incoming migration. In this case we wait for bitmaps migration
ae23c9
through migration channel (if 'dirty-bitmaps' capability is enabled) or
ae23c9
for invalidation (to load bitmaps from the image).
ae23c9
ae23c9
2. We don't remove persistent bitmaps on inactivation. Instead, we only
ae23c9
remove bitmaps after storing. This is the only way to restore bitmaps,
ae23c9
if we decided to resume source after [failed] migration with
ae23c9
'dirty-bitmaps' capability enabled (which means, that bitmaps were not
ae23c9
stored).
ae23c9
ae23c9
3. We load bitmaps on open and any invalidation, it's ok for all cases:
ae23c9
  - normal open
ae23c9
  - migration target invalidation with dirty-bitmaps capability
ae23c9
    (bitmaps are migrating through migration channel, the are not
ae23c9
     stored, so they should have IN_USE flag set and will be skipped
ae23c9
     when loading. However, it would fail if bitmaps are read-only[1])
ae23c9
  - migration target invalidation without dirty-bitmaps capability
ae23c9
    (normal load of the bitmaps, if migrated with shared storage)
ae23c9
  - source invalidation with dirty-bitmaps capability
ae23c9
    (skip because IN_USE)
ae23c9
  - source invalidation without dirty-bitmaps capability
ae23c9
    (bitmaps were dropped, reload them)
ae23c9
ae23c9
[1]: to accurately handle this, migration of read-only bitmaps is
ae23c9
     explicitly forbidden in this patch.
ae23c9
ae23c9
New mechanism for not storing bitmaps when migrate with dirty-bitmaps
ae23c9
capability is introduced: migration filed in BdrvDirtyBitmap.
ae23c9
ae23c9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
ae23c9
Signed-off-by: John Snow <jsnow@redhat.com>
ae23c9
(cherry picked from commit 9c98f145dfb994e1e9d68a4d606ee5693891280d)
ae23c9
Signed-off-by: John Snow <jsnow@redhat.com>
ae23c9
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ae23c9
---
ae23c9
 block.c                        | 11 ++++---
ae23c9
 block/dirty-bitmap.c           | 36 +++++++++--------------
ae23c9
 block/qcow2-bitmap.c           | 16 +++++++++++
ae23c9
 block/qcow2.c                  | 65 ++++++++++++++++++++++++++++++++++++++++--
ae23c9
 include/block/dirty-bitmap.h   |  2 +-
ae23c9
 migration/block-dirty-bitmap.c | 10 +++++--
ae23c9
 6 files changed, 109 insertions(+), 31 deletions(-)
ae23c9
ae23c9
diff --git a/block.c b/block.c
ae23c9
index fbd569c..18ae591 100644
ae23c9
--- a/block.c
ae23c9
+++ b/block.c
ae23c9
@@ -4316,6 +4316,7 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
ae23c9
     uint64_t perm, shared_perm;
ae23c9
     Error *local_err = NULL;
ae23c9
     int ret;
ae23c9
+    BdrvDirtyBitmap *bm;
ae23c9
 
ae23c9
     if (!bs->drv)  {
ae23c9
         return;
ae23c9
@@ -4365,6 +4366,12 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
ae23c9
         }
ae23c9
     }
ae23c9
 
ae23c9
+    for (bm = bdrv_dirty_bitmap_next(bs, NULL); bm;
ae23c9
+         bm = bdrv_dirty_bitmap_next(bs, bm))
ae23c9
+    {
ae23c9
+        bdrv_dirty_bitmap_set_migration(bm, false);
ae23c9
+    }
ae23c9
+
ae23c9
     ret = refresh_total_sectors(bs, bs->total_sectors);
ae23c9
     if (ret < 0) {
ae23c9
         bs->open_flags |= BDRV_O_INACTIVE;
ae23c9
@@ -4479,10 +4486,6 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs,
ae23c9
         }
ae23c9
     }
ae23c9
 
ae23c9
-    /* At this point persistent bitmaps should be already stored by the format
ae23c9
-     * driver */
ae23c9
-    bdrv_release_persistent_dirty_bitmaps(bs);
ae23c9
-
ae23c9
     return 0;
ae23c9
 }
ae23c9
 
ae23c9
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
ae23c9
index 9b9ebd7..89fd1d7 100644
ae23c9
--- a/block/dirty-bitmap.c
ae23c9
+++ b/block/dirty-bitmap.c
ae23c9
@@ -55,6 +55,10 @@ struct BdrvDirtyBitmap {
ae23c9
                                    and this bitmap must remain unchanged while
ae23c9
                                    this flag is set. */
ae23c9
     bool persistent;            /* bitmap must be saved to owner disk image */
ae23c9
+    bool migration;             /* Bitmap is selected for migration, it should
ae23c9
+                                   not be stored on the next inactivation
ae23c9
+                                   (persistent flag doesn't matter until next
ae23c9
+                                   invalidation).*/
ae23c9
     QLIST_ENTRY(BdrvDirtyBitmap) list;
ae23c9
 };
ae23c9
 
ae23c9
@@ -390,26 +394,6 @@ void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
ae23c9
 }
ae23c9
 
ae23c9
 /**
ae23c9
- * Release all persistent dirty bitmaps attached to a BDS (for use in
ae23c9
- * bdrv_inactivate_recurse()).
ae23c9
- * There must not be any frozen bitmaps attached.
ae23c9
- * This function does not remove persistent bitmaps from the storage.
ae23c9
- * Called with BQL taken.
ae23c9
- */
ae23c9
-void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs)
ae23c9
-{
ae23c9
-    BdrvDirtyBitmap *bm, *next;
ae23c9
-
ae23c9
-    bdrv_dirty_bitmaps_lock(bs);
ae23c9
-    QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
ae23c9
-        if (bdrv_dirty_bitmap_get_persistance(bm)) {
ae23c9
-            bdrv_release_dirty_bitmap_locked(bm);
ae23c9
-        }
ae23c9
-    }
ae23c9
-    bdrv_dirty_bitmaps_unlock(bs);
ae23c9
-}
ae23c9
-
ae23c9
-/**
ae23c9
  * Remove persistent dirty bitmap from the storage if it exists.
ae23c9
  * Absence of bitmap is not an error, because we have the following scenario:
ae23c9
  * BdrvDirtyBitmap can have .persistent = true but not yet saved and have no
ae23c9
@@ -761,16 +745,24 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
ae23c9
     qemu_mutex_unlock(bitmap->mutex);
ae23c9
 }
ae23c9
 
ae23c9
+/* Called with BQL taken. */
ae23c9
+void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration)
ae23c9
+{
ae23c9
+    qemu_mutex_lock(bitmap->mutex);
ae23c9
+    bitmap->migration = migration;
ae23c9
+    qemu_mutex_unlock(bitmap->mutex);
ae23c9
+}
ae23c9
+
ae23c9
 bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
ae23c9
 {
ae23c9
-    return bitmap->persistent;
ae23c9
+    return bitmap->persistent && !bitmap->migration;
ae23c9
 }
ae23c9
 
ae23c9
 bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs)
ae23c9
 {
ae23c9
     BdrvDirtyBitmap *bm;
ae23c9
     QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
ae23c9
-        if (bm->persistent && !bm->readonly) {
ae23c9
+        if (bm->persistent && !bm->readonly && !bm->migration) {
ae23c9
             return true;
ae23c9
         }
ae23c9
     }
ae23c9
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
ae23c9
index 14050eb..a36773c 100644
ae23c9
--- a/block/qcow2-bitmap.c
ae23c9
+++ b/block/qcow2-bitmap.c
ae23c9
@@ -1418,6 +1418,22 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
ae23c9
         g_free(tb);
ae23c9
     }
ae23c9
 
ae23c9
+    QSIMPLEQ_FOREACH(bm, bm_list, entry) {
ae23c9
+        /* For safety, we remove bitmap after storing.
ae23c9
+         * We may be here in two cases:
ae23c9
+         * 1. bdrv_close. It's ok to drop bitmap.
ae23c9
+         * 2. inactivation. It means migration without 'dirty-bitmaps'
ae23c9
+         *    capability, so bitmaps are not marked with
ae23c9
+         *    BdrvDirtyBitmap.migration flags. It's not bad to drop them too,
ae23c9
+         *    and reload on invalidation.
ae23c9
+         */
ae23c9
+        if (bm->dirty_bitmap == NULL) {
ae23c9
+            continue;
ae23c9
+        }
ae23c9
+
ae23c9
+        bdrv_release_dirty_bitmap(bs, bm->dirty_bitmap);
ae23c9
+    }
ae23c9
+
ae23c9
     bitmap_list_free(bm_list);
ae23c9
     return;
ae23c9
 
ae23c9
diff --git a/block/qcow2.c b/block/qcow2.c
ae23c9
index d260cd6..36d1152 100644
ae23c9
--- a/block/qcow2.c
ae23c9
+++ b/block/qcow2.c
ae23c9
@@ -1487,8 +1487,69 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
ae23c9
         s->autoclear_features &= QCOW2_AUTOCLEAR_MASK;
ae23c9
     }
ae23c9
 
ae23c9
-    if (qcow2_load_dirty_bitmaps(bs, &local_err)) {
ae23c9
-        update_header = false;
ae23c9
+    /* == Handle persistent dirty bitmaps ==
ae23c9
+     *
ae23c9
+     * We want load dirty bitmaps in three cases:
ae23c9
+     *
ae23c9
+     * 1. Normal open of the disk in active mode, not related to invalidation
ae23c9
+     *    after migration.
ae23c9
+     *
ae23c9
+     * 2. Invalidation of the target vm after pre-copy phase of migration, if
ae23c9
+     *    bitmaps are _not_ migrating through migration channel, i.e.
ae23c9
+     *    'dirty-bitmaps' capability is disabled.
ae23c9
+     *
ae23c9
+     * 3. Invalidation of source vm after failed or canceled migration.
ae23c9
+     *    This is a very interesting case. There are two possible types of
ae23c9
+     *    bitmaps:
ae23c9
+     *
ae23c9
+     *    A. Stored on inactivation and removed. They should be loaded from the
ae23c9
+     *       image.
ae23c9
+     *
ae23c9
+     *    B. Not stored: not-persistent bitmaps and bitmaps, migrated through
ae23c9
+     *       the migration channel (with dirty-bitmaps capability).
ae23c9
+     *
ae23c9
+     *    On the other hand, there are two possible sub-cases:
ae23c9
+     *
ae23c9
+     *    3.1 disk was changed by somebody else while were inactive. In this
ae23c9
+     *        case all in-RAM dirty bitmaps (both persistent and not) are
ae23c9
+     *        definitely invalid. And we don't have any method to determine
ae23c9
+     *        this.
ae23c9
+     *
ae23c9
+     *        Simple and safe thing is to just drop all the bitmaps of type B on
ae23c9
+     *        inactivation. But in this case we lose bitmaps in valid 4.2 case.
ae23c9
+     *
ae23c9
+     *        On the other hand, resuming source vm, if disk was already changed
ae23c9
+     *        is a bad thing anyway: not only bitmaps, the whole vm state is
ae23c9
+     *        out of sync with disk.
ae23c9
+     *
ae23c9
+     *        This means, that user or management tool, who for some reason
ae23c9
+     *        decided to resume source vm, after disk was already changed by
ae23c9
+     *        target vm, should at least drop all dirty bitmaps by hand.
ae23c9
+     *
ae23c9
+     *        So, we can ignore this case for now, but TODO: "generation"
ae23c9
+     *        extension for qcow2, to determine, that image was changed after
ae23c9
+     *        last inactivation. And if it is changed, we will drop (or at least
ae23c9
+     *        mark as 'invalid' all the bitmaps of type B, both persistent
ae23c9
+     *        and not).
ae23c9
+     *
ae23c9
+     *    3.2 disk was _not_ changed while were inactive. Bitmaps may be saved
ae23c9
+     *        to disk ('dirty-bitmaps' capability disabled), or not saved
ae23c9
+     *        ('dirty-bitmaps' capability enabled), but we don't need to care
ae23c9
+     *        of: let's load bitmaps as always: stored bitmaps will be loaded,
ae23c9
+     *        and not stored has flag IN_USE=1 in the image and will be skipped
ae23c9
+     *        on loading.
ae23c9
+     *
ae23c9
+     * One remaining possible case when we don't want load bitmaps:
ae23c9
+     *
ae23c9
+     * 4. Open disk in inactive mode in target vm (bitmaps are migrating or
ae23c9
+     *    will be loaded on invalidation, no needs try loading them before)
ae23c9
+     */
ae23c9
+
ae23c9
+    if (!(bdrv_get_flags(bs) & BDRV_O_INACTIVE)) {
ae23c9
+        /* It's case 1, 2 or 3.2. Or 3.1 which is BUG in management layer. */
ae23c9
+        bool header_updated = qcow2_load_dirty_bitmaps(bs, &local_err);
ae23c9
+
ae23c9
+        update_header = update_header && !header_updated;
ae23c9
     }
ae23c9
     if (local_err != NULL) {
ae23c9
         error_propagate(errp, local_err);
ae23c9
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
ae23c9
index 1463943..8f38a3d 100644
ae23c9
--- a/include/block/dirty-bitmap.h
ae23c9
+++ b/include/block/dirty-bitmap.h
ae23c9
@@ -26,7 +26,6 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
ae23c9
                                         const char *name);
ae23c9
 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
ae23c9
 void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);
ae23c9
-void bdrv_release_persistent_dirty_bitmaps(BlockDriverState *bs);
ae23c9
 void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
ae23c9
                                          const char *name,
ae23c9
                                          Error **errp);
ae23c9
@@ -72,6 +71,7 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
ae23c9
 void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked);
ae23c9
 void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
ae23c9
                              HBitmap **backup, Error **errp);
ae23c9
+void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration);
ae23c9
 
ae23c9
 /* Functions that require manual locking.  */
ae23c9
 void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
ae23c9
diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
ae23c9
index 47251af..ffe7aca 100644
ae23c9
--- a/migration/block-dirty-bitmap.c
ae23c9
+++ b/migration/block-dirty-bitmap.c
ae23c9
@@ -307,6 +307,12 @@ static int init_dirty_bitmap_migration(void)
ae23c9
                 goto fail;
ae23c9
             }
ae23c9
 
ae23c9
+            if (bdrv_dirty_bitmap_readonly(bitmap)) {
ae23c9
+                error_report("Can't migrate read-only dirty bitmap: '%s",
ae23c9
+                             bdrv_dirty_bitmap_name(bitmap));
ae23c9
+                goto fail;
ae23c9
+            }
ae23c9
+
ae23c9
             bdrv_ref(bs);
ae23c9
             bdrv_dirty_bitmap_set_qmp_locked(bitmap, true);
ae23c9
 
ae23c9
@@ -329,9 +335,9 @@ static int init_dirty_bitmap_migration(void)
ae23c9
         }
ae23c9
     }
ae23c9
 
ae23c9
-    /* unset persistance here, to not roll back it */
ae23c9
+    /* unset migration flags here, to not roll back it */
ae23c9
     QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) {
ae23c9
-        bdrv_dirty_bitmap_set_persistance(dbms->bitmap, false);
ae23c9
+        bdrv_dirty_bitmap_set_migration(dbms->bitmap, true);
ae23c9
     }
ae23c9
 
ae23c9
     if (QSIMPLEQ_EMPTY(&dirty_bitmap_mig_state.dbms_list)) {
ae23c9
-- 
ae23c9
1.8.3.1
ae23c9