* [Qemu-devel] [PATCH 01/24] specs/qcow2: fix bitmap granularity qemu-specific note
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 02/24] specs/qcow2: do not use wording 'bitmap header' Vladimir Sementsov-Ogievskiy
` (23 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
docs/specs/qcow2.txt | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
index 80cdfd0..dda53dd 100644
--- a/docs/specs/qcow2.txt
+++ b/docs/specs/qcow2.txt
@@ -472,8 +472,7 @@ Structure of a bitmap directory entry:
17: granularity_bits
Granularity bits. Valid values: 0 - 63.
- Note: Qemu currently doesn't support granularity_bits
- greater than 31.
+ Note: Qemu currently supports only values 9 - 31.
Granularity is calculated as
granularity = 1 << granularity_bits
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 02/24] specs/qcow2: do not use wording 'bitmap header'
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 01/24] specs/qcow2: fix bitmap granularity qemu-specific note Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 03/24] hbitmap: improve dirty iter Vladimir Sementsov-Ogievskiy
` (22 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
A bitmap directory entry is sometimes called a 'bitmap header'. This
patch leaves only one name - 'bitmap directory entry'. The name 'bitmap
header' creates misunderstandings with 'qcow2 header' and 'qcow2 bitmap
header extension' (which is extension of qcow2 header)
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
docs/specs/qcow2.txt | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
index dda53dd..8874e8c 100644
--- a/docs/specs/qcow2.txt
+++ b/docs/specs/qcow2.txt
@@ -201,7 +201,7 @@ The fields of the bitmaps extension are:
8 - 15: bitmap_directory_size
Size of the bitmap directory in bytes. It is the cumulative
- size of all (nb_bitmaps) bitmap headers.
+ size of all (nb_bitmaps) bitmap directory entries.
16 - 23: bitmap_directory_offset
Offset into the image file at which the bitmap directory
@@ -426,8 +426,7 @@ Each bitmap saved in the image is described in a bitmap directory entry. The
bitmap directory is a contiguous area in the image file, whose starting offset
and length are given by the header extension fields bitmap_directory_offset and
bitmap_directory_size. The entries of the bitmap directory have variable
-length, depending on the lengths of the bitmap name and extra data. These
-entries are also called bitmap headers.
+length, depending on the lengths of the bitmap name and extra data.
Structure of a bitmap directory entry:
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 03/24] hbitmap: improve dirty iter
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 01/24] specs/qcow2: fix bitmap granularity qemu-specific note Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 02/24] specs/qcow2: do not use wording 'bitmap header' Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 04/24] tests: add hbitmap iter test Vladimir Sementsov-Ogievskiy
` (21 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Make dirty iter resistant to resetting bits in corresponding HBitmap.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
include/qemu/hbitmap.h | 26 ++++----------------------
util/hbitmap.c | 23 ++++++++++++++++++++++-
2 files changed, 26 insertions(+), 23 deletions(-)
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
index eb46475..2965f01 100644
--- a/include/qemu/hbitmap.h
+++ b/include/qemu/hbitmap.h
@@ -243,10 +243,9 @@ void hbitmap_free(HBitmap *hb);
* the lowest-numbered bit that is set in @hb, starting at @first.
*
* Concurrent setting of bits is acceptable, and will at worst cause the
- * iteration to miss some of those bits. Resetting bits before the current
- * position of the iterator is also okay. However, concurrent resetting of
- * bits can lead to unexpected behavior if the iterator has not yet reached
- * those bits.
+ * iteration to miss some of those bits.
+ *
+ * The concurrent resetting of bits is OK.
*/
void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
@@ -285,24 +284,7 @@ void hbitmap_free_meta(HBitmap *hb);
* Return the next bit that is set in @hbi's associated HBitmap,
* or -1 if all remaining bits are zero.
*/
-static inline int64_t hbitmap_iter_next(HBitmapIter *hbi)
-{
- unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1];
- int64_t item;
-
- if (cur == 0) {
- cur = hbitmap_iter_skip_words(hbi);
- if (cur == 0) {
- return -1;
- }
- }
-
- /* The next call will resume work from the next bit. */
- hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1);
- item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur);
-
- return item << hbi->granularity;
-}
+int64_t hbitmap_iter_next(HBitmapIter *hbi);
/**
* hbitmap_iter_next_word:
diff --git a/util/hbitmap.c b/util/hbitmap.c
index 9f691b7..1dbc8ba 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -106,8 +106,9 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi)
unsigned long cur;
do {
- cur = hbi->cur[--i];
+ i--;
pos >>= BITS_PER_LEVEL;
+ cur = hbi->cur[i] & hb->levels[i][pos];
} while (cur == 0);
/* Check for end of iteration. We always use fewer than BITS_PER_LONG
@@ -139,6 +140,26 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi)
return cur;
}
+int64_t hbitmap_iter_next(HBitmapIter *hbi)
+{
+ unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1] &
+ hbi->hb->levels[HBITMAP_LEVELS - 1][hbi->pos];
+ int64_t item;
+
+ if (cur == 0) {
+ cur = hbitmap_iter_skip_words(hbi);
+ if (cur == 0) {
+ return -1;
+ }
+ }
+
+ /* The next call will resume work from the next bit. */
+ hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1);
+ item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur);
+
+ return item << hbi->granularity;
+}
+
void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first)
{
unsigned i, bit;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 04/24] tests: add hbitmap iter test
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (2 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 03/24] hbitmap: improve dirty iter Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 05/24] block: fix bdrv_dirty_bitmap_granularity signature Vladimir Sementsov-Ogievskiy
` (20 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Test that hbitmap iter is resistant to bitmap resetting.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
tests/test-hbitmap.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
index 9b7495c..c76d2b5 100644
--- a/tests/test-hbitmap.c
+++ b/tests/test-hbitmap.c
@@ -898,6 +898,22 @@ static void hbitmap_test_add(const char *testpath,
hbitmap_test_teardown);
}
+static void test_hbitmap_iter_and_reset(TestHBitmapData *data,
+ const void *unused)
+{
+ HBitmapIter hbi;
+
+ hbitmap_test_init(data, L1 * 2, 0);
+ hbitmap_set(data->hb, 0, data->size);
+
+ hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1);
+
+ hbitmap_iter_next(&hbi);
+
+ hbitmap_reset_all(data->hb);
+ hbitmap_iter_next(&hbi);
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -955,6 +971,9 @@ int main(int argc, char **argv)
test_hbitmap_serialize_part);
hbitmap_test_add("/hbitmap/serialize/zeroes",
test_hbitmap_serialize_zeroes);
+
+ hbitmap_test_add("/hbitmap/iter/iter_and_reset",
+ test_hbitmap_iter_and_reset);
g_test_run();
return 0;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 05/24] block: fix bdrv_dirty_bitmap_granularity signature
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (3 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 04/24] tests: add hbitmap iter test Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 06/24] block/dirty-bitmap: add deserialize_ones func Vladimir Sementsov-Ogievskiy
` (19 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Make getter signature const-correct. This allows other functions with
const dirty bitmap parameter use bdrv_dirty_bitmap_granularity().
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/dirty-bitmap.c | 2 +-
include/block/dirty-bitmap.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 519737c..186941c 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -388,7 +388,7 @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
return granularity;
}
-uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
+uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
{
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
}
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 9dea14b..7cbe623 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -29,7 +29,7 @@ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
-uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
+uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap);
uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 06/24] block/dirty-bitmap: add deserialize_ones func
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (4 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 05/24] block: fix bdrv_dirty_bitmap_granularity signature Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 07/24] qcow2: add bitmaps extension Vladimir Sementsov-Ogievskiy
` (18 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Add bdrv_dirty_bitmap_deserialize_ones() function, which is needed for
qcow2 bitmap loading, to handle unallocated bitmap parts, marked as
all-ones.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
block/dirty-bitmap.c | 7 +++++++
include/block/dirty-bitmap.h | 3 +++
include/qemu/hbitmap.h | 15 +++++++++++++++
util/hbitmap.c | 17 +++++++++++++++++
4 files changed, 42 insertions(+)
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 186941c..90af372 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -499,6 +499,13 @@ void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish);
}
+void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
+ uint64_t start, uint64_t count,
+ bool finish)
+{
+ hbitmap_deserialize_ones(bitmap->bitmap, start, count, finish);
+}
+
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
{
hbitmap_deserialize_finish(bitmap->bitmap);
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 7cbe623..1e17729 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -70,6 +70,9 @@ void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
uint64_t start, uint64_t count,
bool finish);
+void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
+ uint64_t start, uint64_t count,
+ bool finish);
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
#endif
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
index 2965f01..063ec0e 100644
--- a/include/qemu/hbitmap.h
+++ b/include/qemu/hbitmap.h
@@ -216,6 +216,21 @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
bool finish);
/**
+ * hbitmap_deserialize_ones
+ * @hb: HBitmap to operate on.
+ * @start: First bit to restore.
+ * @count: Number of bits to restore.
+ * @finish: Whether to call hbitmap_deserialize_finish automatically.
+ *
+ * Fills the bitmap with ones.
+ *
+ * If @finish is false, caller must call hbitmap_serialize_finish before using
+ * the bitmap.
+ */
+void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count,
+ bool finish);
+
+/**
* hbitmap_deserialize_finish
* @hb: HBitmap to operate on.
*
diff --git a/util/hbitmap.c b/util/hbitmap.c
index 1dbc8ba..47418a9 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -535,6 +535,23 @@ void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
}
}
+void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count,
+ bool finish)
+{
+ uint64_t el_count;
+ unsigned long *first;
+
+ if (!count) {
+ return;
+ }
+ serialization_chunk(hb, start, count, &first, &el_count);
+
+ memset(first, 0xff, el_count * sizeof(unsigned long));
+ if (finish) {
+ hbitmap_deserialize_finish(hb);
+ }
+}
+
void hbitmap_deserialize_finish(HBitmap *bitmap)
{
int64_t i, size, prev_size;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 07/24] qcow2: add bitmaps extension
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (5 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 06/24] block/dirty-bitmap: add deserialize_ones func Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 08/24] block: introduce auto-loading bitmaps Vladimir Sementsov-Ogievskiy
` (17 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Add bitmap extension as specified in docs/specs/qcow2.txt.
For now, just mirror extension header into Qcow2 state and check
constraints.
For now, disable image resize if it has bitmaps. It will be fixed later.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/qcow2.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
block/qcow2.h | 24 ++++++++++++
2 files changed, 141 insertions(+), 2 deletions(-)
diff --git a/block/qcow2.c b/block/qcow2.c
index 96fb8a8..a883598 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -63,6 +63,7 @@ typedef struct {
#define QCOW2_EXT_MAGIC_END 0
#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
#define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
+#define QCOW2_EXT_MAGIC_BITMAPS 0x23852875
static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
{
@@ -92,6 +93,8 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
QCowExtension ext;
uint64_t offset;
int ret;
+ Qcow2BitmapHeaderExt bitmaps_ext;
+ bool need_update;
#ifdef DEBUG_EXT
printf("qcow2_read_extensions: start=%ld end=%ld\n", start_offset, end_offset);
@@ -162,6 +165,83 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
}
break;
+ case QCOW2_EXT_MAGIC_BITMAPS:
+ if (ext.len != sizeof(bitmaps_ext)) {
+ error_setg_errno(errp, -ret, "bitmaps_ext: "
+ "Invalid extension length");
+ return -EINVAL;
+ }
+
+ if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) {
+ fprintf(stderr,
+ "WARNING: a program lacking bitmap support modified "
+ "this file, so all bitmaps are now considered "
+ "inconsistent. Some clusters may be leaked, run "
+ "'qemu-img check -r' on the image file to fix.");
+ need_update = true;
+ break;
+ }
+
+ ret = bdrv_pread(bs->file, offset, &bitmaps_ext, ext.len);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "bitmaps_ext: "
+ "Could not read ext header");
+ return ret;
+ }
+
+ if (bitmaps_ext.reserved32 != 0) {
+ error_setg_errno(errp, -ret, "bitmaps_ext: "
+ "Reserved field is not zero");
+ return -EINVAL;
+ }
+
+ be32_to_cpus(&bitmaps_ext.nb_bitmaps);
+ be64_to_cpus(&bitmaps_ext.bitmap_directory_size);
+ be64_to_cpus(&bitmaps_ext.bitmap_directory_offset);
+
+ if (bitmaps_ext.nb_bitmaps > QCOW2_MAX_BITMAPS) {
+ error_setg(errp,
+ "bitmaps_ext: File %s has %" PRIu32 " bitmaps, "
+ "exceeding the QEMU supported maximum of %d",
+ bs->filename, bitmaps_ext.nb_bitmaps,
+ QCOW2_MAX_BITMAPS);
+ return -EINVAL;
+ }
+
+ if (bitmaps_ext.nb_bitmaps == 0) {
+ error_setg(errp, "found bitmaps extension with zero bitmaps");
+ return -EINVAL;
+ }
+
+ if (bitmaps_ext.bitmap_directory_offset & (s->cluster_size - 1)) {
+ error_setg(errp, "bitmaps_ext: "
+ "invalid bitmap directory offset");
+ return -EINVAL;
+ }
+
+ if (bitmaps_ext.bitmap_directory_size >
+ QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
+ error_setg(errp, "bitmaps_ext: "
+ "bitmap directory size (%" PRIu64 ") exceeds "
+ "the maximum supported size (%d)",
+ bitmaps_ext.bitmap_directory_size,
+ QCOW2_MAX_BITMAP_DIRECTORY_SIZE);
+ return -EINVAL;
+ }
+
+ s->nb_bitmaps = bitmaps_ext.nb_bitmaps;
+ s->bitmap_directory_offset =
+ bitmaps_ext.bitmap_directory_offset;
+ s->bitmap_directory_size =
+ bitmaps_ext.bitmap_directory_size;
+
+#ifdef DEBUG_EXT
+ printf("Qcow2: Got bitmaps extension: "
+ "offset=%" PRIu64 " nb_bitmaps=%" PRIu32 "\n",
+ s->bitmap_directory_offset, s->nb_bitmaps);
+#endif
+ break;
+
default:
/* unknown magic - save it in case we need to rewrite the header */
{
@@ -185,6 +265,15 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
offset += ((ext.len + 7) & ~7);
}
+ if (need_update && !bdrv_is_root_node(bs) &&
+ !(bdrv_get_flags(bs) & BDRV_O_INACTIVE))
+ {
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
return 0;
}
@@ -1152,8 +1241,9 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
}
/* Clear unknown autoclear feature bits */
- if (!bs->read_only && !(flags & BDRV_O_INACTIVE) && s->autoclear_features) {
- s->autoclear_features = 0;
+ if (!bs->read_only && !(flags & BDRV_O_INACTIVE) &&
+ (s->autoclear_features & ~QCOW2_AUTOCLEAR_MASK)) {
+ s->autoclear_features &= QCOW2_AUTOCLEAR_MASK;
ret = qcow2_update_header(bs);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not update qcow2 header");
@@ -1953,6 +2043,24 @@ int qcow2_update_header(BlockDriverState *bs)
buflen -= ret;
}
+ if (s->nb_bitmaps > 0) {
+ Qcow2BitmapHeaderExt bitmaps_header = {
+ .nb_bitmaps = cpu_to_be32(s->nb_bitmaps),
+ .bitmap_directory_size =
+ cpu_to_be64(s->bitmap_directory_size),
+ .bitmap_directory_offset =
+ cpu_to_be64(s->bitmap_directory_offset)
+ };
+ ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BITMAPS,
+ &bitmaps_header, sizeof(bitmaps_header),
+ buflen);
+ if (ret < 0) {
+ goto fail;
+ }
+ buf += ret;
+ buflen -= ret;
+ }
+
/* Keep unknown header extensions */
QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
@@ -2528,6 +2636,13 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
return -ENOTSUP;
}
+ /* cannot proceed if image has bitmaps */
+ if (s->nb_bitmaps) {
+ /* TODO: resize bitmaps in the image */
+ error_report("Can't resize an image which has bitmaps");
+ return -ENOTSUP;
+ }
+
/* shrinking is currently not supported */
if (offset < bs->total_sectors * 512) {
error_report("qcow2 doesn't support shrinking images yet");
diff --git a/block/qcow2.h b/block/qcow2.h
index 1823414..861b501 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -52,6 +52,10 @@
* space for snapshot names and IDs */
#define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS)
+/* Bitmap header extension constraints */
+#define QCOW2_MAX_BITMAPS 65535
+#define QCOW2_MAX_BITMAP_DIRECTORY_SIZE (1024 * QCOW2_MAX_BITMAPS)
+
/* indicate that the refcount of the referenced cluster is exactly one. */
#define QCOW_OFLAG_COPIED (1ULL << 63)
/* indicate that the cluster is compressed (they never have the copied flag) */
@@ -195,6 +199,15 @@ enum {
QCOW2_COMPAT_FEAT_MASK = QCOW2_COMPAT_LAZY_REFCOUNTS,
};
+/* Autoclear feature bits */
+enum {
+ QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0,
+ QCOW2_AUTOCLEAR_BITMAPS =
+ 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR,
+
+ QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS,
+};
+
enum qcow2_discard_type {
QCOW2_DISCARD_NEVER = 0,
QCOW2_DISCARD_ALWAYS,
@@ -222,6 +235,13 @@ typedef uint64_t Qcow2GetRefcountFunc(const void *refcount_array,
typedef void Qcow2SetRefcountFunc(void *refcount_array,
uint64_t index, uint64_t value);
+typedef struct Qcow2BitmapHeaderExt {
+ uint32_t nb_bitmaps;
+ uint32_t reserved32;
+ uint64_t bitmap_directory_size;
+ uint64_t bitmap_directory_offset;
+} QEMU_PACKED Qcow2BitmapHeaderExt;
+
typedef struct BDRVQcow2State {
int cluster_bits;
int cluster_size;
@@ -263,6 +283,10 @@ typedef struct BDRVQcow2State {
unsigned int nb_snapshots;
QCowSnapshot *snapshots;
+ uint32_t nb_bitmaps;
+ uint64_t bitmap_directory_size;
+ uint64_t bitmap_directory_offset;
+
int flags;
int qcow_version;
bool use_lazy_refcounts;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 08/24] block: introduce auto-loading bitmaps
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (6 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 07/24] qcow2: add bitmaps extension Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 09/24] qcow2: add .bdrv_load_autoloading_dirty_bitmaps Vladimir Sementsov-Ogievskiy
` (16 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Auto loading bitmaps are bitmaps stored in the disk image, which should
be loaded when the image is opened and become BdrvDirtyBitmaps for the
corresponding drive.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
block.c | 14 ++++++++++++++
include/block/block.h | 2 ++
include/block/block_int.h | 3 +++
3 files changed, 19 insertions(+)
diff --git a/block.c b/block.c
index 39ddea3..1095176 100644
--- a/block.c
+++ b/block.c
@@ -1141,6 +1141,13 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
assert(bdrv_min_mem_align(bs) != 0);
assert(is_power_of_2(bs->bl.request_alignment));
+ bdrv_load_autoloading_dirty_bitmaps(bs, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto free_and_fail;
+ }
+
qemu_opts_del(opts);
return 0;
@@ -4093,3 +4100,10 @@ void bdrv_del_child(BlockDriverState *parent_bs, BdrvChild *child, Error **errp)
parent_bs->drv->bdrv_del_child(parent_bs, child, errp);
}
+
+void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
+{
+ if (bs->drv && bs->drv->bdrv_load_autoloading_dirty_bitmaps) {
+ bs->drv->bdrv_load_autoloading_dirty_bitmaps(bs, errp);
+ }
+}
diff --git a/include/block/block.h b/include/block/block.h
index 49bb0b2..f701da2 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -552,4 +552,6 @@ void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
Error **errp);
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
+void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+
#endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 83a423c..ca955f0 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -320,6 +320,9 @@ struct BlockDriver {
void (*bdrv_del_child)(BlockDriverState *parent, BdrvChild *child,
Error **errp);
+ void (*bdrv_load_autoloading_dirty_bitmaps)(BlockDriverState *bs,
+ Error **errp);
+
QLIST_ENTRY(BlockDriver) list;
};
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 09/24] qcow2: add .bdrv_load_autoloading_dirty_bitmaps
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (7 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 08/24] block: introduce auto-loading bitmaps Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 10/24] block/dirty-bitmap: add autoload field to BdrvDirtyBitmap Vladimir Sementsov-Ogievskiy
` (15 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Auto loading bitmaps are bitmaps in Qcow2, with the AUTO flag set. They
are loaded when the image is opened and become BdrvDirtyBitmaps for the
corresponding drive.
Extra data in bitmaps is not supported for now.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/Makefile.objs | 2 +-
block/qcow2-bitmap.c | 712 +++++++++++++++++++++++++++++++++++++++++++++++++++
block/qcow2.c | 2 +
block/qcow2.h | 3 +
4 files changed, 718 insertions(+), 1 deletion(-)
create mode 100644 block/qcow2-bitmap.c
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 67a036a..b8b6cf3 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -1,5 +1,5 @@
block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
-block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
+block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
new file mode 100644
index 0000000..758622d
--- /dev/null
+++ b/block/qcow2-bitmap.c
@@ -0,0 +1,712 @@
+/*
+ * Bitmaps for the QCOW version 2 format
+ *
+ * Copyright (c) 2014-2016 Vladimir Sementsov-Ogievskiy
+ *
+ * This file is derived from qcow2-snapshot.c, original copyright:
+ * Copyright (c) 2004-2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "exec/log.h"
+
+#include "block/block_int.h"
+#include "block/qcow2.h"
+
+/* NOTICE: BME here means Bitmaps Extension and used as a namespace for
+ * _internal_ constants. Please do not use this _internal_ abbreviation for
+ * other needs and/or outside of this file. */
+
+/* Bitmap directory entry constraints */
+#define BME_MAX_TABLE_SIZE 0x8000000
+#define BME_MAX_PHYS_SIZE 0x20000000 /* restrict BdrvDirtyBitmap size in RAM */
+#define BME_MAX_GRANULARITY_BITS 31
+#define BME_MIN_GRANULARITY_BITS 9
+#define BME_MAX_NAME_SIZE 1023
+
+/* Bitmap directory entry flags */
+#define BME_RESERVED_FLAGS 0xfffffffcU
+#define BME_FLAG_IN_USE 1
+#define BME_FLAG_AUTO (1U << 1)
+
+/* bits [1, 8] U [56, 63] are reserved */
+#define BME_TABLE_ENTRY_RESERVED_MASK 0xff000000000001feULL
+#define BME_TABLE_ENTRY_OFFSET_MASK 0x00fffffffffffe00ULL
+
+typedef struct QEMU_PACKED Qcow2BitmapDirEntry {
+ /* header is 8 byte aligned */
+ uint64_t bitmap_table_offset;
+
+ uint32_t bitmap_table_size;
+ uint32_t flags;
+
+ uint8_t type;
+ uint8_t granularity_bits;
+ uint16_t name_size;
+ uint32_t extra_data_size;
+ /* extra data follows */
+ /* name follows */
+} Qcow2BitmapDirEntry;
+
+typedef struct Qcow2Bitmap {
+ uint64_t table_offset;
+ uint32_t table_size;
+ uint32_t flags;
+ uint8_t granularity_bits;
+ char *name;
+
+ QSIMPLEQ_ENTRY(Qcow2Bitmap) entry;
+} Qcow2Bitmap;
+typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList;
+
+typedef enum BitmapType {
+ BT_DIRTY_TRACKING_BITMAP = 1
+} BitmapType;
+
+static inline bool can_write(BlockDriverState *bs)
+{
+ return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
+}
+
+static inline void bitmap_table_to_cpu(uint64_t *bitmap_table, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; ++i) {
+ be64_to_cpus(&bitmap_table[i]);
+ }
+}
+
+static int check_table_entry(uint64_t entry, int cluster_size)
+{
+ uint64_t offset;
+
+ if (cluster_size <= 0) {
+ return -EINVAL;
+ }
+
+ if (entry & BME_TABLE_ENTRY_RESERVED_MASK) {
+ return -EINVAL;
+ }
+
+ offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
+ if (offset != 0) {
+ /* if offset specified, bit 0 is reserved */
+ if (entry & 1) {
+ return -EINVAL;
+ }
+
+ if (offset % cluster_size != 0) {
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int bitmap_table_load(BlockDriverState *bs, Qcow2Bitmap *bm,
+ uint64_t **bitmap_table)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ uint32_t i;
+ uint64_t *table;
+
+ assert(bm->table_size != 0);
+ table = g_try_new(uint64_t, bm->table_size);
+ if (table == NULL) {
+ return -ENOMEM;
+ }
+
+ assert(bm->table_size <= BME_MAX_TABLE_SIZE);
+ ret = bdrv_pread(bs->file, bm->table_offset,
+ table, bm->table_size * sizeof(uint64_t));
+ if (ret < 0) {
+ goto fail;
+ }
+
+ for (i = 0; i < bm->table_size; ++i) {
+ be64_to_cpus(&table[i]);
+ ret = check_table_entry(table[i], s->cluster_size);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
+ *bitmap_table = table;
+ return 0;
+
+fail:
+ g_free(table);
+
+ return ret;
+}
+
+/* This function returns the number of disk sectors covered by a single cluster
+ * of bitmap data. */
+static uint64_t disk_sectors_in_bitmap_cluster(const BDRVQcow2State *s,
+ const BdrvDirtyBitmap *bitmap)
+{
+ uint32_t sector_granularity =
+ bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
+
+ return (uint64_t)sector_granularity * (s->cluster_size << 3);
+}
+
+/* bitmap table entries must satisfy specification constraints */
+static int load_bitmap_data(BlockDriverState *bs,
+ const uint64_t *bitmap_table,
+ uint32_t bitmap_table_size,
+ BdrvDirtyBitmap *bitmap)
+{
+ int ret = 0;
+ BDRVQcow2State *s = bs->opaque;
+ uint64_t sector, dsc;
+ uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
+ uint8_t *buf = NULL;
+ uint64_t i, tab_size =
+ size_to_clusters(s,
+ bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
+
+ if (tab_size != bitmap_table_size || tab_size > BME_MAX_TABLE_SIZE) {
+ return -EINVAL;
+ }
+
+ bdrv_clear_dirty_bitmap(bitmap, NULL);
+
+ buf = g_malloc(s->cluster_size);
+ dsc = disk_sectors_in_bitmap_cluster(s, bitmap);
+ for (i = 0, sector = 0; i < tab_size; ++i, sector += dsc) {
+ uint64_t count = MIN(bm_size - sector, dsc);
+ uint64_t entry = bitmap_table[i];
+ uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
+
+ assert(check_table_entry(entry, s->cluster_size) == 0);
+
+ if (offset == 0) {
+ if (entry & 1) {
+ bdrv_dirty_bitmap_deserialize_ones(bitmap, sector, count,
+ false);
+ } else {
+ /* No need to deserialize zeros because the dirty bitmap is
+ * already cleared */
+ }
+ } else {
+ ret = bdrv_pread(bs->file, offset, buf, s->cluster_size);
+ if (ret < 0) {
+ goto finish;
+ }
+ bdrv_dirty_bitmap_deserialize_part(bitmap, buf, sector, count,
+ false);
+ }
+ }
+ ret = 0;
+
+ bdrv_dirty_bitmap_deserialize_finish(bitmap);
+
+finish:
+ g_free(buf);
+
+ return ret;
+}
+
+static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
+ Qcow2Bitmap *bm, Error **errp)
+{
+ int ret;
+ uint64_t *bitmap_table = NULL;
+ uint32_t granularity;
+ BdrvDirtyBitmap *bitmap = NULL;
+
+ if (bm->flags & BME_FLAG_IN_USE) {
+ error_setg(errp, "Bitmap '%s' is in use", bm->name);
+ goto fail;
+ }
+
+ ret = bitmap_table_load(bs, bm, &bitmap_table);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Could not read bitmap_table table from image for "
+ "bitmap '%s'", bm->name);
+ goto fail;
+ }
+
+ granularity = 1U << bm->granularity_bits;
+ bitmap = bdrv_create_dirty_bitmap(bs, granularity, bm->name, errp);
+ if (bitmap == NULL) {
+ goto fail;
+ }
+
+ ret = load_bitmap_data(bs, bitmap_table, bm->table_size,
+ bitmap);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not read bitmap '%s' from image",
+ bm->name);
+ goto fail;
+ }
+
+ g_free(bitmap_table);
+ return bitmap;
+
+fail:
+ g_free(bitmap_table);
+ if (bitmap != NULL) {
+ bdrv_release_dirty_bitmap(bs, bitmap);
+ }
+
+ return NULL;
+}
+
+/*
+ * Bitmap List
+ */
+
+/*
+ * Bitmap List private functions
+ * Only Bitmap List knows about bitmap directory structure in Qcow2.
+ */
+
+static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry)
+{
+ be64_to_cpus(&entry->bitmap_table_offset);
+ be32_to_cpus(&entry->bitmap_table_size);
+ be32_to_cpus(&entry->flags);
+ be16_to_cpus(&entry->name_size);
+ be32_to_cpus(&entry->extra_data_size);
+}
+
+static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry)
+{
+ cpu_to_be64s(&entry->bitmap_table_offset);
+ cpu_to_be32s(&entry->bitmap_table_size);
+ cpu_to_be32s(&entry->flags);
+ cpu_to_be16s(&entry->name_size);
+ cpu_to_be32s(&entry->extra_data_size);
+}
+
+static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size)
+{
+ return align_offset(sizeof(Qcow2BitmapDirEntry) +
+ name_size + extra_data_size, 8);
+}
+
+static inline int dir_entry_size(Qcow2BitmapDirEntry *entry)
+{
+ return calc_dir_entry_size(entry->name_size, entry->extra_data_size);
+}
+
+static inline const char *dir_entry_name_field(Qcow2BitmapDirEntry *entry)
+{
+ return (const char *)(entry + 1) + entry->extra_data_size;
+}
+
+static inline char *dir_entry_copy_name(Qcow2BitmapDirEntry *entry)
+{
+ const char *name_field = dir_entry_name_field(entry);
+ return g_strndup(name_field, entry->name_size);
+}
+
+static inline Qcow2BitmapDirEntry *next_dir_entry(Qcow2BitmapDirEntry *entry)
+{
+ return (Qcow2BitmapDirEntry *)((uint8_t *)entry + dir_entry_size(entry));
+}
+
+static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry)
+{
+ BDRVQcow2State *s = bs->opaque;
+ uint64_t phys_bitmap_bytes;
+ int64_t len;
+
+ bool fail = (entry->bitmap_table_size == 0) ||
+ (entry->bitmap_table_offset == 0) ||
+ (entry->bitmap_table_offset % s->cluster_size) ||
+ (entry->bitmap_table_size > BME_MAX_TABLE_SIZE) ||
+ (entry->granularity_bits > BME_MAX_GRANULARITY_BITS) ||
+ (entry->granularity_bits < BME_MIN_GRANULARITY_BITS) ||
+ (entry->flags & BME_RESERVED_FLAGS) ||
+ (entry->name_size > BME_MAX_NAME_SIZE) ||
+ (entry->type != BT_DIRTY_TRACKING_BITMAP);
+
+ if (fail) {
+ return -EINVAL;
+ }
+
+ phys_bitmap_bytes = (uint64_t)entry->bitmap_table_size * s->cluster_size;
+ len = bdrv_getlength(bs);
+
+ if (len < 0) {
+ return len;
+ }
+
+ fail = (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) ||
+ (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits));
+
+ return fail ? -EINVAL : 0;
+}
+
+static inline void bitmap_directory_to_be(uint8_t *dir, size_t size)
+{
+ uint8_t *end = dir + size;
+ while (dir < end) {
+ Qcow2BitmapDirEntry *e = (Qcow2BitmapDirEntry *)dir;
+ dir += dir_entry_size(e);
+
+ bitmap_dir_entry_to_be(e);
+ }
+}
+
+/*
+ * Bitmap List public functions
+ */
+
+static void bitmap_free(Qcow2Bitmap *bm)
+{
+ g_free(bm->name);
+ g_free(bm);
+}
+
+static void bitmap_list_free(Qcow2BitmapList *bm_list)
+{
+ Qcow2Bitmap *bm;
+
+ if (bm_list == NULL) {
+ return;
+ }
+
+ while ((bm = QSIMPLEQ_FIRST(bm_list)) != NULL) {
+ QSIMPLEQ_REMOVE_HEAD(bm_list, entry);
+ bitmap_free(bm);
+ }
+
+ g_free(bm_list);
+}
+
+static Qcow2BitmapList *bitmap_list_new(void)
+{
+ Qcow2BitmapList *bm_list = g_new(Qcow2BitmapList, 1);
+ QSIMPLEQ_INIT(bm_list);
+
+ return bm_list;
+}
+
+static uint32_t bitmap_list_count(Qcow2BitmapList *bm_list)
+{
+ Qcow2Bitmap *bm;
+ uint32_t nb_bitmaps = 0;
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ nb_bitmaps++;
+ }
+
+ return nb_bitmaps;
+}
+
+/* bitmap_list_load
+ * Get bitmap list from qcow2 image. Actually reads bitmap directory,
+ * checks it and convert to bitmap list.
+ */
+static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
+ uint64_t size, Error **errp)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ uint8_t *dir, *dir_end;
+ Qcow2BitmapDirEntry *e;
+ uint32_t nb_dir_entries = 0;
+ Qcow2BitmapList *bm_list = NULL;
+
+ if (size == 0) {
+ error_setg(errp, "Requested bitmap directory size is zero");
+ return NULL;
+ }
+
+ if (size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
+ error_setg(errp, "Requested bitmap directory size is too big");
+ return NULL;
+ }
+
+ dir = g_try_malloc(size);
+ if (dir == NULL) {
+ error_setg(errp, "Failed to allocate space for bitmap directory");
+ return NULL;
+ }
+ dir_end = dir + size;
+
+ ret = bdrv_pread(bs->file, offset, dir, size);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to read bitmap directory");
+ goto fail;
+ }
+
+ bm_list = bitmap_list_new();
+ for (e = (Qcow2BitmapDirEntry *)dir;
+ e < (Qcow2BitmapDirEntry *)dir_end;
+ e = next_dir_entry(e))
+ {
+ Qcow2Bitmap *bm;
+
+ if ((uint8_t *)(e + 1) > dir_end) {
+ goto broken_dir;
+ }
+
+ if (++nb_dir_entries > s->nb_bitmaps) {
+ error_setg(errp, "More bitmaps found than specified in header"
+ " extension");
+ goto fail;
+ }
+ bitmap_dir_entry_to_cpu(e);
+
+ if ((uint8_t *)next_dir_entry(e) > dir_end) {
+ goto broken_dir;
+ }
+
+ if (e->extra_data_size != 0) {
+ error_setg(errp, "Bitmap extra data is not supported");
+ goto fail;
+ }
+
+ ret = check_dir_entry(bs, e);
+ if (ret < 0) {
+ error_setg(errp, "Bitmap '%.*s' doesn't satisfy the constraints",
+ e->name_size, dir_entry_name_field(e));
+ goto fail;
+ }
+
+ bm = g_new(Qcow2Bitmap, 1);
+ bm->table_offset = e->bitmap_table_offset;
+ bm->table_size = e->bitmap_table_size;
+ bm->flags = e->flags;
+ bm->granularity_bits = e->granularity_bits;
+ bm->name = dir_entry_copy_name(e);
+ QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry);
+ }
+
+ if (nb_dir_entries != s->nb_bitmaps) {
+ error_setg(errp, "Less bitmaps found than specified in header"
+ " extension");
+ goto fail;
+ }
+
+ if ((uint8_t *)e != dir_end) {
+ goto broken_dir;
+ }
+
+ g_free(dir);
+ return bm_list;
+
+broken_dir:
+ ret = -EINVAL;
+ error_setg(errp, "Broken bitmap directory");
+
+fail:
+ g_free(dir);
+ bitmap_list_free(bm_list);
+
+ return NULL;
+}
+
+/* bitmap_list_store
+ * Store bitmap list to qcow2 image as a bitmap directory.
+ * Everything is checked.
+ */
+static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
+ uint64_t *offset, uint64_t *size, bool in_place)
+{
+ int ret;
+ uint8_t *dir;
+ int64_t dir_offset = 0;
+ uint64_t dir_size = 0;
+ Qcow2Bitmap *bm;
+ Qcow2BitmapDirEntry *e;
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ dir_size += calc_dir_entry_size(strlen(bm->name), 0);
+ }
+
+ if (dir_size == 0 || dir_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
+ return -EINVAL;
+ }
+
+ if (in_place) {
+ if (*size != dir_size || *offset == 0) {
+ return -EINVAL;
+ }
+
+ dir_offset = *offset;
+ }
+
+ dir = g_try_malloc(dir_size);
+ if (dir == NULL) {
+ return -ENOMEM;
+ }
+
+ e = (Qcow2BitmapDirEntry *)dir;
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ e->bitmap_table_offset = bm->table_offset;
+ e->bitmap_table_size = bm->table_size;
+ e->flags = bm->flags;
+ e->type = BT_DIRTY_TRACKING_BITMAP;
+ e->granularity_bits = bm->granularity_bits;
+ e->name_size = strlen(bm->name);
+ e->extra_data_size = 0;
+ memcpy(e + 1, bm->name, e->name_size);
+
+ if (check_dir_entry(bs, e) < 0) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ e = next_dir_entry(e);
+ }
+
+ bitmap_directory_to_be(dir, dir_size);
+
+ if (!in_place) {
+ dir_offset = qcow2_alloc_clusters(bs, dir_size);
+ if (dir_offset < 0) {
+ ret = dir_offset;
+ goto fail;
+ }
+ }
+
+ ret = qcow2_pre_write_overlap_check(bs, 0, dir_offset, dir_size);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ ret = bdrv_pwrite(bs->file, dir_offset, dir, dir_size);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ g_free(dir);
+
+ if (!in_place) {
+ *size = dir_size;
+ *offset = dir_offset;
+ }
+
+ return 0;
+
+fail:
+ g_free(dir);
+
+ if (!in_place && dir_offset > 0) {
+ qcow2_free_clusters(bs, dir_offset, dir_size, QCOW2_DISCARD_OTHER);
+ }
+
+ return ret;
+}
+
+/*
+ * Bitmap List end
+ */
+
+static int update_ext_header_and_dir_in_place(BlockDriverState *bs,
+ Qcow2BitmapList *bm_list)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int ret;
+
+ if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS) ||
+ bm_list == NULL || QSIMPLEQ_EMPTY(bm_list) ||
+ bitmap_list_count(bm_list) != s->nb_bitmaps)
+ {
+ return -EINVAL;
+ }
+
+ s->autoclear_features &= ~(uint64_t)QCOW2_AUTOCLEAR_BITMAPS;
+ ret = update_header_sync(bs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* autoclear bit is not set, so we can safely update bitmap directory */
+
+ ret = bitmap_list_store(bs, bm_list, &s->bitmap_directory_offset,
+ &s->bitmap_directory_size, true);
+ if (ret < 0) {
+ /* autoclear bit is cleared, so all leaked clusters would be removed on
+ * qemu-img check */
+ return ret;
+ }
+
+ s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS;
+ return update_header_sync(bs);
+}
+
+/* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */
+static void release_dirty_bitmap_helper(gpointer bitmap,
+ gpointer bs)
+{
+ bdrv_release_dirty_bitmap(bs, bitmap);
+}
+
+void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+ GSList *created_dirty_bitmaps = NULL;
+
+ if (s->nb_bitmaps == 0) {
+ /* No bitmaps - nothing to do */
+ return;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return;
+ }
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if ((bm->flags & BME_FLAG_AUTO) && !(bm->flags & BME_FLAG_IN_USE)) {
+ BdrvDirtyBitmap *bitmap = load_bitmap(bs, bm, errp);
+ if (bitmap == NULL) {
+ goto fail;
+ }
+ bm->flags |= BME_FLAG_IN_USE;
+ created_dirty_bitmaps =
+ g_slist_append(created_dirty_bitmaps, bitmap);
+ }
+ }
+
+ if (created_dirty_bitmaps != NULL && can_write(bs)) {
+ /* in_use flags must be updated */
+ int ret = update_ext_header_and_dir_in_place(bs, bm_list);
+ if (ret < 0) {
+ error_setg(errp, "Can't update bitmap directory");
+ goto fail;
+ }
+ }
+
+ g_slist_free(created_dirty_bitmaps);
+ bitmap_list_free(bm_list);
+
+ return;
+
+fail:
+ g_slist_foreach(created_dirty_bitmaps, release_dirty_bitmap_helper, bs);
+ g_slist_free(created_dirty_bitmaps);
+ bitmap_list_free(bm_list);
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index a883598..9f64753 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3540,6 +3540,8 @@ BlockDriver bdrv_qcow2 = {
.bdrv_detach_aio_context = qcow2_detach_aio_context,
.bdrv_attach_aio_context = qcow2_attach_aio_context,
+
+ .bdrv_load_autoloading_dirty_bitmaps = qcow2_load_autoloading_dirty_bitmaps,
};
static void bdrv_qcow2_init(void)
diff --git a/block/qcow2.h b/block/qcow2.h
index 861b501..bcedf5b 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -613,4 +613,7 @@ int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table);
void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
+/* qcow2-bitmap.c functions */
+void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 10/24] block/dirty-bitmap: add autoload field to BdrvDirtyBitmap
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (8 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 09/24] qcow2: add .bdrv_load_autoloading_dirty_bitmaps Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 11/24] block: introduce persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (14 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Mirror AUTO flag from Qcow2 bitmap in BdrvDirtyBitmap. This will be
needed in future, to save this flag back to Qcow2 for persistent
bitmaps.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
block/dirty-bitmap.c | 16 ++++++++++++++++
block/qcow2-bitmap.c | 2 ++
include/block/dirty-bitmap.h | 2 ++
3 files changed, 20 insertions(+)
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 90af372..2d27494 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -44,6 +44,8 @@ struct BdrvDirtyBitmap {
int64_t size; /* Size of the bitmap (Number of sectors) */
bool disabled; /* Bitmap is read-only */
int active_iterators; /* How many iterators are active */
+ bool autoload; /* For persistent bitmaps: bitmap must be
+ autoloaded on image opening */
QLIST_ENTRY(BdrvDirtyBitmap) list;
};
@@ -70,6 +72,8 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
assert(!bdrv_dirty_bitmap_frozen(bitmap));
g_free(bitmap->name);
bitmap->name = NULL;
+
+ bitmap->autoload = false;
}
BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
@@ -238,6 +242,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
bitmap->name = NULL;
successor->name = name;
bitmap->successor = NULL;
+ successor->autoload = bitmap->autoload;
+ bitmap->autoload = false;
bdrv_release_dirty_bitmap(bs, bitmap);
return successor;
@@ -540,3 +546,13 @@ int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
{
return hbitmap_count(bitmap->meta);
}
+
+void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload)
+{
+ bitmap->autoload = autoload;
+}
+
+bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->autoload;
+}
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 758622d..277e678 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -685,6 +685,8 @@ void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
if (bitmap == NULL) {
goto fail;
}
+
+ bdrv_dirty_bitmap_set_autoload(bitmap, true);
bm->flags |= BME_FLAG_IN_USE;
created_dirty_bitmaps =
g_slist_append(created_dirty_bitmaps, bitmap);
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 1e17729..45a389a 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -75,4 +75,6 @@ void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
bool finish);
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
+void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
+bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 11/24] block: introduce persistent dirty bitmaps
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (9 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 10/24] block/dirty-bitmap: add autoload field to BdrvDirtyBitmap Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 12/24] block/dirty-bitmap: add bdrv_dirty_bitmap_next() Vladimir Sementsov-Ogievskiy
` (13 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
New field BdrvDirtyBitmap.persistent means, that bitmap should be saved
on bdrv_close, using format driver. Format driver should maintain bitmap
storing.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
block.c | 32 ++++++++++++++++++++++++++++++++
block/dirty-bitmap.c | 26 ++++++++++++++++++++++++++
block/qcow2-bitmap.c | 1 +
include/block/block.h | 1 +
include/block/block_int.h | 2 ++
include/block/dirty-bitmap.h | 6 ++++++
6 files changed, 68 insertions(+)
diff --git a/block.c b/block.c
index 1095176..646ea50 100644
--- a/block.c
+++ b/block.c
@@ -2321,6 +2321,7 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
static void bdrv_close(BlockDriverState *bs)
{
BdrvAioNotifier *ban, *ban_next;
+ Error *local_err = NULL;
assert(!bs->job);
assert(!bs->refcnt);
@@ -2329,6 +2330,12 @@ static void bdrv_close(BlockDriverState *bs)
bdrv_flush(bs);
bdrv_drain(bs); /* in case flush left pending I/O */
+ bdrv_store_persistent_dirty_bitmaps(bs, &local_err);
+ if (local_err != NULL) {
+ error_report_err(local_err);
+ error_report("Persistent bitmaps are lost for node '%s'",
+ bdrv_get_device_or_node_name(bs));
+ }
bdrv_release_named_dirty_bitmaps(bs);
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
@@ -4107,3 +4114,28 @@ void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
bs->drv->bdrv_load_autoloading_dirty_bitmaps(bs, errp);
}
}
+
+void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!bdrv_has_persistent_bitmaps(bs)) {
+ return;
+ }
+
+ if (!drv) {
+ error_setg_errno(errp, ENOMEDIUM,
+ "Can't store persistent bitmaps to %s",
+ bdrv_get_device_or_node_name(bs));
+ return;
+ }
+
+ if (!drv->bdrv_store_persistent_dirty_bitmaps) {
+ error_setg_errno(errp, ENOTSUP,
+ "Can't store persistent bitmaps to %s",
+ bdrv_get_device_or_node_name(bs));
+ return;
+ }
+
+ drv->bdrv_store_persistent_dirty_bitmaps(bs, errp);
+}
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 2d27494..4d026df 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -44,6 +44,7 @@ struct BdrvDirtyBitmap {
int64_t size; /* Size of the bitmap (Number of sectors) */
bool disabled; /* Bitmap is read-only */
int active_iterators; /* How many iterators are active */
+ bool persistent; /* bitmap must be saved to owner disk image */
bool autoload; /* For persistent bitmaps: bitmap must be
autoloaded on image opening */
QLIST_ENTRY(BdrvDirtyBitmap) list;
@@ -73,6 +74,7 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
g_free(bitmap->name);
bitmap->name = NULL;
+ bitmap->persistent = false;
bitmap->autoload = false;
}
@@ -242,6 +244,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
bitmap->name = NULL;
successor->name = name;
bitmap->successor = NULL;
+ successor->persistent = bitmap->persistent;
+ bitmap->persistent = false;
successor->autoload = bitmap->autoload;
bitmap->autoload = false;
bdrv_release_dirty_bitmap(bs, bitmap);
@@ -556,3 +560,25 @@ bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
{
return bitmap->autoload;
}
+
+void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
+{
+ bitmap->persistent = persistent;
+}
+
+bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
+{
+ return bitmap->persistent;
+}
+
+bool bdrv_has_persistent_bitmaps(BlockDriverState *bs)
+{
+ BdrvDirtyBitmap *bm;
+ QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
+ if (bm->persistent) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 277e678..3e8fd03 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -686,6 +686,7 @@ void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
goto fail;
}
+ bdrv_dirty_bitmap_set_persistance(bitmap, true);
bdrv_dirty_bitmap_set_autoload(bitmap, true);
bm->flags |= BME_FLAG_IN_USE;
created_dirty_bitmaps =
diff --git a/include/block/block.h b/include/block/block.h
index f701da2..e3175b5 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -553,5 +553,6 @@ void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
#endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index ca955f0..e8d9210 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -322,6 +322,8 @@ struct BlockDriver {
void (*bdrv_load_autoloading_dirty_bitmaps)(BlockDriverState *bs,
Error **errp);
+ void (*bdrv_store_persistent_dirty_bitmaps)(BlockDriverState *bs,
+ Error **errp);
QLIST_ENTRY(BlockDriver) list;
};
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 45a389a..8dbd16b 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -77,4 +77,10 @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
+void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
+ bool persistent);
+bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
+
+bool bdrv_has_persistent_bitmaps(BlockDriverState *bs);
+
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 12/24] block/dirty-bitmap: add bdrv_dirty_bitmap_next()
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (10 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 11/24] block: introduce persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 13/24] qcow2: add .bdrv_store_persistent_dirty_bitmaps() Vladimir Sementsov-Ogievskiy
` (12 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
block/dirty-bitmap.c | 7 +++++++
include/block/dirty-bitmap.h | 3 +++
2 files changed, 10 insertions(+)
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 4d026df..fe34d48 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -582,3 +582,10 @@ bool bdrv_has_persistent_bitmaps(BlockDriverState *bs)
return false;
}
+
+BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
+ BdrvDirtyBitmap *bitmap)
+{
+ return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) :
+ QLIST_NEXT(bitmap, list);
+}
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 8dbd16b..d71edc4 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -81,6 +81,9 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
bool persistent);
bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
+BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
+ BdrvDirtyBitmap *bitmap);
+
bool bdrv_has_persistent_bitmaps(BlockDriverState *bs);
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 13/24] qcow2: add .bdrv_store_persistent_dirty_bitmaps()
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (11 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 12/24] block/dirty-bitmap: add bdrv_dirty_bitmap_next() Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 14/24] block: add bdrv_can_store_new_dirty_bitmap Vladimir Sementsov-Ogievskiy
` (11 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Realize block bitmap storing interface, to allow qcow2 images store
persistent bitmaps.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/qcow2-bitmap.c | 509 +++++++++++++++++++++++++++++++++++++++++++++++++--
block/qcow2.c | 1 +
block/qcow2.h | 1 +
3 files changed, 496 insertions(+), 15 deletions(-)
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 3e8fd03..a2b857e 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -28,6 +28,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "exec/log.h"
+#include "qemu/cutils.h"
#include "block/block_int.h"
#include "block/qcow2.h"
@@ -43,6 +44,10 @@
#define BME_MIN_GRANULARITY_BITS 9
#define BME_MAX_NAME_SIZE 1023
+#if BME_MAX_TABLE_SIZE * 8ULL > INT_MAX
+#error In the code bitmap table physical size assumed to fit into int
+#endif
+
/* Bitmap directory entry flags */
#define BME_RESERVED_FLAGS 0xfffffffcU
#define BME_FLAG_IN_USE 1
@@ -67,13 +72,21 @@ typedef struct QEMU_PACKED Qcow2BitmapDirEntry {
/* name follows */
} Qcow2BitmapDirEntry;
+typedef struct Qcow2BitmapTable {
+ uint64_t offset;
+ uint32_t size; /* number of 64bit entries */
+ QSIMPLEQ_ENTRY(Qcow2BitmapTable) entry;
+} Qcow2BitmapTable;
+typedef QSIMPLEQ_HEAD(Qcow2BitmapTableList, Qcow2BitmapTable) Qcow2BitmapTableList;
+
typedef struct Qcow2Bitmap {
- uint64_t table_offset;
- uint32_t table_size;
+ Qcow2BitmapTable table;
uint32_t flags;
uint8_t granularity_bits;
char *name;
+ BdrvDirtyBitmap *dirty_bitmap;
+
QSIMPLEQ_ENTRY(Qcow2Bitmap) entry;
} Qcow2Bitmap;
typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList;
@@ -87,6 +100,27 @@ static inline bool can_write(BlockDriverState *bs)
return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
}
+static int update_header_sync(BlockDriverState *bs)
+{
+ int ret;
+
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* We don't return bdrv_flush error code. Even if it fails, write was
+ * successful and it is more logical to consider that header is in the new
+ * state than in the old.
+ */
+ ret = bdrv_flush(bs);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to flush qcow2 header");
+ }
+
+ return 0;
+}
+
static inline void bitmap_table_to_cpu(uint64_t *bitmap_table, size_t size)
{
size_t i;
@@ -96,6 +130,15 @@ static inline void bitmap_table_to_cpu(uint64_t *bitmap_table, size_t size)
}
}
+static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; ++i) {
+ cpu_to_be64s(&bitmap_table[i]);
+ }
+}
+
static int check_table_entry(uint64_t entry, int cluster_size)
{
uint64_t offset;
@@ -123,7 +166,50 @@ static int check_table_entry(uint64_t entry, int cluster_size)
return 0;
}
-static int bitmap_table_load(BlockDriverState *bs, Qcow2Bitmap *bm,
+static int check_constraints_on_bitmap(BlockDriverState *bs,
+ const char *name,
+ uint32_t granularity)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int granularity_bits = ctz32(granularity);
+ int64_t len = bdrv_getlength(bs);
+ bool fail;
+
+ assert(granularity > 0);
+ assert((granularity & (granularity - 1)) == 0);
+
+ if (len < 0) {
+ return len;
+ }
+
+ fail = (granularity_bits > BME_MAX_GRANULARITY_BITS) ||
+ (granularity_bits < BME_MIN_GRANULARITY_BITS) ||
+ (len > (uint64_t)BME_MAX_PHYS_SIZE << granularity_bits) ||
+ (len > (uint64_t)BME_MAX_TABLE_SIZE * s->cluster_size <<
+ granularity_bits) ||
+ (strlen(name) > BME_MAX_NAME_SIZE);
+
+ return fail ? -EINVAL : 0;
+}
+
+static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
+ uint32_t bitmap_table_size)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int i;
+
+ for (i = 0; i < bitmap_table_size; ++i) {
+ uint64_t addr = bitmap_table[i] & BME_TABLE_ENTRY_OFFSET_MASK;
+ if (!addr) {
+ continue;
+ }
+
+ qcow2_free_clusters(bs, addr, s->cluster_size, QCOW2_DISCARD_OTHER);
+ bitmap_table[i] = 0;
+ }
+}
+
+static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
uint64_t **bitmap_table)
{
int ret;
@@ -131,20 +217,20 @@ static int bitmap_table_load(BlockDriverState *bs, Qcow2Bitmap *bm,
uint32_t i;
uint64_t *table;
- assert(bm->table_size != 0);
- table = g_try_new(uint64_t, bm->table_size);
+ assert(tb->size != 0);
+ table = g_try_new(uint64_t, tb->size);
if (table == NULL) {
return -ENOMEM;
}
- assert(bm->table_size <= BME_MAX_TABLE_SIZE);
- ret = bdrv_pread(bs->file, bm->table_offset,
- table, bm->table_size * sizeof(uint64_t));
+ assert(tb->size <= BME_MAX_TABLE_SIZE);
+ ret = bdrv_pread(bs->file, tb->offset,
+ table, tb->size * sizeof(uint64_t));
if (ret < 0) {
goto fail;
}
- for (i = 0; i < bm->table_size; ++i) {
+ for (i = 0; i < tb->size; ++i) {
be64_to_cpus(&table[i]);
ret = check_table_entry(table[i], s->cluster_size);
if (ret < 0) {
@@ -161,6 +247,28 @@ fail:
return ret;
}
+static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
+{
+ int ret;
+ uint64_t *bitmap_table;
+
+ ret = bitmap_table_load(bs, tb, &bitmap_table);
+ if (ret < 0) {
+ assert(bitmap_table == NULL);
+ return ret;
+ }
+
+ clear_bitmap_table(bs, bitmap_table, tb->size);
+ qcow2_free_clusters(bs, tb->offset, tb->size * sizeof(uint64_t),
+ QCOW2_DISCARD_OTHER);
+ g_free(bitmap_table);
+
+ tb->offset = 0;
+ tb->size = 0;
+
+ return 0;
+}
+
/* This function returns the number of disk sectors covered by a single cluster
* of bitmap data. */
static uint64_t disk_sectors_in_bitmap_cluster(const BDRVQcow2State *s,
@@ -242,7 +350,7 @@ static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
goto fail;
}
- ret = bitmap_table_load(bs, bm, &bitmap_table);
+ ret = bitmap_table_load(bs, &bm->table, &bitmap_table);
if (ret < 0) {
error_setg_errno(errp, -ret,
"Could not read bitmap_table table from image for "
@@ -256,7 +364,7 @@ static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
goto fail;
}
- ret = load_bitmap_data(bs, bitmap_table, bm->table_size,
+ ret = load_bitmap_data(bs, bitmap_table, bm->table.size,
bitmap);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read bitmap '%s' from image",
@@ -492,8 +600,8 @@ static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
}
bm = g_new(Qcow2Bitmap, 1);
- bm->table_offset = e->bitmap_table_offset;
- bm->table_size = e->bitmap_table_size;
+ bm->table.offset = e->bitmap_table_offset;
+ bm->table.size = e->bitmap_table_size;
bm->flags = e->flags;
bm->granularity_bits = e->granularity_bits;
bm->name = dir_entry_copy_name(e);
@@ -561,8 +669,8 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
e = (Qcow2BitmapDirEntry *)dir;
QSIMPLEQ_FOREACH(bm, bm_list, entry) {
- e->bitmap_table_offset = bm->table_offset;
- e->bitmap_table_size = bm->table_size;
+ e->bitmap_table_offset = bm->table.offset;
+ e->bitmap_table_size = bm->table.size;
e->flags = bm->flags;
e->type = BT_DIRTY_TRACKING_BITMAP;
e->granularity_bits = bm->granularity_bits;
@@ -654,6 +762,69 @@ static int update_ext_header_and_dir_in_place(BlockDriverState *bs,
return update_header_sync(bs);
}
+static int update_ext_header_and_dir(BlockDriverState *bs,
+ Qcow2BitmapList *bm_list)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int ret;
+ uint64_t new_offset = 0;
+ uint64_t new_size = 0;
+ uint32_t new_nb_bitmaps = 0;
+ uint64_t old_offset = s->bitmap_directory_offset;
+ uint64_t old_size = s->bitmap_directory_size;
+ uint32_t old_nb_bitmaps = s->nb_bitmaps;
+ uint64_t old_autocl = s->autoclear_features;
+
+ if (bm_list != NULL && !QSIMPLEQ_EMPTY(bm_list)) {
+ new_nb_bitmaps = bitmap_list_count(bm_list);
+
+ if (new_nb_bitmaps > QCOW2_MAX_BITMAPS) {
+ return -EINVAL;
+ }
+
+ ret = bitmap_list_store(bs, bm_list, &new_offset, &new_size, false);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = bdrv_flush(bs->file->bs);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS;
+ } else {
+ s->autoclear_features &= ~(uint64_t)QCOW2_AUTOCLEAR_BITMAPS;
+ }
+
+ s->bitmap_directory_offset = new_offset;
+ s->bitmap_directory_size = new_size;
+ s->nb_bitmaps = new_nb_bitmaps;
+
+ ret = update_header_sync(bs);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ if (old_size > 0) {
+ qcow2_free_clusters(bs, old_offset, old_size, QCOW2_DISCARD_OTHER);
+ }
+
+ return 0;
+
+fail:
+ if (new_offset > 0) {
+ qcow2_free_clusters(bs, new_offset, new_size, QCOW2_DISCARD_OTHER);
+ }
+
+ s->bitmap_directory_offset = old_offset;
+ s->bitmap_directory_size = old_size;
+ s->nb_bitmaps = old_nb_bitmaps;
+ s->autoclear_features = old_autocl;
+
+ return ret;
+}
+
/* for g_slist_foreach for GSList of BdrvDirtyBitmap* elements */
static void release_dirty_bitmap_helper(gpointer bitmap,
gpointer bs)
@@ -713,3 +884,311 @@ fail:
g_slist_free(created_dirty_bitmaps);
bitmap_list_free(bm_list);
}
+
+/* store_bitmap_data()
+ * Store bitmap to image, filling bitmap table accordingly.
+ */
+static uint64_t *store_bitmap_data(BlockDriverState *bs,
+ BdrvDirtyBitmap *bitmap,
+ uint32_t *bitmap_table_size, Error **errp)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ int64_t sector;
+ uint64_t dsc;
+ uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
+ const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
+ uint8_t *buf = NULL;
+ BdrvDirtyBitmapIter *dbi;
+ uint64_t *tb;
+ uint64_t tb_size =
+ size_to_clusters(s,
+ bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
+
+ if (tb_size > BME_MAX_TABLE_SIZE ||
+ tb_size * s->cluster_size > BME_MAX_PHYS_SIZE)
+ {
+ error_setg(errp, "Bitmap '%s' is too big", bm_name);
+ return NULL;
+ }
+
+ tb = g_try_new0(uint64_t, tb_size);
+ if (tb == NULL) {
+ error_setg(errp, "No memory");
+ return NULL;
+ }
+
+ dbi = bdrv_dirty_iter_new(bitmap, 0);
+ buf = g_malloc(s->cluster_size);
+ dsc = disk_sectors_in_bitmap_cluster(s, bitmap);
+ assert(DIV_ROUND_UP(bm_size, dsc) == tb_size);
+
+ while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
+ uint64_t cluster = sector / dsc;
+ uint64_t end, write_size;
+ int64_t off;
+
+ sector = cluster * dsc;
+ end = MIN(bm_size, sector + dsc);
+ write_size =
+ bdrv_dirty_bitmap_serialization_size(bitmap, sector, end - sector);
+ assert(write_size <= s->cluster_size);
+
+ off = qcow2_alloc_clusters(bs, s->cluster_size);
+ if (off < 0) {
+ error_setg_errno(errp, -off,
+ "Failed to allocate clusters for bitmap '%s'",
+ bm_name);
+ goto fail;
+ }
+ tb[cluster] = off;
+
+ bdrv_dirty_bitmap_serialize_part(bitmap, buf, sector, end - sector);
+ if (write_size < s->cluster_size) {
+ memset(buf + write_size, 0, s->cluster_size - write_size);
+ }
+
+ ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Qcow2 overlap check failed");
+ goto fail;
+ }
+
+ ret = bdrv_pwrite(bs->file, off, buf, s->cluster_size);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file",
+ bm_name);
+ goto fail;
+ }
+
+ if (end >= bm_size) {
+ break;
+ }
+
+ bdrv_set_dirty_iter(dbi, end);
+ }
+
+ *bitmap_table_size = tb_size;
+ g_free(buf);
+ bdrv_dirty_iter_free(dbi);
+
+ return tb;
+
+fail:
+ clear_bitmap_table(bs, tb, tb_size);
+ g_free(buf);
+ bdrv_dirty_iter_free(dbi);
+ g_free(tb);
+
+ return NULL;
+}
+
+/* store_bitmap()
+ * Store bm->dirty_bitmap to qcow2.
+ * Set bm->table_offset and bm->table_size accordingly.
+ */
+static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp)
+{
+ int ret;
+ uint64_t *tb;
+ int64_t tb_offset;
+ uint32_t tb_size;
+ BdrvDirtyBitmap *bitmap = bm->dirty_bitmap;
+ const char *bm_name;
+
+ assert(bitmap != NULL);
+
+ bm_name = bdrv_dirty_bitmap_name(bitmap);
+
+ tb = store_bitmap_data(bs, bitmap, &tb_size, errp);
+ if (tb == NULL) {
+ g_free(tb);
+ return -EINVAL;
+ }
+
+ assert(tb_size <= BME_MAX_TABLE_SIZE);
+ tb_offset = qcow2_alloc_clusters(bs, tb_size * sizeof(tb[0]));
+ if (tb_offset < 0) {
+ error_setg_errno(errp, -tb_offset,
+ "Failed to allocate clusters for bitmap '%s'",
+ bm_name);
+ goto fail;
+ }
+
+ ret = qcow2_pre_write_overlap_check(bs, 0, tb_offset,
+ tb_size * sizeof(tb[0]));
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Qcow2 overlap check failed");
+ goto fail;
+ }
+
+ bitmap_table_to_be(tb, tb_size);
+ ret = bdrv_pwrite(bs->file, tb_offset, tb, tb_size * sizeof(tb[0]));
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file",
+ bm_name);
+ goto fail;
+ }
+
+ g_free(tb);
+
+ bm->table.offset = tb_offset;
+ bm->table.size = tb_size;
+
+ return 0;
+
+fail:
+ clear_bitmap_table(bs, tb, tb_size);
+
+ if (tb_offset > 0) {
+ qcow2_free_clusters(bs, tb_offset, tb_size * sizeof(tb[0]),
+ QCOW2_DISCARD_OTHER);
+ }
+
+ g_free(tb);
+
+ return ret;
+}
+
+static Qcow2Bitmap *find_bitmap_by_name(Qcow2BitmapList *bm_list,
+ const char *name)
+{
+ Qcow2Bitmap *bm;
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if (strcmp(name, bm->name) == 0) {
+ return bm;
+ }
+ }
+
+ return NULL;
+}
+
+void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
+{
+ BdrvDirtyBitmap *bitmap;
+ BDRVQcow2State *s = bs->opaque;
+ uint32_t new_nb_bitmaps = s->nb_bitmaps;
+ uint64_t new_dir_size = s->bitmap_directory_size;
+ int ret;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+ Qcow2BitmapTableList drop_tables;
+ Qcow2BitmapTable *tb, *tb_next;
+
+ QSIMPLEQ_INIT(&drop_tables);
+
+ if (!can_write(bs)) {
+ error_setg(errp, "No write access");
+ return;
+ }
+
+ if (!bdrv_has_persistent_bitmaps(bs)) {
+ /* nothing to do */
+ return;
+ }
+
+ if (s->nb_bitmaps == 0) {
+ bm_list = bitmap_list_new();
+ } else {
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ /* errp is already set */
+ return;
+ }
+ }
+
+ /* check constraints and names */
+ for (bitmap = bdrv_dirty_bitmap_next(bs, NULL); bitmap != NULL;
+ bitmap = bdrv_dirty_bitmap_next(bs, bitmap))
+ {
+ const char *name = bdrv_dirty_bitmap_name(bitmap);
+ uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
+ Qcow2Bitmap *bm;
+
+ if (!bdrv_dirty_bitmap_get_persistance(bitmap)) {
+ continue;
+ }
+
+ if (check_constraints_on_bitmap(bs, name, granularity) < 0) {
+ error_setg(errp, "Bitmap '%s' doesn't satisfy the constraints",
+ name);
+ goto fail;
+ }
+
+ bm = find_bitmap_by_name(bm_list, name);
+ if (bm == NULL) {
+ if (++new_nb_bitmaps > QCOW2_MAX_BITMAPS) {
+ error_setg(errp, "Too many persistent bitmaps");
+ goto fail;
+ }
+
+ new_dir_size += calc_dir_entry_size(strlen(name), 0);
+ if (new_dir_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
+ error_setg(errp, "Too large bitmap directory");
+ goto fail;
+ }
+
+ bm = g_new0(Qcow2Bitmap, 1);
+ bm->name = g_strdup(name);
+ QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry);
+ } else {
+ if (!(bm->flags & BME_FLAG_IN_USE)) {
+ error_setg(errp, "Bitmap '%s' already exists in the image",
+ name);
+ goto fail;
+ }
+ tb = g_memdup(&bm->table, sizeof(bm->table));
+ bm->table.offset = 0;
+ bm->table.size = 0;
+ QSIMPLEQ_INSERT_TAIL(&drop_tables, tb, entry);
+ }
+ bm->flags = bdrv_dirty_bitmap_get_autoload(bitmap) ? BME_FLAG_AUTO : 0;
+ bm->granularity_bits = ctz32(bdrv_dirty_bitmap_granularity(bitmap));
+ bm->dirty_bitmap = bitmap;
+ }
+
+ /* allocate clusters and store bitmaps */
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if (bm->dirty_bitmap == NULL) {
+ continue;
+ }
+
+ ret = store_bitmap(bs, bm, errp);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
+ ret = update_ext_header_and_dir(bs, bm_list);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to update bitmap extension");
+ goto fail;
+ }
+
+ /* Bitmap directory was successfully updated, so, old data can be dropped.
+ * TODO it is better to reuse these clusters */
+ QSIMPLEQ_FOREACH_SAFE(tb, &drop_tables, entry, tb_next) {
+ free_bitmap_clusters(bs, tb);
+ g_free(tb);
+ }
+
+ bitmap_list_free(bm_list);
+ return;
+
+fail:
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ if (bm->dirty_bitmap == NULL || bm->table.offset == 0) {
+ continue;
+ }
+
+ free_bitmap_clusters(bs, &bm->table);
+ }
+
+ QSIMPLEQ_FOREACH_SAFE(tb, &drop_tables, entry, tb_next) {
+ g_free(tb);
+ }
+
+ bitmap_list_free(bm_list);
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index 9f64753..af580d2 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3542,6 +3542,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_attach_aio_context = qcow2_attach_aio_context,
.bdrv_load_autoloading_dirty_bitmaps = qcow2_load_autoloading_dirty_bitmaps,
+ .bdrv_store_persistent_dirty_bitmaps = qcow2_store_persistent_dirty_bitmaps,
};
static void bdrv_qcow2_init(void)
diff --git a/block/qcow2.h b/block/qcow2.h
index bcedf5b..d9a7643 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -615,5 +615,6 @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
/* qcow2-bitmap.c functions */
void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 14/24] block: add bdrv_can_store_new_dirty_bitmap
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (12 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 13/24] qcow2: add .bdrv_store_persistent_dirty_bitmaps() Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 15/24] qcow2: add .bdrv_can_store_new_dirty_bitmap Vladimir Sementsov-Ogievskiy
` (10 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
This will be needed to check some restrictions before making bitmap
persistent in qmp-block-dirty-bitmap-add (this functionality will be
added by future patch)
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
block.c | 22 ++++++++++++++++++++++
include/block/block.h | 2 ++
include/block/block_int.h | 2 ++
3 files changed, 26 insertions(+)
diff --git a/block.c b/block.c
index 646ea50..c20b22f 100644
--- a/block.c
+++ b/block.c
@@ -4139,3 +4139,25 @@ void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
drv->bdrv_store_persistent_dirty_bitmaps(bs, errp);
}
+
+bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
+ uint32_t granularity, Error **errp)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (!drv) {
+ error_setg_errno(errp, ENOMEDIUM,
+ "Can't store persistent bitmaps to %s",
+ bdrv_get_device_or_node_name(bs));
+ return false;
+ }
+
+ if (!drv->bdrv_can_store_new_dirty_bitmap) {
+ error_setg_errno(errp, ENOTSUP,
+ "Can't store persistent bitmaps to %s",
+ bdrv_get_device_or_node_name(bs));
+ return false;
+ }
+
+ return drv->bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp);
+}
diff --git a/include/block/block.h b/include/block/block.h
index e3175b5..1b5f270 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -554,5 +554,7 @@ void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+bool bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
+ uint32_t granularity, Error **errp);
#endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index e8d9210..b38b3aa 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -324,6 +324,8 @@ struct BlockDriver {
Error **errp);
void (*bdrv_store_persistent_dirty_bitmaps)(BlockDriverState *bs,
Error **errp);
+ bool (*bdrv_can_store_new_dirty_bitmap)(BlockDriverState *bs, const char *name,
+ uint32_t granularity, Error **errp);
QLIST_ENTRY(BlockDriver) list;
};
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 15/24] qcow2: add .bdrv_can_store_new_dirty_bitmap
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (13 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 14/24] block: add bdrv_can_store_new_dirty_bitmap Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 16/24] qmp: add persistent flag to block-dirty-bitmap-add Vladimir Sementsov-Ogievskiy
` (9 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Realize .bdrv_can_store_new_dirty_bitmap interface.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/qcow2-bitmap.c | 40 ++++++++++++++++++++++++++++++++++++++++
block/qcow2.c | 1 +
block/qcow2.h | 4 ++++
3 files changed, 45 insertions(+)
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index a2b857e..8b8f2d1 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -1192,3 +1192,43 @@ fail:
bitmap_list_free(bm_list);
}
+
+bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ uint32_t granularity,
+ Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+ const char *reason = NULL;
+ bool found;
+ Qcow2BitmapList *bm_list;
+
+ if (check_constraints_on_bitmap(bs, name, granularity) != 0) {
+ reason = "it doesn't satisfy the constraints";
+ goto common_errp;
+ }
+
+ if (s->nb_bitmaps == 0) {
+ return true;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return false;
+ }
+
+ found = find_bitmap_by_name(bm_list, name);
+ bitmap_list_free(bm_list);
+ if (found) {
+ reason = "bitmap with the same name is already stored";
+ goto common_errp;
+ }
+
+ return true;
+
+common_errp:
+ error_setg(errp, "Can't make bitmap '%s' persistent in '%s', as %s.",
+ name, bdrv_get_device_or_node_name(bs), reason);
+ return false;
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index af580d2..76a6a2b 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3543,6 +3543,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_load_autoloading_dirty_bitmaps = qcow2_load_autoloading_dirty_bitmaps,
.bdrv_store_persistent_dirty_bitmaps = qcow2_store_persistent_dirty_bitmaps,
+ .bdrv_can_store_new_dirty_bitmap = qcow2_can_store_new_dirty_bitmap,
};
static void bdrv_qcow2_init(void)
diff --git a/block/qcow2.h b/block/qcow2.h
index d9a7643..749710d 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -616,5 +616,9 @@ void qcow2_cache_put(BlockDriverState *bs, Qcow2Cache *c, void **table);
/* qcow2-bitmap.c functions */
void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ uint32_t granularity,
+ Error **errp);
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 16/24] qmp: add persistent flag to block-dirty-bitmap-add
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (14 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 15/24] qcow2: add .bdrv_can_store_new_dirty_bitmap Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 17/24] qmp: add autoload parameter " Vladimir Sementsov-Ogievskiy
` (8 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Add optional 'persistent' flag to qmp command block-dirty-bitmap-add.
Default is false.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 18 +++++++++++++++++-
docs/qmp-commands.txt | 3 +++
qapi/block-core.json | 7 ++++++-
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 245e1e1..40605fa 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1967,6 +1967,7 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common,
/* AIO context taken and released within qmp_block_dirty_bitmap_add */
qmp_block_dirty_bitmap_add(action->node, action->name,
action->has_granularity, action->granularity,
+ action->has_persistent, action->persistent,
&local_err);
if (!local_err) {
@@ -2696,10 +2697,12 @@ out:
void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bool has_granularity, uint32_t granularity,
+ bool has_persistent, bool persistent,
Error **errp)
{
AioContext *aio_context;
BlockDriverState *bs;
+ BdrvDirtyBitmap *bitmap;
if (!name || name[0] == '\0') {
error_setg(errp, "Bitmap name cannot be empty");
@@ -2725,7 +2728,20 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
granularity = bdrv_get_default_bitmap_granularity(bs);
}
- bdrv_create_dirty_bitmap(bs, granularity, name, errp);
+ if (!has_persistent) {
+ persistent = false;
+ }
+
+ if (persistent &&
+ !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
+ {
+ goto out;
+ }
+
+ bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
+ if (bitmap != NULL) {
+ bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
+ }
out:
aio_context_release(aio_context);
diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt
index abf210a..ef0245d 100644
--- a/docs/qmp-commands.txt
+++ b/docs/qmp-commands.txt
@@ -1015,6 +1015,9 @@ Arguments:
- "node": device/node on which to create dirty bitmap (json-string)
- "name": name of the new dirty bitmap (json-string)
- "granularity": granularity to track writes with (int, optional)
+- "persistent": bitmap will be saved to the corresponding block device image
+ file on its close. For now only Qcow2 disks support persistent
+ bitmaps. (json-bool, optional, default false) (Since 2.9)
Example:
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 6b42216..b6a2553 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1231,10 +1231,15 @@
# @granularity: #optional the bitmap granularity, default is 64k for
# block-dirty-bitmap-add
#
+# @persistent: #optional the bitmap is persistent, i.e. it will be saved to the
+# corresponding block device image file on its close. Default is
+# false. (Since 2.9)
+#
# Since: 2.4
##
{ 'struct': 'BlockDirtyBitmapAdd',
- 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } }
+ 'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32',
+ '*persistent': 'bool' } }
##
# @block-dirty-bitmap-add:
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 17/24] qmp: add autoload parameter to block-dirty-bitmap-add
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (15 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 16/24] qmp: add persistent flag to block-dirty-bitmap-add Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 18/24] qmp: add x-debug-block-dirty-bitmap-sha256 Vladimir Sementsov-Ogievskiy
` (7 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Optional. Default is false.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 18 ++++++++++++++++--
docs/qmp-commands.txt | 4 ++++
qapi/block-core.json | 6 +++++-
3 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 40605fa..e32ac69 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1968,6 +1968,7 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common,
qmp_block_dirty_bitmap_add(action->node, action->name,
action->has_granularity, action->granularity,
action->has_persistent, action->persistent,
+ action->has_autoload, action->autoload,
&local_err);
if (!local_err) {
@@ -2698,6 +2699,7 @@ out:
void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bool has_granularity, uint32_t granularity,
bool has_persistent, bool persistent,
+ bool has_autoload, bool autoload,
Error **errp)
{
AioContext *aio_context;
@@ -2731,6 +2733,15 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
if (!has_persistent) {
persistent = false;
}
+ if (!has_autoload) {
+ autoload = false;
+ }
+
+ if (has_autoload && !persistent) {
+ error_setg(errp, "Autoload flag must be used only for persistent "
+ "bitmaps");
+ goto out;
+ }
if (persistent &&
!bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp))
@@ -2739,10 +2750,13 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
}
bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
- if (bitmap != NULL) {
- bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
+ if (bitmap == NULL) {
+ goto out;
}
+ bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
+ bdrv_dirty_bitmap_set_autoload(bitmap, autoload);
+
out:
aio_context_release(aio_context);
}
diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt
index ef0245d..62469c0 100644
--- a/docs/qmp-commands.txt
+++ b/docs/qmp-commands.txt
@@ -1018,6 +1018,10 @@ Arguments:
- "persistent": bitmap will be saved to the corresponding block device image
file on its close. For now only Qcow2 disks support persistent
bitmaps. (json-bool, optional, default false) (Since 2.9)
+- "autoload": the bitmap will be automatically loaded when the image it is
+ stored in is opened. This flag may only be specified for
+ persistent bitmaps (json-bool, optional, default false)
+ (Since 2.9)
Example:
diff --git a/qapi/block-core.json b/qapi/block-core.json
index b6a2553..2c0aa1f 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1235,11 +1235,15 @@
# corresponding block device image file on its close. Default is
# false. (Since 2.9)
#
+# @autoload: #optional the bitmap will be automatically loaded when the image
+# it is stored in is opened. This flag may only be specified for
+# persistent bitmaps. Default is false. (Since 2.9)
+#
# Since: 2.4
##
{ 'struct': 'BlockDirtyBitmapAdd',
'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32',
- '*persistent': 'bool' } }
+ '*persistent': 'bool', '*autoload': 'bool' } }
##
# @block-dirty-bitmap-add:
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 18/24] qmp: add x-debug-block-dirty-bitmap-sha256
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (16 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 17/24] qmp: add autoload parameter " Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 15:09 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 19/24] iotests: test qcow2 persistent dirty bitmap Vladimir Sementsov-Ogievskiy
` (6 subsequent siblings)
24 siblings, 1 reply; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/dirty-bitmap.c | 5 +++++
blockdev.c | 29 +++++++++++++++++++++++++++++
include/block/dirty-bitmap.h | 2 ++
include/qemu/hbitmap.h | 8 ++++++++
qapi/block-core.json | 27 +++++++++++++++++++++++++++
tests/Makefile.include | 2 +-
util/hbitmap.c | 11 +++++++++++
7 files changed, 83 insertions(+), 1 deletion(-)
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index fe34d48..775181c 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -589,3 +589,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) :
QLIST_NEXT(bitmap, list);
}
+
+char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
+{
+ return hbitmap_sha256(bitmap->bitmap, errp);
+}
diff --git a/blockdev.c b/blockdev.c
index e32ac69..c41b791 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2820,6 +2820,35 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
aio_context_release(aio_context);
}
+BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
+ const char *name,
+ Error **errp)
+{
+ AioContext *aio_context;
+ BdrvDirtyBitmap *bitmap;
+ BlockDriverState *bs;
+ BlockDirtyBitmapSha256 *ret = NULL;
+ char *sha256;
+
+ bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
+ if (!bitmap || !bs) {
+ return NULL;
+ }
+
+ sha256 = bdrv_dirty_bitmap_sha256(bitmap, errp);
+ if (sha256 == NULL) {
+ goto out;
+ }
+
+ ret = g_new(BlockDirtyBitmapSha256, 1);
+ ret->sha256 = sha256;
+
+out:
+ aio_context_release(aio_context);
+
+ return ret;
+}
+
void hmp_drive_del(Monitor *mon, const QDict *qdict)
{
const char *id = qdict_get_str(qdict, "id");
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index d71edc4..b022b34 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -86,4 +86,6 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
bool bdrv_has_persistent_bitmaps(BlockDriverState *bs);
+char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp);
+
#endif
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
index 063ec0e..750346c 100644
--- a/include/qemu/hbitmap.h
+++ b/include/qemu/hbitmap.h
@@ -240,6 +240,14 @@ void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count,
void hbitmap_deserialize_finish(HBitmap *hb);
/**
+ * hbitmap_sha256:
+ * @bitmap: HBitmap to operate on.
+ *
+ * Returns SHA256 hash of the last level.
+ */
+char *hbitmap_sha256(const HBitmap *bitmap, Error **errp);
+
+/**
* hbitmap_free:
* @hb: HBitmap to operate on.
*
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 2c0aa1f..5f9a7fd 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1289,6 +1289,33 @@
'data': 'BlockDirtyBitmap' }
##
+# @BlockDirtyBitmapSha256:
+#
+# SHA256 hash of dirty bitmap data
+#
+# @sha256: bitmap SHA256 hash
+#
+# Since: 2.9
+##
+ { 'struct': 'BlockDirtyBitmapSha256',
+ 'data': {'sha256': 'str'} }
+
+##
+# @x-debug-block-dirty-bitmap-sha256:
+#
+# Get bitmap SHA256
+#
+# Returns: BlockDirtyBitmapSha256 on success
+# If @node is not a valid block device, DeviceNotFound
+# If @name is not found or if hashing is failed, GenericError with an
+# explanation
+#
+# Since: 2.9
+##
+ { 'command': 'x-debug-block-dirty-bitmap-sha256',
+ 'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256' }
+
+##
# @blockdev-mirror:
#
# Start mirroring a block device's writes to a new destination.
diff --git a/tests/Makefile.include b/tests/Makefile.include
index e98d3b6..b85ff78 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -496,7 +496,7 @@ tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-u
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
-tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y)
+tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o page_cache.o $(test-util-obj-y)
tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o
diff --git a/util/hbitmap.c b/util/hbitmap.c
index 47418a9..2dc09b8 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -13,6 +13,7 @@
#include "qemu/hbitmap.h"
#include "qemu/host-utils.h"
#include "trace.h"
+#include "crypto/hash.h"
/* HBitmaps provides an array of bits. The bits are stored as usual in an
* array of unsigned longs, but HBitmap is also optimized to provide fast
@@ -711,3 +712,13 @@ void hbitmap_free_meta(HBitmap *hb)
hbitmap_free(hb->meta);
hb->meta = NULL;
}
+
+char *hbitmap_sha256(const HBitmap *bitmap, Error **errp)
+{
+ size_t size = bitmap->sizes[HBITMAP_LEVELS - 1] * sizeof(unsigned long);
+ char *data = (char *)bitmap->levels[HBITMAP_LEVELS - 1];
+ char *hash = NULL;
+ qcrypto_hash_digest(QCRYPTO_HASH_ALG_SHA256, data, size, &hash, errp);
+
+ return hash;
+}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [Qemu-devel] [PATCH 18/24] qmp: add x-debug-block-dirty-bitmap-sha256
2016-12-21 14:54 ` [Qemu-devel] [PATCH 18/24] qmp: add x-debug-block-dirty-bitmap-sha256 Vladimir Sementsov-Ogievskiy
@ 2016-12-21 15:09 ` Vladimir Sementsov-Ogievskiy
0 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 15:09 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha, pbonzini
21.12.2016 17:54, Vladimir Sementsov-Ogievskiy wrote:
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> ---
> block/dirty-bitmap.c | 5 +++++
> blockdev.c | 29 +++++++++++++++++++++++++++++
> include/block/dirty-bitmap.h | 2 ++
> include/qemu/hbitmap.h | 8 ++++++++
> qapi/block-core.json | 27 +++++++++++++++++++++++++++
> tests/Makefile.include | 2 +-
> util/hbitmap.c | 11 +++++++++++
> 7 files changed, 83 insertions(+), 1 deletion(-)
>
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index fe34d48..775181c 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -589,3 +589,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
> return bitmap == NULL ? QLIST_FIRST(&bs->dirty_bitmaps) :
> QLIST_NEXT(bitmap, list);
> }
> +
> +char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
> +{
> + return hbitmap_sha256(bitmap->bitmap, errp);
> +}
> diff --git a/blockdev.c b/blockdev.c
> index e32ac69..c41b791 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -2820,6 +2820,35 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
> aio_context_release(aio_context);
> }
>
> +BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
> + const char *name,
> + Error **errp)
> +{
> + AioContext *aio_context;
> + BdrvDirtyBitmap *bitmap;
> + BlockDriverState *bs;
> + BlockDirtyBitmapSha256 *ret = NULL;
> + char *sha256;
> +
> + bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
> + if (!bitmap || !bs) {
> + return NULL;
> + }
> +
> + sha256 = bdrv_dirty_bitmap_sha256(bitmap, errp);
> + if (sha256 == NULL) {
> + goto out;
> + }
> +
> + ret = g_new(BlockDirtyBitmapSha256, 1);
> + ret->sha256 = sha256;
> +
> +out:
> + aio_context_release(aio_context);
> +
> + return ret;
> +}
> +
> void hmp_drive_del(Monitor *mon, const QDict *qdict)
> {
> const char *id = qdict_get_str(qdict, "id");
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index d71edc4..b022b34 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -86,4 +86,6 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
>
> bool bdrv_has_persistent_bitmaps(BlockDriverState *bs);
>
> +char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp);
> +
> #endif
> diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
> index 063ec0e..750346c 100644
> --- a/include/qemu/hbitmap.h
> +++ b/include/qemu/hbitmap.h
> @@ -240,6 +240,14 @@ void hbitmap_deserialize_ones(HBitmap *hb, uint64_t start, uint64_t count,
> void hbitmap_deserialize_finish(HBitmap *hb);
>
> /**
> + * hbitmap_sha256:
> + * @bitmap: HBitmap to operate on.
> + *
> + * Returns SHA256 hash of the last level.
> + */
> +char *hbitmap_sha256(const HBitmap *bitmap, Error **errp);
> +
> +/**
> * hbitmap_free:
> * @hb: HBitmap to operate on.
> *
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 2c0aa1f..5f9a7fd 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -1289,6 +1289,33 @@
> 'data': 'BlockDirtyBitmap' }
>
> ##
> +# @BlockDirtyBitmapSha256:
> +#
> +# SHA256 hash of dirty bitmap data
From bitmap migration series:
21.11.2016 19:46, Eric Blake wrote:
> Maybe 'ASCII representation of SHA256 hash...' to make it clear that
> this is a longhand representation rather than a binary value that might
> include non-characters.
- sorry for this inconsistency with my two series. Also, I think that
these details are better to be inserted into next line ('@sha255: ...')
> +#
> +# @sha256: bitmap SHA256 hash
> +#
> +# Since: 2.9
> +##
> + { 'struct': 'BlockDirtyBitmapSha256',
> + 'data': {'sha256': 'str'} }
> +
> +##
> +# @x-debug-block-dirty-bitmap-sha256:
> +#
> +# Get bitmap SHA256
> +#
> +# Returns: BlockDirtyBitmapSha256 on success
> +# If @node is not a valid block device, DeviceNotFound
> +# If @name is not found or if hashing is failed, GenericError with an
> +# explanation
> +#
> +# Since: 2.9
> +##
> + { 'command': 'x-debug-block-dirty-bitmap-sha256',
> + 'data': 'BlockDirtyBitmap', 'returns': 'BlockDirtyBitmapSha256' }
> +
> +##
> # @blockdev-mirror:
> #
> # Start mirroring a block device's writes to a new destination.
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index e98d3b6..b85ff78 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -496,7 +496,7 @@ tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-u
> tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
> tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
> tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
> -tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y)
> +tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
> tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
> tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o page_cache.o $(test-util-obj-y)
> tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o
> diff --git a/util/hbitmap.c b/util/hbitmap.c
> index 47418a9..2dc09b8 100644
> --- a/util/hbitmap.c
> +++ b/util/hbitmap.c
> @@ -13,6 +13,7 @@
> #include "qemu/hbitmap.h"
> #include "qemu/host-utils.h"
> #include "trace.h"
> +#include "crypto/hash.h"
>
> /* HBitmaps provides an array of bits. The bits are stored as usual in an
> * array of unsigned longs, but HBitmap is also optimized to provide fast
> @@ -711,3 +712,13 @@ void hbitmap_free_meta(HBitmap *hb)
> hbitmap_free(hb->meta);
> hb->meta = NULL;
> }
> +
> +char *hbitmap_sha256(const HBitmap *bitmap, Error **errp)
> +{
> + size_t size = bitmap->sizes[HBITMAP_LEVELS - 1] * sizeof(unsigned long);
> + char *data = (char *)bitmap->levels[HBITMAP_LEVELS - 1];
> + char *hash = NULL;
> + qcrypto_hash_digest(QCRYPTO_HASH_ALG_SHA256, data, size, &hash, errp);
> +
> + return hash;
> +}
--
Best regards,
Vladimir
^ permalink raw reply [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 19/24] iotests: test qcow2 persistent dirty bitmap
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (17 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 18/24] qmp: add x-debug-block-dirty-bitmap-sha256 Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 20/24] qcow2-refcount: rename inc_refcounts() and make it public Vladimir Sementsov-Ogievskiy
` (5 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
tests/qemu-iotests/165 | 89 ++++++++++++++++++++++++++++++++++++++++++++++
tests/qemu-iotests/165.out | 5 +++
tests/qemu-iotests/group | 1 +
3 files changed, 95 insertions(+)
create mode 100755 tests/qemu-iotests/165
create mode 100644 tests/qemu-iotests/165.out
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
new file mode 100755
index 0000000..11d2e22
--- /dev/null
+++ b/tests/qemu-iotests/165
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+#
+# Tests for persistent dirty bitmaps.
+#
+# Copyright: Vladimir Sementsov-Ogievskiy 2015-2016
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import iotests
+from iotests import qemu_img
+
+disk = os.path.join(iotests.test_dir, 'disk')
+disk_size = 0x40000000 # 1G
+
+# regions for qemu_io: (start, count) in bytes
+regions1 = ((0, 0x100000),
+ (0x200000, 0x100000))
+
+regions2 = ((0x10000000, 0x20000),
+ (0x3fff0000, 0x10000))
+
+class TestPersistentDirtyBitmap(iotests.QMPTestCase):
+
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, disk, str(disk_size))
+
+ def tearDown(self):
+ os.remove(disk)
+
+ def mkVm(self):
+ return iotests.VM().add_drive(disk)
+
+ def getSha256(self):
+ result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256',
+ node='drive0', name='bitmap0')
+ return result['return']['sha256']
+
+ def checkBitmap(self, sha256):
+ result = self.vm.qmp('x-debug-block-dirty-bitmap-sha256',
+ node='drive0', name='bitmap0')
+ self.assert_qmp(result, 'return/sha256', sha256);
+
+ def writeRegions(self, regions):
+ for r in regions:
+ self.vm.hmp_qemu_io('drive0',
+ 'write %d %d' % r)
+
+ def qmpAddBitmap(self):
+ self.vm.qmp('block-dirty-bitmap-add', node='drive0',
+ name='bitmap0', persistent=True, autoload=True)
+
+ def test_persistent(self):
+ self.vm = self.mkVm()
+ self.vm.launch()
+ self.qmpAddBitmap()
+
+ self.writeRegions(regions1)
+ sha256 = self.getSha256()
+
+ self.vm.shutdown()
+ self.vm = self.mkVm()
+ self.vm.launch()
+
+ self.checkBitmap(sha256)
+ self.writeRegions(regions2)
+ sha256 = self.getSha256()
+
+ self.vm.shutdown()
+ self.vm.launch()
+
+ self.checkBitmap(sha256)
+
+ self.vm.shutdown()
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['qcow2'])
diff --git a/tests/qemu-iotests/165.out b/tests/qemu-iotests/165.out
new file mode 100644
index 0000000..ae1213e
--- /dev/null
+++ b/tests/qemu-iotests/165.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 866c1a0..8bd7a84 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -162,6 +162,7 @@
159 rw auto quick
160 rw auto quick
162 auto quick
+165 rw auto quick
170 rw auto quick
171 rw auto quick
172 auto
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 20/24] qcow2-refcount: rename inc_refcounts() and make it public
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (18 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 19/24] iotests: test qcow2 persistent dirty bitmap Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:54 ` [Qemu-devel] [PATCH 21/24] qcow2-bitmap: refcounts Vladimir Sementsov-Ogievskiy
` (4 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
This is needed for the following patch, which will introduce refcounts
checking for qcow2 bitmaps.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
block/qcow2-refcount.c | 53 ++++++++++++++++++++++++++------------------------
block/qcow2.h | 4 ++++
2 files changed, 32 insertions(+), 25 deletions(-)
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index cbfb3fe..14a736d 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1309,11 +1309,10 @@ static int realloc_refcount_array(BDRVQcow2State *s, void **array,
*
* Modifies the number of errors in res.
*/
-static int inc_refcounts(BlockDriverState *bs,
- BdrvCheckResult *res,
- void **refcount_table,
- int64_t *refcount_table_size,
- int64_t offset, int64_t size)
+int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size,
+ int64_t offset, int64_t size)
{
BDRVQcow2State *s = bs->opaque;
uint64_t start, last, cluster_offset, k, refcount;
@@ -1406,8 +1405,9 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
nb_csectors = ((l2_entry >> s->csize_shift) &
s->csize_mask) + 1;
l2_entry &= s->cluster_offset_mask;
- ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
- l2_entry & ~511, nb_csectors * 512);
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ l2_entry & ~511, nb_csectors * 512);
if (ret < 0) {
goto fail;
}
@@ -1445,8 +1445,9 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
}
/* Mark cluster as used */
- ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
- offset, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ offset, s->cluster_size);
if (ret < 0) {
goto fail;
}
@@ -1498,8 +1499,8 @@ static int check_refcounts_l1(BlockDriverState *bs,
l1_size2 = l1_size * sizeof(uint64_t);
/* Mark L1 table as used */
- ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
- l1_table_offset, l1_size2);
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
+ l1_table_offset, l1_size2);
if (ret < 0) {
goto fail;
}
@@ -1528,8 +1529,9 @@ static int check_refcounts_l1(BlockDriverState *bs,
if (l2_offset) {
/* Mark L2 table as used */
l2_offset &= L1E_OFFSET_MASK;
- ret = inc_refcounts(bs, res, refcount_table, refcount_table_size,
- l2_offset, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ l2_offset, s->cluster_size);
if (ret < 0) {
goto fail;
}
@@ -1744,14 +1746,15 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
}
res->corruptions_fixed++;
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- offset, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, nb_clusters,
+ offset, s->cluster_size);
if (ret < 0) {
return ret;
}
/* No need to check whether the refcount is now greater than 1:
* This area was just allocated and zeroed, so it can only be
- * exactly 1 after inc_refcounts() */
+ * exactly 1 after qcow2_inc_refcounts_imrt() */
continue;
resize_fail:
@@ -1766,8 +1769,8 @@ resize_fail:
}
if (offset != 0) {
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- offset, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ offset, s->cluster_size);
if (ret < 0) {
return ret;
}
@@ -1807,8 +1810,8 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
}
/* header */
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- 0, s->cluster_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ 0, s->cluster_size);
if (ret < 0) {
return ret;
}
@@ -1829,16 +1832,16 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
return ret;
}
}
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- s->snapshots_offset, s->snapshots_size);
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ s->snapshots_offset, s->snapshots_size);
if (ret < 0) {
return ret;
}
/* refcount data */
- ret = inc_refcounts(bs, res, refcount_table, nb_clusters,
- s->refcount_table_offset,
- s->refcount_table_size * sizeof(uint64_t));
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, nb_clusters,
+ s->refcount_table_offset,
+ s->refcount_table_size * sizeof(uint64_t));
if (ret < 0) {
return ret;
}
diff --git a/block/qcow2.h b/block/qcow2.h
index 749710d..0a3708d 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -543,6 +543,10 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
int64_t size);
+int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size,
+ int64_t offset, int64_t size);
int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
BlockDriverAmendStatusCB *status_cb,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 21/24] qcow2-bitmap: refcounts
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (19 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 20/24] qcow2-refcount: rename inc_refcounts() and make it public Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:54 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:55 ` [Qemu-devel] [PATCH 22/24] block/dirty-bitmap: deep release dirty bitmaps Vladimir Sementsov-Ogievskiy
` (3 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:54 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Calculate refcounts for qcow2 bitmaps. It is needed for qcow2's qemu-img
check implementation.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/qcow2-bitmap.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++
block/qcow2-refcount.c | 6 ++++
block/qcow2.h | 3 ++
3 files changed, 89 insertions(+)
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 8b8f2d1..2687a3a 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -1232,3 +1232,83 @@ common_errp:
name, bdrv_get_device_or_node_name(bs), reason);
return false;
}
+
+int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2BitmapList *bm_list;
+ Qcow2Bitmap *bm;
+
+ if (s->nb_bitmaps == 0) {
+ return 0;
+ }
+
+ ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
+ s->bitmap_directory_offset,
+ s->bitmap_directory_size);
+ if (ret < 0) {
+ return ret;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, NULL);
+ if (bm_list == NULL) {
+ res->corruptions++;
+ return -EINVAL;
+ }
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ uint64_t *bitmap_table = NULL;
+ int i;
+
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ bm->table.offset,
+ bm->table.size * sizeof(uint64_t));
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = bitmap_table_load(bs, &bm->table, &bitmap_table);
+ if (ret < 0) {
+ res->corruptions++;
+ goto out;
+ }
+
+ for (i = 0; i < bm->table.size; ++i) {
+ uint64_t entry = bitmap_table[i];
+ uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
+
+ if (check_table_entry(entry, s->cluster_size) < 0) {
+ res->corruptions++;
+ continue;
+ }
+
+ if (offset == 0) {
+ continue;
+ }
+
+ ret = qcow2_inc_refcounts_imrt(bs, res,
+ refcount_table, refcount_table_size,
+ offset, s->cluster_size);
+ if (ret < 0) {
+ g_free(bitmap_table);
+ goto out;
+ }
+ }
+
+ g_free(bitmap_table);
+ }
+
+ if (res->corruptions > 0) {
+ ret = -EINVAL;
+ }
+
+out:
+ bitmap_list_free(bm_list);
+
+ return ret;
+}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 14a736d..cdb74ba 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1846,6 +1846,12 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
return ret;
}
+ /* bitmaps */
+ ret = qcow2_check_bitmaps_refcounts(bs, res, refcount_table, nb_clusters);
+ if (ret < 0) {
+ return ret;
+ }
+
return check_refblocks(bs, res, fix, rebuild, refcount_table, nb_clusters);
}
diff --git a/block/qcow2.h b/block/qcow2.h
index 0a3708d..eaad34a 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -624,5 +624,8 @@ bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
const char *name,
uint32_t granularity,
Error **errp);
+int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
+ void **refcount_table,
+ int64_t *refcount_table_size);
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 22/24] block/dirty-bitmap: deep release dirty bitmaps
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (20 preceding siblings ...)
2016-12-21 14:54 ` [Qemu-devel] [PATCH 21/24] qcow2-bitmap: refcounts Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:55 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:55 ` [Qemu-devel] [PATCH 23/24] qcow2: add .bdrv_remove_persistent_dirty_bitmap Vladimir Sementsov-Ogievskiy
` (2 subsequent siblings)
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:55 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Remove persistent bitmap from its storage on bdrv_release_dirty_bitmap.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/dirty-bitmap.c | 21 ++++++++++++++++++---
include/block/block_int.h | 3 +++
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 775181c..0977df6 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -297,7 +297,8 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap,
- bool only_named)
+ bool only_named,
+ bool deep)
{
BdrvDirtyBitmap *bm, *next;
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
@@ -305,6 +306,19 @@ static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
assert(!bm->active_iterators);
assert(!bdrv_dirty_bitmap_frozen(bm));
assert(!bm->meta);
+
+ if (deep && bm->persistent && bs->drv &&
+ bs->drv->bdrv_remove_persistent_dirty_bitmap)
+ {
+ Error *local_err = NULL;
+ bs->drv->bdrv_remove_persistent_dirty_bitmap(bs, bm->name,
+ &local_err);
+ if (local_err != NULL) {
+ error_report_err(local_err);
+ }
+ }
+
+
QLIST_REMOVE(bm, list);
hbitmap_free(bm->bitmap);
g_free(bm->name);
@@ -322,16 +336,17 @@ static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
{
- bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false);
+ bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false, true);
}
/**
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
* There must not be any frozen bitmaps attached.
+ * This function do not remove persistent bitmaps from the storage.
*/
void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
{
- bdrv_do_release_matching_dirty_bitmap(bs, NULL, true);
+ bdrv_do_release_matching_dirty_bitmap(bs, NULL, true, false);
}
void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
diff --git a/include/block/block_int.h b/include/block/block_int.h
index b38b3aa..3e080d6 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -326,6 +326,9 @@ struct BlockDriver {
Error **errp);
bool (*bdrv_can_store_new_dirty_bitmap)(BlockDriverState *bs, const char *name,
uint32_t granularity, Error **errp);
+ void (*bdrv_remove_persistent_dirty_bitmap)(BlockDriverState *bs,
+ const char *name,
+ Error **errp);
QLIST_ENTRY(BlockDriver) list;
};
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 23/24] qcow2: add .bdrv_remove_persistent_dirty_bitmap
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (21 preceding siblings ...)
2016-12-21 14:55 ` [Qemu-devel] [PATCH 22/24] block/dirty-bitmap: deep release dirty bitmaps Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:55 ` Vladimir Sementsov-Ogievskiy
2016-12-21 14:55 ` [Qemu-devel] [PATCH 24/24] qcow2-bitmap: cache bitmap list in BDRVQcow2State Vladimir Sementsov-Ogievskiy
2016-12-21 15:29 ` [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps no-reply
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:55 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Realize .bdrv_remove_persistent_dirty_bitmap interface.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/qcow2-bitmap.c | 40 ++++++++++++++++++++++++++++++++++++++++
block/qcow2.c | 1 +
block/qcow2.h | 3 +++
3 files changed, 44 insertions(+)
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 2687a3a..be026fc 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -1064,6 +1064,46 @@ static Qcow2Bitmap *find_bitmap_by_name(Qcow2BitmapList *bm_list,
return NULL;
}
+void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ Error **errp)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ Qcow2Bitmap *bm;
+ Qcow2BitmapList *bm_list;
+
+ if (s->nb_bitmaps == 0) {
+ /* No bitmaps - nothing to do */
+ return;
+ }
+
+ bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+ if (bm_list == NULL) {
+ return;
+ }
+
+ bm = find_bitmap_by_name(bm_list, name);
+ if (bm == NULL) {
+ goto fail;
+ }
+
+ QSIMPLEQ_REMOVE(bm_list, bm, Qcow2Bitmap, entry);
+
+ ret = update_ext_header_and_dir(bs, bm_list);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to update bitmap extension");
+ goto fail;
+ }
+
+ free_bitmap_clusters(bs, &bm->table);
+
+fail:
+ bitmap_free(bm);
+ bitmap_list_free(bm_list);
+}
+
void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
{
BdrvDirtyBitmap *bitmap;
diff --git a/block/qcow2.c b/block/qcow2.c
index 76a6a2b..f6bac38e 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3544,6 +3544,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_load_autoloading_dirty_bitmaps = qcow2_load_autoloading_dirty_bitmaps,
.bdrv_store_persistent_dirty_bitmaps = qcow2_store_persistent_dirty_bitmaps,
.bdrv_can_store_new_dirty_bitmap = qcow2_can_store_new_dirty_bitmap,
+ .bdrv_remove_persistent_dirty_bitmap = qcow2_remove_persistent_dirty_bitmap,
};
static void bdrv_qcow2_init(void)
diff --git a/block/qcow2.h b/block/qcow2.h
index eaad34a..a009827 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -627,5 +627,8 @@ bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size);
+void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs,
+ const char *name,
+ Error **errp);
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [Qemu-devel] [PATCH 24/24] qcow2-bitmap: cache bitmap list in BDRVQcow2State
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (22 preceding siblings ...)
2016-12-21 14:55 ` [Qemu-devel] [PATCH 23/24] qcow2: add .bdrv_remove_persistent_dirty_bitmap Vladimir Sementsov-Ogievskiy
@ 2016-12-21 14:55 ` Vladimir Sementsov-Ogievskiy
2016-12-21 15:29 ` [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps no-reply
24 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 14:55 UTC (permalink / raw)
To: qemu-block, qemu-devel
Cc: kwolf, mreitz, armbru, eblake, jsnow, famz, den, stefanha,
vsementsov, pbonzini
Do not reload bitmap list every time it is needed.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/qcow2-bitmap.c | 121 ++++++++++++++++++++++++++++++++++-----------------
block/qcow2.c | 2 +
block/qcow2.h | 4 ++
3 files changed, 87 insertions(+), 40 deletions(-)
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index be026fc..b9f3d62 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -89,7 +89,6 @@ typedef struct Qcow2Bitmap {
QSIMPLEQ_ENTRY(Qcow2Bitmap) entry;
} Qcow2Bitmap;
-typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList;
typedef enum BitmapType {
BT_DIRTY_TRACKING_BITMAP = 1
@@ -492,6 +491,14 @@ static void bitmap_free(Qcow2Bitmap *bm)
g_free(bm);
}
+static Qcow2Bitmap *bitmap_dup(Qcow2Bitmap *bm)
+{
+ Qcow2Bitmap *copy = g_memdup(bm, sizeof(*bm));
+ copy->name = g_strdup(bm->name);
+
+ return copy;
+}
+
static void bitmap_list_free(Qcow2BitmapList *bm_list)
{
Qcow2Bitmap *bm;
@@ -729,6 +736,44 @@ fail:
* Bitmap List end
*/
+static const Qcow2BitmapList *qcow2_get_bitmap_list_const(BlockDriverState *bs,
+ Error **errp)
+{
+ BDRVQcow2State *s = bs->opaque;
+
+ if (s->bitmaps != NULL) {
+ return s->bitmaps;
+ }
+
+ if (s->nb_bitmaps == 0) {
+ return NULL;
+ }
+
+ return s->bitmaps = bitmap_list_load(bs, s->bitmap_directory_offset,
+ s->bitmap_directory_size, errp);
+}
+
+static Qcow2BitmapList *qcow2_get_bitmap_list(BlockDriverState *bs,
+ Error **errp)
+{
+ Qcow2Bitmap *bm;
+ Qcow2BitmapList *bm_list_copy;
+ const Qcow2BitmapList *bm_list = qcow2_get_bitmap_list_const(bs, errp);
+
+ if (bm_list == NULL) {
+ return NULL;
+ }
+
+ bm_list_copy = bitmap_list_new();
+
+ QSIMPLEQ_FOREACH(bm, bm_list, entry) {
+ QSIMPLEQ_INSERT_TAIL(bm_list_copy, bitmap_dup(bm), entry);
+ }
+
+ return bm_list_copy;
+}
+
+/* This function consumes bm_list on success. */
static int update_ext_header_and_dir_in_place(BlockDriverState *bs,
Qcow2BitmapList *bm_list)
{
@@ -759,9 +804,20 @@ static int update_ext_header_and_dir_in_place(BlockDriverState *bs,
}
s->autoclear_features |= QCOW2_AUTOCLEAR_BITMAPS;
- return update_header_sync(bs);
+ ret = update_header_sync(bs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* success, consume bm_list */
+ assert(s->bitmaps != bm_list);
+ bitmap_list_free(s->bitmaps);
+ s->bitmaps = bm_list;
+
+ return 0;
}
+/* This function consumes bm_list on success. */
static int update_ext_header_and_dir(BlockDriverState *bs,
Qcow2BitmapList *bm_list)
{
@@ -810,6 +866,11 @@ static int update_ext_header_and_dir(BlockDriverState *bs,
qcow2_free_clusters(bs, old_offset, old_size, QCOW2_DISCARD_OTHER);
}
+ /* success, consume bm_list */
+ assert(s->bitmaps != bm_list);
+ bitmap_list_free(s->bitmaps);
+ s->bitmaps = bm_list;
+
return 0;
fail:
@@ -834,18 +895,11 @@ static void release_dirty_bitmap_helper(gpointer bitmap,
void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
{
- BDRVQcow2State *s = bs->opaque;
Qcow2BitmapList *bm_list;
Qcow2Bitmap *bm;
GSList *created_dirty_bitmaps = NULL;
- if (s->nb_bitmaps == 0) {
- /* No bitmaps - nothing to do */
- return;
- }
-
- bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
- s->bitmap_directory_size, errp);
+ bm_list = qcow2_get_bitmap_list(bs, errp);
if (bm_list == NULL) {
return;
}
@@ -875,9 +929,8 @@ void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
}
g_slist_free(created_dirty_bitmaps);
- bitmap_list_free(bm_list);
- return;
+ return; /* bm_list is consumed */
fail:
g_slist_foreach(created_dirty_bitmaps, release_dirty_bitmap_helper, bs);
@@ -1069,17 +1122,10 @@ void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs,
Error **errp)
{
int ret;
- BDRVQcow2State *s = bs->opaque;
Qcow2Bitmap *bm;
Qcow2BitmapList *bm_list;
- if (s->nb_bitmaps == 0) {
- /* No bitmaps - nothing to do */
- return;
- }
-
- bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
- s->bitmap_directory_size, errp);
+ bm_list = qcow2_get_bitmap_list(bs, errp);
if (bm_list == NULL) {
return;
}
@@ -1131,10 +1177,8 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
if (s->nb_bitmaps == 0) {
bm_list = bitmap_list_new();
} else {
- bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
- s->bitmap_directory_size, errp);
+ bm_list = qcow2_get_bitmap_list(bs, errp);
if (bm_list == NULL) {
- /* errp is already set */
return;
}
}
@@ -1214,8 +1258,7 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
g_free(tb);
}
- bitmap_list_free(bm_list);
- return;
+ return; /* bm_list is consumed */
fail:
QSIMPLEQ_FOREACH(bm, bm_list, entry) {
@@ -1252,8 +1295,7 @@ bool qcow2_can_store_new_dirty_bitmap(BlockDriverState *bs,
return true;
}
- bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
- s->bitmap_directory_size, errp);
+ bm_list = qcow2_get_bitmap_list(bs, errp);
if (bm_list == NULL) {
return false;
}
@@ -1279,7 +1321,7 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
{
int ret;
BDRVQcow2State *s = bs->opaque;
- Qcow2BitmapList *bm_list;
+ const Qcow2BitmapList *bm_list;
Qcow2Bitmap *bm;
if (s->nb_bitmaps == 0) {
@@ -1293,8 +1335,7 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
return ret;
}
- bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
- s->bitmap_directory_size, NULL);
+ bm_list = qcow2_get_bitmap_list_const(bs, NULL);
if (bm_list == NULL) {
res->corruptions++;
return -EINVAL;
@@ -1309,13 +1350,13 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
bm->table.offset,
bm->table.size * sizeof(uint64_t));
if (ret < 0) {
- goto out;
+ return ret;
}
ret = bitmap_table_load(bs, &bm->table, &bitmap_table);
if (ret < 0) {
res->corruptions++;
- goto out;
+ return ret;
}
for (i = 0; i < bm->table.size; ++i) {
@@ -1336,19 +1377,19 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
offset, s->cluster_size);
if (ret < 0) {
g_free(bitmap_table);
- goto out;
+ return ret;
}
}
g_free(bitmap_table);
}
- if (res->corruptions > 0) {
- ret = -EINVAL;
- }
-
-out:
- bitmap_list_free(bm_list);
+ return res->corruptions > 0 ? -EINVAL : 0;
+}
- return ret;
+void qcow2_free_bitmaps(BlockDriverState *bs)
+{
+ BDRVQcow2State *s = bs->opaque;
+ bitmap_list_free(s->bitmaps);
+ s->bitmaps = NULL;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index f6bac38e..f6544d5 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1850,6 +1850,8 @@ static void qcow2_close(BlockDriverState *bs)
qemu_vfree(s->cluster_data);
qcow2_refcount_close(bs);
qcow2_free_snapshots(bs);
+
+ qcow2_free_bitmaps(bs);
}
static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
diff --git a/block/qcow2.h b/block/qcow2.h
index a009827..ed8f5a7 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -242,6 +242,8 @@ typedef struct Qcow2BitmapHeaderExt {
uint64_t bitmap_directory_offset;
} QEMU_PACKED Qcow2BitmapHeaderExt;
+typedef struct Qcow2Bitmap Qcow2Bitmap;
+typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList;
typedef struct BDRVQcow2State {
int cluster_bits;
int cluster_size;
@@ -286,6 +288,7 @@ typedef struct BDRVQcow2State {
uint32_t nb_bitmaps;
uint64_t bitmap_directory_size;
uint64_t bitmap_directory_offset;
+ Qcow2BitmapList *bitmaps; /* cached version of bitmaps list in file */
int flags;
int qcow_version;
@@ -630,5 +633,6 @@ int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs,
const char *name,
Error **errp);
+void qcow2_free_bitmaps(BlockDriverState *bs);
#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps
2016-12-21 14:54 [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps Vladimir Sementsov-Ogievskiy
` (23 preceding siblings ...)
2016-12-21 14:55 ` [Qemu-devel] [PATCH 24/24] qcow2-bitmap: cache bitmap list in BDRVQcow2State Vladimir Sementsov-Ogievskiy
@ 2016-12-21 15:29 ` no-reply
2016-12-21 16:20 ` Vladimir Sementsov-Ogievskiy
24 siblings, 1 reply; 32+ messages in thread
From: no-reply @ 2016-12-21 15:29 UTC (permalink / raw)
To: vsementsov; +Cc: famz, qemu-block, qemu-devel, kwolf
Hi,
Your series failed automatic build test. Please find the testing commands and
their output below. If you have docker installed, you can probably reproduce it
locally.
Type: series
Message-id: 1482332102-131788-1-git-send-email-vsementsov@virtuozzo.com
Subject: [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps
=== TEST SCRIPT BEGIN ===
#!/bin/bash
set -e
git submodule update --init dtc
# Let docker tests dump environment info
export SHOW_ENV=1
export J=16
make docker-test-quick@centos6
make docker-test-mingw@fedora
make docker-test-build@min-glib
=== TEST SCRIPT END ===
Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
ef76b98 qcow2-bitmap: cache bitmap list in BDRVQcow2State
a357743 qcow2: add .bdrv_remove_persistent_dirty_bitmap
8310147 block/dirty-bitmap: deep release dirty bitmaps
089c498 qcow2-bitmap: refcounts
fbfe535 qcow2-refcount: rename inc_refcounts() and make it public
275eed2 iotests: test qcow2 persistent dirty bitmap
96a9ce0 qmp: add x-debug-block-dirty-bitmap-sha256
3e6dd36 qmp: add autoload parameter to block-dirty-bitmap-add
b5418b0 qmp: add persistent flag to block-dirty-bitmap-add
f624bc8 qcow2: add .bdrv_can_store_new_dirty_bitmap
4d9d7ac block: add bdrv_can_store_new_dirty_bitmap
87d58da qcow2: add .bdrv_store_persistent_dirty_bitmaps()
5fbebdd block/dirty-bitmap: add bdrv_dirty_bitmap_next()
731f771 block: introduce persistent dirty bitmaps
714509e block/dirty-bitmap: add autoload field to BdrvDirtyBitmap
7ff58fc qcow2: add .bdrv_load_autoloading_dirty_bitmaps
7a56b01 block: introduce auto-loading bitmaps
566981a qcow2: add bitmaps extension
ec285c1 block/dirty-bitmap: add deserialize_ones func
d4759b3 block: fix bdrv_dirty_bitmap_granularity signature
e5331b0 tests: add hbitmap iter test
e1b9104 hbitmap: improve dirty iter
7dc36ce specs/qcow2: do not use wording 'bitmap header'
3a6086b specs/qcow2: fix bitmap granularity qemu-specific note
=== OUTPUT BEGIN ===
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into 'dtc'...
Submodule path 'dtc': checked out '65cc4d2748a2c2e6f27f1cf39e07a5dbabd80ebf'
BUILD centos6
make[1]: Entering directory `/var/tmp/patchew-tester-tmp-xcliqr1_/src'
ARCHIVE qemu.tgz
ARCHIVE dtc.tgz
COPY RUNNER
RUN test-quick in qemu:centos6
Packages installed:
SDL-devel-1.2.14-7.el6_7.1.x86_64
ccache-3.1.6-2.el6.x86_64
epel-release-6-8.noarch
gcc-4.4.7-17.el6.x86_64
git-1.7.1-4.el6_7.1.x86_64
glib2-devel-2.28.8-5.el6.x86_64
libfdt-devel-1.4.0-1.el6.x86_64
make-3.81-23.el6.x86_64
package g++ is not installed
pixman-devel-0.32.8-1.el6.x86_64
tar-1.23-15.el6_8.x86_64
zlib-devel-1.2.3-29.el6.x86_64
Environment variables:
PACKAGES=libfdt-devel ccache tar git make gcc g++ zlib-devel glib2-devel SDL-devel pixman-devel epel-release
HOSTNAME=0ca1e1148429
TERM=xterm
MAKEFLAGS= -j16
HISTSIZE=1000
J=16
USER=root
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
MAIL=/var/spool/mail/root
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
LANG=en_US.UTF-8
TARGET_LIST=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
FEATURES= dtc
DEBUG=
G_BROKEN_FILENAMES=1
CCACHE_HASHDIR=
_=/usr/bin/env
Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/var/tmp/qemu-build/install
No C++ compiler available; disabling C++ specific optional code
Install prefix /var/tmp/qemu-build/install
BIOS directory /var/tmp/qemu-build/install/share/qemu
binary directory /var/tmp/qemu-build/install/bin
library directory /var/tmp/qemu-build/install/lib
module directory /var/tmp/qemu-build/install/lib/qemu
libexec directory /var/tmp/qemu-build/install/libexec
include directory /var/tmp/qemu-build/install/include
config directory /var/tmp/qemu-build/install/etc
local state directory /var/tmp/qemu-build/install/var
Manual directory /var/tmp/qemu-build/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path /tmp/qemu-test/src
C compiler cc
Host C compiler cc
C++ compiler
Objective-C compiler cc
ARFLAGS rv
CFLAGS -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g
QEMU_CFLAGS -I/usr/include/pixman-1 -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv -Wendif-labels -Wmissing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-all
LDFLAGS -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g
make make
install install
python python -B
smbd /usr/sbin/smbd
module support no
host CPU x86_64
host big endian no
target list x86_64-softmmu aarch64-softmmu
tcg debug enabled no
gprof enabled no
sparse enabled no
strip binaries yes
profiler no
static build no
pixman system
SDL support yes (1.2.14)
GTK support no
GTK GL support no
VTE support no
TLS priority NORMAL
GNUTLS support no
GNUTLS rnd no
libgcrypt no
libgcrypt kdf no
nettle no
nettle kdf no
libtasn1 no
curses support no
virgl support no
curl support no
mingw32 support no
Audio drivers oss
Block whitelist (rw)
Block whitelist (ro)
VirtFS support no
VNC support yes
VNC SASL support no
VNC JPEG support no
VNC PNG support no
xen support no
brlapi support no
bluez support no
Documentation no
PIE yes
vde support no
netmap support no
Linux AIO support no
ATTR/XATTR support yes
Install blobs yes
KVM support yes
COLO support yes
RDMA support no
TCG interpreter no
fdt support yes
preadv support yes
fdatasync yes
madvise yes
posix_madvise yes
libcap-ng support no
vhost-net support yes
vhost-scsi support yes
vhost-vsock support yes
Trace backends log
spice support no
rbd support no
xfsctl support no
smartcard support no
libusb no
usb net redir no
OpenGL support no
OpenGL dmabufs no
libiscsi support no
libnfs support no
build guest agent yes
QGA VSS support no
QGA w32 disk info no
QGA MSI support no
seccomp support no
coroutine backend ucontext
coroutine pool yes
debug stack usage no
GlusterFS support no
Archipelago support no
gcov gcov
gcov enabled no
TPM support yes
libssh2 support no
TPM passthrough yes
QOM debugging yes
lzo support no
snappy support no
bzip2 support no
NUMA host support no
tcmalloc support no
jemalloc support no
avx2 optimization no
replication support yes
GEN x86_64-softmmu/config-devices.mak.tmp
GEN aarch64-softmmu/config-devices.mak.tmp
GEN config-host.h
GEN qemu-options.def
GEN qmp-commands.h
GEN qapi-types.h
GEN qapi-visit.h
GEN qapi-event.h
GEN qmp-introspect.h
GEN x86_64-softmmu/config-devices.mak
GEN aarch64-softmmu/config-devices.mak
GEN module_block.h
GEN tests/test-qapi-types.h
GEN tests/test-qapi-visit.h
GEN tests/test-qmp-commands.h
GEN tests/test-qapi-event.h
GEN tests/test-qmp-introspect.h
GEN config-all-devices.mak
GEN trace/generated-tracers.h
GEN trace/generated-tcg-tracers.h
GEN trace/generated-helpers-wrappers.h
GEN trace/generated-helpers.h
CC tests/qemu-iotests/socket_scm_helper.o
GEN qga/qapi-generated/qga-qapi-types.h
GEN qga/qapi-generated/qga-qapi-visit.h
GEN qga/qapi-generated/qga-qmp-commands.h
GEN qga/qapi-generated/qga-qapi-types.c
GEN qga/qapi-generated/qga-qapi-visit.c
GEN qga/qapi-generated/qga-qmp-marshal.c
GEN qmp-introspect.c
GEN qapi-types.c
GEN qapi-visit.c
GEN qapi-event.c
CC qapi/qapi-visit-core.o
CC qapi/qobject-output-visitor.o
CC qapi/qapi-dealloc-visitor.o
CC qapi/qobject-input-visitor.o
CC qapi/qmp-registry.o
CC qapi/qmp-dispatch.o
CC qapi/string-output-visitor.o
CC qapi/opts-visitor.o
CC qapi/string-input-visitor.o
CC qapi/qmp-event.o
CC qapi/qapi-clone-visitor.o
CC qapi/qapi-util.o
CC qobject/qnull.o
CC qobject/qint.o
CC qobject/qstring.o
CC qobject/qdict.o
CC qobject/qlist.o
CC qobject/qfloat.o
CC qobject/qbool.o
CC qobject/qjson.o
CC qobject/qobject.o
CC qobject/json-lexer.o
CC qobject/json-streamer.o
CC qobject/json-parser.o
GEN trace/generated-tracers.c
CC trace/control.o
CC trace/qmp.o
CC util/osdep.o
CC util/cutils.o
CC util/unicode.o
CC util/qemu-timer-common.o
CC util/bufferiszero.o
CC util/compatfd.o
CC util/event_notifier-posix.o
CC util/mmap-alloc.o
CC util/oslib-posix.o
CC util/qemu-openpty.o
CC util/qemu-thread-posix.o
CC util/memfd.o
CC util/envlist.o
CC util/path.o
CC util/module.o
CC util/bitmap.o
CC util/bitops.o
CC util/hbitmap.o
CC util/fifo8.o
CC util/acl.o
CC util/error.o
CC util/qemu-error.o
CC util/id.o
CC util/iov.o
CC util/qemu-config.o
CC util/qemu-sockets.o
CC util/uri.o
CC util/notify.o
CC util/qemu-option.o
CC util/qemu-progress.o
CC util/hexdump.o
CC util/crc32c.o
CC util/uuid.o
CC util/throttle.o
CC util/getauxval.o
CC util/readline.o
CC util/rcu.o
CC util/qemu-coroutine.o
CC util/qemu-coroutine-lock.o
CC util/qemu-coroutine-io.o
CC util/qemu-coroutine-sleep.o
CC util/coroutine-ucontext.o
CC util/buffer.o
CC util/timed-average.o
CC util/base64.o
CC util/log.o
CC util/qdist.o
CC util/qht.o
CC util/range.o
CC crypto/pbkdf-stub.o
CC stubs/arch-query-cpu-def.o
CC stubs/arch-query-cpu-model-expansion.o
CC stubs/arch-query-cpu-model-comparison.o
CC stubs/arch-query-cpu-model-baseline.o
CC stubs/bdrv-next-monitor-owned.o
CC stubs/blk-commit-all.o
CC stubs/blockdev-close-all-bdrv-states.o
CC stubs/cpu-get-clock.o
CC stubs/clock-warp.o
CC stubs/cpu-get-icount.o
CC stubs/dump.o
CC stubs/error-printf.o
CC stubs/fdset-add-fd.o
CC stubs/fdset-find-fd.o
CC stubs/fdset-get-fd.o
CC stubs/fdset-remove-fd.o
CC stubs/gdbstub.o
CC stubs/get-fd.o
CC stubs/get-next-serial.o
CC stubs/get-vm-name.o
CC stubs/iothread.o
CC stubs/is-daemonized.o
CC stubs/iothread-lock.o
CC stubs/machine-init-done.o
CC stubs/migr-blocker.o
CC stubs/mon-is-qmp.o
CC stubs/monitor-init.o
CC stubs/notify-event.o
CC stubs/qtest.o
CC stubs/replay.o
CC stubs/reset.o
CC stubs/replay-user.o
CC stubs/runstate-check.o
CC stubs/set-fd-handler.o
CC stubs/slirp.o
CC stubs/sysbus.o
CC stubs/trace-control.o
CC stubs/uuid.o
CC stubs/vm-stop.o
CC stubs/vmstate.o
CC stubs/cpus.o
CC stubs/kvm.o
CC stubs/qmp_pc_dimm_device_list.o
CC stubs/target-monitor-defs.o
CC stubs/target-get-monitor-def.o
CC stubs/vhost.o
CC stubs/iohandler.o
CC stubs/smbios_type_38.o
CC stubs/ipmi.o
CC stubs/pc_madt_cpu_entry.o
CC stubs/migration-colo.o
CC contrib/ivshmem-client/ivshmem-client.o
CC contrib/ivshmem-client/main.o
CC contrib/ivshmem-server/ivshmem-server.o
CC contrib/ivshmem-server/main.o
CC qemu-nbd.o
CC async.o
CC thread-pool.o
CC block.o
CC blockjob.o
CC main-loop.o
CC iohandler.o
CC qemu-timer.o
CC aio-posix.o
CC qemu-io-cmds.o
CC replication.o
CC block/raw_bsd.o
CC block/qcow.o
CC block/vdi.o
CC block/vmdk.o
CC block/cloop.o
CC block/bochs.o
CC block/vpc.o
CC block/vvfat.o
CC block/dmg.o
CC block/qcow2.o
CC block/qcow2-refcount.o
CC block/qcow2-cluster.o
CC block/qcow2-snapshot.o
CC block/qcow2-cache.o
CC block/qcow2-bitmap.o
CC block/qed.o
CC block/qed-gencb.o
CC block/qed-l2-cache.o
CC block/qed-table.o
CC block/qed-cluster.o
CC block/qed-check.o
CC block/vhdx.o
CC block/vhdx-endian.o
/tmp/qemu-test/src/block/qcow2-bitmap.c:91: error: redefinition of typedef ‘Qcow2Bitmap’
/tmp/qemu-test/src/block/qcow2.h:245: note: previous declaration of ‘Qcow2Bitmap’ was here
make: *** [block/qcow2-bitmap.o] Error 1
make: *** Waiting for unfinished jobs....
make[1]: *** [docker-run] Error 2
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-xcliqr1_/src'
make: *** [docker-run-test-quick@centos6] Error 2
=== OUTPUT END ===
Test command exited with code: 2
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps
2016-12-21 15:29 ` [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps no-reply
@ 2016-12-21 16:20 ` Vladimir Sementsov-Ogievskiy
0 siblings, 0 replies; 32+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-12-21 16:20 UTC (permalink / raw)
To: qemu-devel
Cc: famz, qemu-block, kwolf, armbru, mreitz, stefanha, pbonzini, den, jsnow
Last patch breaks it.
Fix will look like
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index b9f3d62..dd987a1 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -79,7 +79,7 @@ typedef struct Qcow2BitmapTable {
} Qcow2BitmapTable;
typedef QSIMPLEQ_HEAD(Qcow2BitmapTableList, Qcow2BitmapTable)
Qcow2BitmapTableList;
-typedef struct Qcow2Bitmap {
+struct Qcow2Bitmap {
Qcow2BitmapTable table;
uint32_t flags;
uint8_t granularity_bits;
@@ -88,7 +88,7 @@ typedef struct Qcow2Bitmap {
BdrvDirtyBitmap *dirty_bitmap;
QSIMPLEQ_ENTRY(Qcow2Bitmap) entry;
-} Qcow2Bitmap;
+};
typedef enum BitmapType {
BT_DIRTY_TRACKING_BITMAP = 1
21.12.2016 18:29, no-reply@patchew.org wrote:
> Hi,
>
> Your series failed automatic build test. Please find the testing commands and
> their output below. If you have docker installed, you can probably reproduce it
> locally.
>
> Type: series
> Message-id: 1482332102-131788-1-git-send-email-vsementsov@virtuozzo.com
> Subject: [Qemu-devel] [PATCH v10 00/24] qcow2: persistent dirty bitmaps
>
> === TEST SCRIPT BEGIN ===
> #!/bin/bash
> set -e
> git submodule update --init dtc
> # Let docker tests dump environment info
> export SHOW_ENV=1
> export J=16
> make docker-test-quick@centos6
> make docker-test-mingw@fedora
> make docker-test-build@min-glib
> === TEST SCRIPT END ===
>
> Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
> Switched to a new branch 'test'
> ef76b98 qcow2-bitmap: cache bitmap list in BDRVQcow2State
> a357743 qcow2: add .bdrv_remove_persistent_dirty_bitmap
> 8310147 block/dirty-bitmap: deep release dirty bitmaps
> 089c498 qcow2-bitmap: refcounts
> fbfe535 qcow2-refcount: rename inc_refcounts() and make it public
> 275eed2 iotests: test qcow2 persistent dirty bitmap
> 96a9ce0 qmp: add x-debug-block-dirty-bitmap-sha256
> 3e6dd36 qmp: add autoload parameter to block-dirty-bitmap-add
> b5418b0 qmp: add persistent flag to block-dirty-bitmap-add
> f624bc8 qcow2: add .bdrv_can_store_new_dirty_bitmap
> 4d9d7ac block: add bdrv_can_store_new_dirty_bitmap
> 87d58da qcow2: add .bdrv_store_persistent_dirty_bitmaps()
> 5fbebdd block/dirty-bitmap: add bdrv_dirty_bitmap_next()
> 731f771 block: introduce persistent dirty bitmaps
> 714509e block/dirty-bitmap: add autoload field to BdrvDirtyBitmap
> 7ff58fc qcow2: add .bdrv_load_autoloading_dirty_bitmaps
> 7a56b01 block: introduce auto-loading bitmaps
> 566981a qcow2: add bitmaps extension
> ec285c1 block/dirty-bitmap: add deserialize_ones func
> d4759b3 block: fix bdrv_dirty_bitmap_granularity signature
> e5331b0 tests: add hbitmap iter test
> e1b9104 hbitmap: improve dirty iter
> 7dc36ce specs/qcow2: do not use wording 'bitmap header'
> 3a6086b specs/qcow2: fix bitmap granularity qemu-specific note
>
> === OUTPUT BEGIN ===
> Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
> Cloning into 'dtc'...
> Submodule path 'dtc': checked out '65cc4d2748a2c2e6f27f1cf39e07a5dbabd80ebf'
> BUILD centos6
> make[1]: Entering directory `/var/tmp/patchew-tester-tmp-xcliqr1_/src'
> ARCHIVE qemu.tgz
> ARCHIVE dtc.tgz
> COPY RUNNER
> RUN test-quick in qemu:centos6
> Packages installed:
> SDL-devel-1.2.14-7.el6_7.1.x86_64
> ccache-3.1.6-2.el6.x86_64
> epel-release-6-8.noarch
> gcc-4.4.7-17.el6.x86_64
> git-1.7.1-4.el6_7.1.x86_64
> glib2-devel-2.28.8-5.el6.x86_64
> libfdt-devel-1.4.0-1.el6.x86_64
> make-3.81-23.el6.x86_64
> package g++ is not installed
> pixman-devel-0.32.8-1.el6.x86_64
> tar-1.23-15.el6_8.x86_64
> zlib-devel-1.2.3-29.el6.x86_64
>
> Environment variables:
> PACKAGES=libfdt-devel ccache tar git make gcc g++ zlib-devel glib2-devel SDL-devel pixman-devel epel-release
> HOSTNAME=0ca1e1148429
> TERM=xterm
> MAKEFLAGS= -j16
> HISTSIZE=1000
> J=16
> USER=root
> CCACHE_DIR=/var/tmp/ccache
> EXTRA_CONFIGURE_OPTS=
> V=
> SHOW_ENV=1
> MAIL=/var/spool/mail/root
> PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
> PWD=/
> LANG=en_US.UTF-8
> TARGET_LIST=
> HISTCONTROL=ignoredups
> SHLVL=1
> HOME=/root
> TEST_DIR=/tmp/qemu-test
> LOGNAME=root
> LESSOPEN=||/usr/bin/lesspipe.sh %s
> FEATURES= dtc
> DEBUG=
> G_BROKEN_FILENAMES=1
> CCACHE_HASHDIR=
> _=/usr/bin/env
>
> Configure options:
> --enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/var/tmp/qemu-build/install
> No C++ compiler available; disabling C++ specific optional code
> Install prefix /var/tmp/qemu-build/install
> BIOS directory /var/tmp/qemu-build/install/share/qemu
> binary directory /var/tmp/qemu-build/install/bin
> library directory /var/tmp/qemu-build/install/lib
> module directory /var/tmp/qemu-build/install/lib/qemu
> libexec directory /var/tmp/qemu-build/install/libexec
> include directory /var/tmp/qemu-build/install/include
> config directory /var/tmp/qemu-build/install/etc
> local state directory /var/tmp/qemu-build/install/var
> Manual directory /var/tmp/qemu-build/install/share/man
> ELF interp prefix /usr/gnemul/qemu-%M
> Source path /tmp/qemu-test/src
> C compiler cc
> Host C compiler cc
> C++ compiler
> Objective-C compiler cc
> ARFLAGS rv
> CFLAGS -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g
> QEMU_CFLAGS -I/usr/include/pixman-1 -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv -Wendif-labels -Wmissing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-all
> LDFLAGS -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g
> make make
> install install
> python python -B
> smbd /usr/sbin/smbd
> module support no
> host CPU x86_64
> host big endian no
> target list x86_64-softmmu aarch64-softmmu
> tcg debug enabled no
> gprof enabled no
> sparse enabled no
> strip binaries yes
> profiler no
> static build no
> pixman system
> SDL support yes (1.2.14)
> GTK support no
> GTK GL support no
> VTE support no
> TLS priority NORMAL
> GNUTLS support no
> GNUTLS rnd no
> libgcrypt no
> libgcrypt kdf no
> nettle no
> nettle kdf no
> libtasn1 no
> curses support no
> virgl support no
> curl support no
> mingw32 support no
> Audio drivers oss
> Block whitelist (rw)
> Block whitelist (ro)
> VirtFS support no
> VNC support yes
> VNC SASL support no
> VNC JPEG support no
> VNC PNG support no
> xen support no
> brlapi support no
> bluez support no
> Documentation no
> PIE yes
> vde support no
> netmap support no
> Linux AIO support no
> ATTR/XATTR support yes
> Install blobs yes
> KVM support yes
> COLO support yes
> RDMA support no
> TCG interpreter no
> fdt support yes
> preadv support yes
> fdatasync yes
> madvise yes
> posix_madvise yes
> libcap-ng support no
> vhost-net support yes
> vhost-scsi support yes
> vhost-vsock support yes
> Trace backends log
> spice support no
> rbd support no
> xfsctl support no
> smartcard support no
> libusb no
> usb net redir no
> OpenGL support no
> OpenGL dmabufs no
> libiscsi support no
> libnfs support no
> build guest agent yes
> QGA VSS support no
> QGA w32 disk info no
> QGA MSI support no
> seccomp support no
> coroutine backend ucontext
> coroutine pool yes
> debug stack usage no
> GlusterFS support no
> Archipelago support no
> gcov gcov
> gcov enabled no
> TPM support yes
> libssh2 support no
> TPM passthrough yes
> QOM debugging yes
> lzo support no
> snappy support no
> bzip2 support no
> NUMA host support no
> tcmalloc support no
> jemalloc support no
> avx2 optimization no
> replication support yes
> GEN x86_64-softmmu/config-devices.mak.tmp
> GEN aarch64-softmmu/config-devices.mak.tmp
> GEN config-host.h
> GEN qemu-options.def
> GEN qmp-commands.h
> GEN qapi-types.h
> GEN qapi-visit.h
> GEN qapi-event.h
> GEN qmp-introspect.h
> GEN x86_64-softmmu/config-devices.mak
> GEN aarch64-softmmu/config-devices.mak
> GEN module_block.h
> GEN tests/test-qapi-types.h
> GEN tests/test-qapi-visit.h
> GEN tests/test-qmp-commands.h
> GEN tests/test-qapi-event.h
> GEN tests/test-qmp-introspect.h
> GEN config-all-devices.mak
> GEN trace/generated-tracers.h
> GEN trace/generated-tcg-tracers.h
> GEN trace/generated-helpers-wrappers.h
> GEN trace/generated-helpers.h
> CC tests/qemu-iotests/socket_scm_helper.o
> GEN qga/qapi-generated/qga-qapi-types.h
> GEN qga/qapi-generated/qga-qapi-visit.h
> GEN qga/qapi-generated/qga-qmp-commands.h
> GEN qga/qapi-generated/qga-qapi-types.c
> GEN qga/qapi-generated/qga-qapi-visit.c
> GEN qga/qapi-generated/qga-qmp-marshal.c
> GEN qmp-introspect.c
> GEN qapi-types.c
> GEN qapi-visit.c
> GEN qapi-event.c
> CC qapi/qapi-visit-core.o
> CC qapi/qobject-output-visitor.o
> CC qapi/qapi-dealloc-visitor.o
> CC qapi/qobject-input-visitor.o
> CC qapi/qmp-registry.o
> CC qapi/qmp-dispatch.o
> CC qapi/string-output-visitor.o
> CC qapi/opts-visitor.o
> CC qapi/string-input-visitor.o
> CC qapi/qmp-event.o
> CC qapi/qapi-clone-visitor.o
> CC qapi/qapi-util.o
> CC qobject/qnull.o
> CC qobject/qint.o
> CC qobject/qstring.o
> CC qobject/qdict.o
> CC qobject/qlist.o
> CC qobject/qfloat.o
> CC qobject/qbool.o
> CC qobject/qjson.o
> CC qobject/qobject.o
> CC qobject/json-lexer.o
> CC qobject/json-streamer.o
> CC qobject/json-parser.o
> GEN trace/generated-tracers.c
> CC trace/control.o
> CC trace/qmp.o
> CC util/osdep.o
> CC util/cutils.o
> CC util/unicode.o
> CC util/qemu-timer-common.o
> CC util/bufferiszero.o
> CC util/compatfd.o
> CC util/event_notifier-posix.o
> CC util/mmap-alloc.o
> CC util/oslib-posix.o
> CC util/qemu-openpty.o
> CC util/qemu-thread-posix.o
> CC util/memfd.o
> CC util/envlist.o
> CC util/path.o
> CC util/module.o
> CC util/bitmap.o
> CC util/bitops.o
> CC util/hbitmap.o
> CC util/fifo8.o
> CC util/acl.o
> CC util/error.o
> CC util/qemu-error.o
> CC util/id.o
> CC util/iov.o
> CC util/qemu-config.o
> CC util/qemu-sockets.o
> CC util/uri.o
> CC util/notify.o
> CC util/qemu-option.o
> CC util/qemu-progress.o
> CC util/hexdump.o
> CC util/crc32c.o
> CC util/uuid.o
> CC util/throttle.o
> CC util/getauxval.o
> CC util/readline.o
> CC util/rcu.o
> CC util/qemu-coroutine.o
> CC util/qemu-coroutine-lock.o
> CC util/qemu-coroutine-io.o
> CC util/qemu-coroutine-sleep.o
> CC util/coroutine-ucontext.o
> CC util/buffer.o
> CC util/timed-average.o
> CC util/base64.o
> CC util/log.o
> CC util/qdist.o
> CC util/qht.o
> CC util/range.o
> CC crypto/pbkdf-stub.o
> CC stubs/arch-query-cpu-def.o
> CC stubs/arch-query-cpu-model-expansion.o
> CC stubs/arch-query-cpu-model-comparison.o
> CC stubs/arch-query-cpu-model-baseline.o
> CC stubs/bdrv-next-monitor-owned.o
> CC stubs/blk-commit-all.o
> CC stubs/blockdev-close-all-bdrv-states.o
> CC stubs/cpu-get-clock.o
> CC stubs/clock-warp.o
> CC stubs/cpu-get-icount.o
> CC stubs/dump.o
> CC stubs/error-printf.o
> CC stubs/fdset-add-fd.o
> CC stubs/fdset-find-fd.o
> CC stubs/fdset-get-fd.o
> CC stubs/fdset-remove-fd.o
> CC stubs/gdbstub.o
> CC stubs/get-fd.o
> CC stubs/get-next-serial.o
> CC stubs/get-vm-name.o
> CC stubs/iothread.o
> CC stubs/is-daemonized.o
> CC stubs/iothread-lock.o
> CC stubs/machine-init-done.o
> CC stubs/migr-blocker.o
> CC stubs/mon-is-qmp.o
> CC stubs/monitor-init.o
> CC stubs/notify-event.o
> CC stubs/qtest.o
> CC stubs/replay.o
> CC stubs/reset.o
> CC stubs/replay-user.o
> CC stubs/runstate-check.o
> CC stubs/set-fd-handler.o
> CC stubs/slirp.o
> CC stubs/sysbus.o
> CC stubs/trace-control.o
> CC stubs/uuid.o
> CC stubs/vm-stop.o
> CC stubs/vmstate.o
> CC stubs/cpus.o
> CC stubs/kvm.o
> CC stubs/qmp_pc_dimm_device_list.o
> CC stubs/target-monitor-defs.o
> CC stubs/target-get-monitor-def.o
> CC stubs/vhost.o
> CC stubs/iohandler.o
> CC stubs/smbios_type_38.o
> CC stubs/ipmi.o
> CC stubs/pc_madt_cpu_entry.o
> CC stubs/migration-colo.o
> CC contrib/ivshmem-client/ivshmem-client.o
> CC contrib/ivshmem-client/main.o
> CC contrib/ivshmem-server/ivshmem-server.o
> CC contrib/ivshmem-server/main.o
> CC qemu-nbd.o
> CC async.o
> CC thread-pool.o
> CC block.o
> CC blockjob.o
> CC main-loop.o
> CC iohandler.o
> CC qemu-timer.o
> CC aio-posix.o
> CC qemu-io-cmds.o
> CC replication.o
> CC block/raw_bsd.o
> CC block/qcow.o
> CC block/vdi.o
> CC block/vmdk.o
> CC block/cloop.o
> CC block/bochs.o
> CC block/vpc.o
> CC block/vvfat.o
> CC block/dmg.o
> CC block/qcow2.o
> CC block/qcow2-refcount.o
> CC block/qcow2-cluster.o
> CC block/qcow2-snapshot.o
> CC block/qcow2-cache.o
> CC block/qcow2-bitmap.o
> CC block/qed.o
> CC block/qed-gencb.o
> CC block/qed-l2-cache.o
> CC block/qed-table.o
> CC block/qed-cluster.o
> CC block/qed-check.o
> CC block/vhdx.o
> CC block/vhdx-endian.o
> /tmp/qemu-test/src/block/qcow2-bitmap.c:91: error: redefinition of typedef ‘Qcow2Bitmap’
> /tmp/qemu-test/src/block/qcow2.h:245: note: previous declaration of ‘Qcow2Bitmap’ was here
> make: *** [block/qcow2-bitmap.o] Error 1
> make: *** Waiting for unfinished jobs....
> make[1]: *** [docker-run] Error 2
> make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-xcliqr1_/src'
> make: *** [docker-run-test-quick@centos6] Error 2
> === OUTPUT END ===
>
> Test command exited with code: 2
>
>
> ---
> Email generated automatically by Patchew [http://patchew.org/].
> Please send your feedback to patchew-devel@freelists.org
--
Best regards,
Vladimir
^ permalink raw reply related [flat|nested] 32+ messages in thread