A new physical cluster with the same hash value will be used for further occurence of this hash. --- block/qcow2-dedup.c | 32 ++++++++++++++++++++++++++++++++ block/qcow2-refcount.c | 3 +++ block/qcow2.h | 4 ++++ 3 files changed, 39 insertions(+)
diff --git a/block/qcow2-dedup.c b/block/qcow2-dedup.c index 25ecefa..9eba773 100644 --- a/block/qcow2-dedup.c +++ b/block/qcow2-dedup.c @@ -941,3 +941,35 @@ int qcow2_dedup_store_new_hashes(BlockDriverState *bs, return ret; } + +/* Force to use a new physical cluster and QCowHashNode when the refcount pass + * 2^16/2. + * + * @cluster_index: the index of the physical cluster + */ +void qcow2_dedup_refcount_half_max_reached(BlockDriverState *bs, + uint64_t cluster_index) +{ + BDRVQcowState *s = bs->opaque; + QCowHashNode *hash_node; + uint64_t physical_sect = cluster_index * s->cluster_sectors; + + hash_node = g_tree_lookup(s->dedup_tree_by_sect, &physical_sect); + + if (!hash_node) { + return; + } + + /* mark this hash so we won't load it anymore at startup after writing it */ + hash_node->first_logical_sect |= QCOW_FLAG_HALF_MAX_REFCOUNT; + + /* write to disk */ + qcow2_dedup_read_write_hash(bs, + &hash_node->hash, + &hash_node->first_logical_sect, + hash_node->physical_sect, + true); + + /* remove the QCowHashNode from ram so we won't use it anymore for dedup */ + qcow2_remove_hash_node(bs, hash_node); +} diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index b1ad112..ac396c4 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -489,6 +489,9 @@ int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, ret = -EINVAL; goto fail; } + if (s->has_dedup && deduplication && refcount >= 0xFFFF/2) { + qcow2_dedup_refcount_half_max_reached(bs, cluster_index); + } if (refcount == 0 && cluster_index < s->free_cluster_index) { s->free_cluster_index = cluster_index; } diff --git a/block/qcow2.h b/block/qcow2.h index 5c126be..ba10ed0 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -65,6 +65,8 @@ #define DEFAULT_CLUSTER_SIZE 65536 #define HASH_LENGTH 32 +/* indicate that this cluster refcount has reached its maximum value */ +#define QCOW_FLAG_HALF_MAX_REFCOUNT (1LL << 61) /* indicate that the hash structure is empty and miss offset */ #define QCOW_FLAG_EMPTY (1LL << 62) /* indicate that the cluster for this hash has QCOW_OFLAG_COPIED on disk */ @@ -499,5 +501,7 @@ int qcow2_dedup_store_new_hashes(BlockDriverState *bs, int count, uint64_t logical_sect, uint64_t physical_sect); +void qcow2_dedup_refcount_half_max_reached(BlockDriverState *bs, + uint64_t cluster_index); #endif -- 1.7.10.4