@@ -656,3 +656,48 @@ int qcow2_dedup_store_new_hashes(BlockDriverState *bs,
return ret;
}
+
+/* Clean the last reference to a given cluster when its refcount is zero
+ *
+ * @cluster_index: the index of the physical cluster
+ */
+void qcow2_dedup_destroy_hash(BlockDriverState *bs,
+ uint64_t cluster_index)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t offset = cluster_index * s->cluster_size;
+ QCowHashInfo hash_info;
+ uint8_t *buf;
+ int ret = 0;
+
+ /* allocate buffer */
+ buf = qemu_blockalign(bs, s->cluster_size);
+
+ /* read cluster from disk */
+ ret = bdrv_pread(bs->file, offset, buf, s->cluster_size);
+
+ /* error */
+ if (ret < 0) {
+ goto free_exit;
+ }
+
+ /* clear hash info */
+ memset(&hash_info, 0, sizeof(QCowHashInfo));
+
+ /* compute hash for the cluster */
+ ret = qcow2_compute_cluster_hash(bs,
+ &hash_info.hash,
+ buf);
+
+
+ /* error */
+ if (ret < 0) {
+ goto free_exit;
+ }
+
+ /* delete hash from key value store. It will not be deduplicated anymore */
+ qcow2_store_delete(bs, &s->key_value_store, &hash_info);
+
+free_exit:
+ qemu_vfree(buf);
+}
@@ -482,6 +482,9 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
ret = -EINVAL;
goto fail;
}
+ if (s->has_dedup && refcount == 0) {
+ qcow2_dedup_destroy_hash(bs, cluster_index);
+ }
if (refcount == 0 && cluster_index < s->free_cluster_index) {
s->free_cluster_index = cluster_index;
}
@@ -748,5 +748,7 @@ int qcow2_dedup_store_new_hashes(BlockDriverState *bs,
int count,
uint64_t logical_sect,
uint64_t physical_sect);
+void qcow2_dedup_destroy_hash(BlockDriverState *bs,
+ uint64_t cluster_index);
#endif
Signed-off-by: Benoit Canet <benoit@irqsave.net> --- block/qcow2-dedup.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ block/qcow2-refcount.c | 3 +++ block/qcow2.h | 2 ++ 3 files changed, 50 insertions(+)