[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC V2 01/16] qcow2: Add qcow2_co_dedup_resume to restart
From: |
Benoît Canet |
Subject: |
[Qemu-devel] [RFC V2 01/16] qcow2: Add qcow2_co_dedup_resume to restart deduplication. |
Date: |
Wed, 6 Feb 2013 13:32:04 +0100 |
---
block/qcow2-dedup.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 180 insertions(+)
diff --git a/block/qcow2-dedup.c b/block/qcow2-dedup.c
index 0679a68..cd08594 100644
--- a/block/qcow2-dedup.c
+++ b/block/qcow2-dedup.c
@@ -34,6 +34,7 @@
#include <skeinApi.h>
#endif
+static void qcow2_dedup_reset(BlockDriverState *bs);
static int qcow2_dedup_read_write_hash(BlockDriverState *bs,
QCowHash *hash,
uint64_t *first_logical_sect,
@@ -1020,6 +1021,175 @@ bool qcow2_dedup_is_running(BlockDriverState *bs)
return s->has_dedup && s->dedup_status == DEDUP_STATUS_STARTED;
}
+static bool hash_is_null(QCowHash *hash)
+{
+ QCowHash null_hash;
+ memset(&null_hash.data, 0, HASH_LENGTH);
+ return !memcmp(hash->data, null_hash.data, HASH_LENGTH);
+}
+
+static void qcow2_dedup_insert_hash_node(BlockDriverState *bs,
+ QCowHashNode *hash_node)
+{
+ BDRVQcowState *s = bs->opaque;
+
+ g_tree_insert(s->dedup_tree_by_hash, &hash_node->hash, hash_node);
+ g_tree_insert(s->dedup_tree_by_sect, &hash_node->physical_sect, hash_node);
+}
+
+/* This load the QCowHashNode corresponding to a given cluster index into ram
+ *
+ * @index: index of the given physical sector
+ * @ret: 0 on succes, negative on error
+ */
+static int qcow2_load_cluster_hash(BlockDriverState *bs,
+ uint64_t index)
+{
+ BDRVQcowState *s = bs->opaque;
+ int ret = 0;
+ QCowHash hash;
+ uint64_t first_logical_sect;
+ QCowHashNode *hash_node;
+
+ /* get the hash */
+ ret = qcow2_dedup_read_write_hash(bs, &hash,
+ &first_logical_sect,
+ index * s->cluster_sectors,
+ false);
+
+ if (ret < 0) {
+ error_report("Failed to load deduplication hash.");
+ return ret;
+ }
+
+ /* if the hash is null don't load it */
+ if (hash_is_null(&hash)) {
+ return ret;
+ }
+
+ hash_node = qcow2_dedup_build_qcow_hash_node(&hash,
+ index * s->cluster_sectors,
+ first_logical_sect);
+ qcow2_dedup_insert_hash_node(bs, hash_node);
+
+ return 0;
+}
+
+/* Load all the actives hashes into RAM
+ *
+ * @ret: 0 on success, negative on error
+ */
+static int qcow2_load_valid_hashes(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t max_clusters, i;
+ int nb_hash_in_hash_block = s->hash_block_size / (HASH_LENGTH + 8);
+ int ret = 0;
+
+ max_clusters = s->dedup_table_size * nb_hash_in_hash_block;
+
+ /* load all the hash stored to disk in memory */
+ for (i = 0; i < max_clusters; i++) {
+ if (!(i % nb_hash_in_hash_block)) {
+ co_sleep_ns(rt_clock, s->dedup_co_delay);
+ }
+ qemu_co_mutex_lock(&s->lock);
+ ret = qcow2_load_cluster_hash(bs, i);
+ qemu_co_mutex_unlock(&s->lock);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int qcow2_drop_to_dedup_stale_hash(BlockDriverState *bs,
+ uint64_t index)
+{
+ int ret = 0;
+ bool to_dedup;
+ uint64_t physical_sect;
+
+ to_dedup = qcow2_is_cluster_to_dedup(bs, index, &physical_sect, &ret);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (!to_dedup) {
+ return 0;
+ }
+
+ qcow2_remove_hash_node_by_sector(bs, physical_sect);
+ return 0;
+}
+
+/* For each l2 entry marked as QCOW_OFLAG_TO_DEDUP drop the obsolete hash
+ * from the trees
+ *
+ * @ret: 0 on success, negative on error
+ */
+static int qcow2_drop_to_dedup_hashes(BlockDriverState *bs)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t i;
+ int ret = 0;
+
+ /* for each l2 entry */
+ for (i = 0; i < s->l2_size * s->l1_size; i++) {
+ if (!(i % s->l2_size)) {
+ co_sleep_ns(rt_clock, s->dedup_co_delay);
+ }
+ qemu_co_mutex_lock(&s->lock);
+ ret = qcow2_drop_to_dedup_stale_hash(bs, i);
+ qemu_co_mutex_unlock(&s->lock);
+
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This coroutine resume deduplication
+ *
+ * @data: the given BlockDriverState
+ * @ret: NULL
+ */
+static void coroutine_fn qcow2_co_dedup_resume(void *opaque)
+{
+ BlockDriverState *bs = opaque;
+ BDRVQcowState *s = bs->opaque;
+ int ret = 0;
+
+ ret = qcow2_load_valid_hashes(bs);
+
+ if (ret < 0) {
+ goto fail;
+ }
+
+ ret = qcow2_drop_to_dedup_hashes(bs);
+
+ if (ret < 0) {
+ goto fail;
+ }
+
+ qemu_co_mutex_lock(&s->lock);
+ s->dedup_status = DEDUP_STATUS_STARTED;
+ qemu_co_mutex_unlock(&s->lock);
+
+ return;
+
+fail:
+ qemu_co_mutex_lock(&s->lock);
+ s->dedup_status = DEDUP_STATUS_STOPPED;
+ qcow2_dedup_reset(bs);
+ qemu_co_mutex_unlock(&s->lock);
+}
+
static gint qcow2_dedup_compare_by_hash(gconstpointer a,
gconstpointer b,
gpointer data)
@@ -1089,6 +1259,12 @@ static void qcow2_dedup_free(BlockDriverState *bs)
g_tree_destroy(s->dedup_tree_by_hash);
}
+static void qcow2_dedup_reset(BlockDriverState *bs)
+{
+ qcow2_dedup_free(bs);
+ qcow2_dedup_alloc(bs);
+}
+
int qcow2_dedup_init(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
@@ -1109,6 +1285,10 @@ int qcow2_dedup_init(BlockDriverState *bs)
s->dedup_status = DEDUP_STATUS_STARTING;
+ /* resume deduplication */
+ s->dedup_resume_co = qemu_coroutine_create(qcow2_co_dedup_resume);
+ qemu_coroutine_enter(s->dedup_resume_co, bs);
+
return 0;
}
--
1.7.10.4
- [Qemu-devel] [RFC V2 00/16] QCOW2 deduplication metrics, Benoît Canet, 2013/02/06
- [Qemu-devel] [RFC V2 01/16] qcow2: Add qcow2_co_dedup_resume to restart deduplication.,
Benoît Canet <=
- [Qemu-devel] [RFC V2 03/16] qcow2: Add deduplication metrics structures., Benoît Canet, 2013/02/06
- [Qemu-devel] [RFC V2 05/16] qcow2: Collect unaligned writes missing data reads metric., Benoît Canet, 2013/02/06
- [Qemu-devel] [RFC V2 06/16] qcow2: Collect deduplicated cluster metric., Benoît Canet, 2013/02/06
- [Qemu-devel] [RFC V2 14/16] qcow2: Add qcow2_dedup_update_metrics to compute dedup RAM usage., Benoît Canet, 2013/02/06
- [Qemu-devel] [RFC V2 15/16] qcow2: returns deduplication metrics and status via bdrv_get_info(), Benoît Canet, 2013/02/06
- [Qemu-devel] [RFC V2 10/16] qcow2: Count cluster deleted metric, Benoît Canet, 2013/02/06
- [Qemu-devel] [RFC V2 11/16] qcow2: Count deduplication refcount overflow metric., Benoît Canet, 2013/02/06
- [Qemu-devel] [RFC V2 07/16] qcow2: Collect undeduplicated cluster metric., Benoît Canet, 2013/02/06