|
|
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 |
|