[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH v3 09/27] qcow2: Add l2_entry_size()
From: |
Alberto Garcia |
Subject: |
[RFC PATCH v3 09/27] qcow2: Add l2_entry_size() |
Date: |
Sun, 22 Dec 2019 12:36:50 +0100 |
qcow2 images with subclusters have 128-bit L2 entries. The first 64
bits contain the same information as traditional images and the last
64 bits form a bitmap with the status of each individual subcluster.
Because of that we cannot assume that L2 entries are sizeof(uint64_t)
anymore. This function returns the proper value for the image.
Signed-off-by: Alberto Garcia <address@hidden>
---
block/qcow2-cluster.c | 12 ++++++------
block/qcow2-refcount.c | 14 ++++++++------
block/qcow2.c | 8 ++++----
block/qcow2.h | 9 +++++++++
4 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 683c9569ad..851c7e6165 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -209,7 +209,7 @@ static int l2_load(BlockDriverState *bs, uint64_t offset,
uint64_t l2_offset, uint64_t **l2_slice)
{
BDRVQcow2State *s = bs->opaque;
- int start_of_slice = sizeof(uint64_t) *
+ int start_of_slice = l2_entry_size(s) *
(offset_to_l2_index(s, offset) - offset_to_l2_slice_index(s, offset));
return qcow2_cache_get(bs, s->l2_table_cache, l2_offset + start_of_slice,
@@ -277,7 +277,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index)
/* allocate a new l2 entry */
- l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
+ l2_offset = qcow2_alloc_clusters(bs, s->l2_size * l2_entry_size(s));
if (l2_offset < 0) {
ret = l2_offset;
goto fail;
@@ -301,7 +301,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index)
/* allocate a new entry in the l2 cache */
- slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+ slice_size2 = s->l2_slice_size * l2_entry_size(s);
n_slices = s->cluster_size / slice_size2;
trace_qcow2_l2_allocate_get_empty(bs, l1_index);
@@ -365,7 +365,7 @@ fail:
}
s->l1_table[l1_index] = old_l2_offset;
if (l2_offset > 0) {
- qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t),
+ qcow2_free_clusters(bs, l2_offset, s->l2_size * l2_entry_size(s),
QCOW2_DISCARD_ALWAYS);
}
return ret;
@@ -708,7 +708,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t
offset,
/* Then decrease the refcount of the old table */
if (l2_offset) {
- qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t),
+ qcow2_free_clusters(bs, l2_offset, s->l2_size * l2_entry_size(s),
QCOW2_DISCARD_OTHER);
}
@@ -1895,7 +1895,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState
*bs, uint64_t *l1_table,
int ret;
int i, j;
- slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+ slice_size2 = s->l2_slice_size * l2_entry_size(s);
n_slices = s->cluster_size / slice_size2;
if (!is_active_l1) {
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 223048569e..de85ed29a4 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1253,7 +1253,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
l2_slice = NULL;
l1_table = NULL;
l1_size2 = l1_size * sizeof(uint64_t);
- slice_size2 = s->l2_slice_size * sizeof(uint64_t);
+ slice_size2 = s->l2_slice_size * l2_entry_size(s);
n_slices = s->cluster_size / slice_size2;
s->cache_discards = true;
@@ -1604,7 +1604,7 @@ static int check_refcounts_l2(BlockDriverState *bs,
BdrvCheckResult *res,
int i, l2_size, nb_csectors, ret;
/* Read L2 table from disk */
- l2_size = s->l2_size * sizeof(uint64_t);
+ l2_size = s->l2_size * l2_entry_size(s);
l2_table = g_malloc(l2_size);
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size);
@@ -1679,15 +1679,16 @@ static int check_refcounts_l2(BlockDriverState *bs,
BdrvCheckResult *res,
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
offset);
if (fix & BDRV_FIX_ERRORS) {
+ int idx = i * (l2_entry_size(s) / sizeof(uint64_t));
uint64_t l2e_offset =
- l2_offset + (uint64_t)i * sizeof(uint64_t);
+ l2_offset + (uint64_t)i * l2_entry_size(s);
int ign = active ? QCOW2_OL_ACTIVE_L2 :
QCOW2_OL_INACTIVE_L2;
l2_entry = QCOW_OFLAG_ZERO;
set_l2_entry(s, l2_table, i, l2_entry);
ret = qcow2_pre_write_overlap_check(bs, ign,
- l2e_offset, sizeof(uint64_t), false);
+ l2e_offset, l2_entry_size(s), false);
if (ret < 0) {
fprintf(stderr, "ERROR: Overlap check failed\n");
res->check_errors++;
@@ -1697,7 +1698,8 @@ static int check_refcounts_l2(BlockDriverState *bs,
BdrvCheckResult *res,
}
ret = bdrv_pwrite_sync(bs->file, l2e_offset,
- &l2_table[i], sizeof(uint64_t));
+ &l2_table[idx],
+ l2_entry_size(s));
if (ret < 0) {
fprintf(stderr, "ERROR: Failed to overwrite L2 "
"table entry: %s\n", strerror(-ret));
@@ -1904,7 +1906,7 @@ static int check_oflag_copied(BlockDriverState *bs,
BdrvCheckResult *res,
}
ret = bdrv_pread(bs->file, l2_offset, l2_table,
- s->l2_size * sizeof(uint64_t));
+ s->l2_size * l2_entry_size(s));
if (ret < 0) {
fprintf(stderr, "ERROR: Could not read L2 table: %s\n",
strerror(-ret));
diff --git a/block/qcow2.c b/block/qcow2.c
index cbd857e9c7..e7607d90d4 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -868,7 +868,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts
*opts,
uint64_t max_l2_entries = DIV_ROUND_UP(virtual_disk_size, s->cluster_size);
/* An L2 table is always one cluster in size so the max cache size
* should be a multiple of the cluster size. */
- uint64_t max_l2_cache = ROUND_UP(max_l2_entries * sizeof(uint64_t),
+ uint64_t max_l2_cache = ROUND_UP(max_l2_entries * l2_entry_size(s),
s->cluster_size);
combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE);
@@ -1029,7 +1029,7 @@ static int qcow2_update_options_prepare(BlockDriverState
*bs,
}
}
- r->l2_slice_size = l2_cache_entry_size / sizeof(uint64_t);
+ r->l2_slice_size = l2_cache_entry_size / l2_entry_size(s);
r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size,
l2_cache_entry_size);
r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size,
@@ -1423,7 +1423,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState
*bs, QDict *options,
bs->encrypted = true;
}
- s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
+ s->l2_bits = s->cluster_bits - ctz32(l2_entry_size(s));
s->l2_size = 1 << s->l2_bits;
/* 2^(s->refcount_order - 3) is the refcount width in bytes */
s->refcount_block_bits = s->cluster_bits - (s->refcount_order - 3);
@@ -4115,7 +4115,7 @@ static int coroutine_fn
qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
* preallocation. All that matters is that we will not have to
allocate
* new refcount structures for them.) */
nb_new_l2_tables = DIV_ROUND_UP(nb_new_data_clusters,
- s->cluster_size / sizeof(uint64_t));
+ s->cluster_size / l2_entry_size(s));
/* The cluster range may not be aligned to L2 boundaries, so add one L2
* table for a potential head/tail */
nb_new_l2_tables++;
diff --git a/block/qcow2.h b/block/qcow2.h
index 523bc489a5..8be020bb76 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -80,6 +80,10 @@
#define QCOW_MAX_SUBCLUSTERS_PER_CLUSTER 32
+/* Size of normal and extended L2 entries */
+#define L2E_SIZE_NORMAL (sizeof(uint64_t))
+#define L2E_SIZE_EXTENDED (sizeof(uint64_t) * 2)
+
#define MIN_CLUSTER_BITS 9
#define MAX_CLUSTER_BITS 21
@@ -506,6 +510,11 @@ static inline bool has_subclusters(BDRVQcow2State *s)
return false;
}
+static inline size_t l2_entry_size(BDRVQcow2State *s)
+{
+ return has_subclusters(s) ? L2E_SIZE_EXTENDED : L2E_SIZE_NORMAL;
+}
+
static inline uint64_t get_l2_entry(BDRVQcow2State *s, uint64_t *l2_slice,
int idx)
{
--
2.20.1
- [RFC PATCH v3 08/27] qcow2: Add offset_to_sc_index(), (continued)
- [RFC PATCH v3 08/27] qcow2: Add offset_to_sc_index(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 19/27] qcow2: Add subcluster support to expand_zero_clusters_in_l1(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 21/27] qcow2: Update L2 bitmap in qcow2_alloc_cluster_link_l2(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 06/27] qcow2: Add dummy has_subclusters() function, Alberto Garcia, 2019/12/22
- [RFC PATCH v3 02/27] qcow2: Split cluster_needs_cow() out of count_cow_clusters(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 13/27] qcow2: Handle QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC, Alberto Garcia, 2019/12/22
- [RFC PATCH v3 15/27] qcow2: Add subcluster support to qcow2_get_cluster_offset(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 20/27] qcow2: Fix offset calculation in handle_dependencies(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 23/27] qcow2: Add subcluster support to handle_alloc_space(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 05/27] qcow2: Document the Extended L2 Entries feature, Alberto Garcia, 2019/12/22
- [RFC PATCH v3 09/27] qcow2: Add l2_entry_size(),
Alberto Garcia <=
- [RFC PATCH v3 12/27] qcow2: Replace QCOW2_CLUSTER_* with QCOW2_SUBCLUSTER_*, Alberto Garcia, 2019/12/22
- [RFC PATCH v3 26/27] qcow2: Add subcluster support to qcow2_measure(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 14/27] qcow2: Add subcluster support to calculate_l2_meta(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 04/27] qcow2: Add get_l2_entry() and set_l2_entry(), Alberto Garcia, 2019/12/22
- [RFC PATCH v3 25/27] qcow2: Add the 'extended_l2' option and the QCOW2_INCOMPAT_EXTL2 bit, Alberto Garcia, 2019/12/22