Signed-off-by: Benoit Canet <ben...@irqsave.net> --- block/qcow2-dedup.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++- block/qcow2.h | 6 +++- 2 files changed, 101 insertions(+), 2 deletions(-)
diff --git a/block/qcow2-dedup.c b/block/qcow2-dedup.c index 0daf77e..ffbf866 100644 --- a/block/qcow2-dedup.c +++ b/block/qcow2-dedup.c @@ -251,6 +251,7 @@ static int qcow2_dedup_link_l2(BlockDriverState *bs, static int qcow2_clear_l2_copied_flag_if_needed(BlockDriverState *bs, QCowHashInfo *hash_info) { + BDRVQcowState *s = bs->opaque; int ret = 0; uint64_t first_logical_sect = hash_info->first_logical_sect; @@ -273,7 +274,8 @@ static int qcow2_clear_l2_copied_flag_if_needed(BlockDriverState *bs, /* remember that we don't need to clear QCOW_OFLAG_COPIED again */ hash_info->first_logical_sect = first_logical_sect; - return 0; + /* clear the QCOW_OFLAG_COPIED flag from disk */ + return qcow2_store_insert(bs, &s->key_value_store, hash_info); } /* This function deduplicate a cluster @@ -534,3 +536,96 @@ exit: return deduped_clusters_nr * s->cluster_sectors - start_index; } + +static inline bool is_hash_info_empty(QCowHashInfo *hash_info) +{ + return hash_info->physical_sect & QCOW_DEDUP_FLAG_EMPTY; +} + +/* This function store a hash information to disk and RAM + * + * @hash_info: the QCowHashInfo to process + * @logical_sect: the logical sector of the cluster seen by the guest + * @physical_sect: the physical sector of the stored cluster + * @ret: 0 on success, negative on error + */ +static int qcow2_store_hash(BlockDriverState *bs, + QCowHashInfo *hash_info, + uint64_t logical_sect, + uint64_t physical_sect) +{ + BDRVQcowState *s = bs->opaque; + int ret = 0; + + ret = qcow2_store_get(bs, &s->key_value_store, hash_info); + + /* no hash info found in store or error */ + if (ret <= 0) { + return ret; + } + + /* the hash info information are already completed */ + if (!is_hash_info_empty(hash_info)) { + return 0; + } + + /* Remember that this QCowHashInfo represents the first occurrence of the + * cluster so we will be able to clear QCOW_OFLAG_COPIED from the L2 table + * entry when refcount will go > 1. + */ + logical_sect = logical_sect | QCOW_OFLAG_COPIED; + + /* fill the missing fields of the hash info */ + hash_info->physical_sect = physical_sect; + hash_info->first_logical_sect = logical_sect; + + /* write the hash into the key value store */ + return qcow2_store_insert(bs, &s->key_value_store, hash_info); +} + +/* This function store the hashes of the clusters which are not duplicated + * + * @ds: The deduplication state + * @count: the number of dedup hash to process + * @logical_sect: logical offset of the first cluster (in sectors) + * @physical_sect: offset of the first cluster (in sectors) + * @ret: 0 on succes, errno on error + */ +int qcow2_dedup_store_new_hashes(BlockDriverState *bs, + QCowDedupState *ds, + int count, + uint64_t logical_sect, + uint64_t physical_sect) +{ + int ret = 0; + int i = 0; + BDRVQcowState *s = bs->opaque; + QCowHashElement *dedup_hash, *next_dedup_hash; + + /* round values on cluster boundaries for easier cluster deletion */ + logical_sect = logical_sect & ~(s->cluster_sectors - 1); + physical_sect = physical_sect & ~(s->cluster_sectors - 1); + + QTAILQ_FOREACH_SAFE(dedup_hash, &ds->undedupables, next, next_dedup_hash) { + + ret = qcow2_store_hash(bs, + &dedup_hash->hash_info, + logical_sect + i * s->cluster_sectors, + physical_sect + i * s->cluster_sectors); + + QTAILQ_REMOVE(&ds->undedupables, dedup_hash, next); + g_free(dedup_hash); + + if (ret < 0) { + break; + } + + i++; + + if (i == count) { + break; + } + } + + return ret; +} diff --git a/block/qcow2.h b/block/qcow2.h index 3346842..ff26e81 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -742,6 +742,10 @@ int qcow2_dedup(BlockDriverState *bs, uint64_t sector_num, uint8_t *data, int data_nr); - +int qcow2_dedup_store_new_hashes(BlockDriverState *bs, + QCowDedupState *ds, + int count, + uint64_t logical_sect, + uint64_t physical_sect); #endif -- 1.7.10.4