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

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