diff --git a/block/Makefile.objs b/block/Makefile.objs
index cafd4f8..2d1a269 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -1,6 +1,6 @@
 block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
 block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
-block-obj-y += qcow2-journal.o qcow2-log-store.o qcow2-hash-store.o
+block-obj-y += qcow2-journal.o qcow2-log-store.o qcow2-hash-store.o qcow2-store.o
 block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
 block-obj-y += qed-check.o
 block-obj-y += vhdx.o
diff --git a/block/qcow2-store.c b/block/qcow2-store.c
new file mode 100644
index 0000000..8e3fad5
--- /dev/null
+++ b/block/qcow2-store.c
@@ -0,0 +1,771 @@
+/*
+ * QCOW2 key value store for SSD storage
+ *
+ * Copyright (C) Nodalink, SARL. 2013
+ *
+ * Author:
+ *   Benoît Canet <benoit.canet@irqsave.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "block/block_int.h"
+#include "block/qcow2.h"
+
+/* The qcow2_store combine the qcow2_log_store with the qcow2_hash_store->
+ *
+ * insertions:
+ * Entries are inserted in the qcow2_log_store which delegate writing to disk
+ * to the qcow2_journal.
+ * When full the qcow2_log_store is frozen into an incarnation and given to the
+ * qcow2_hash_store-> A new qcow2_log store is then created
+ *
+ * deletions:
+ * Deletions are insertions with an additional flag set and a mandatory
+ * write flush of the journal: loosing an insertion is not a problem whereas
+ * loosing a deletion is a problem.
+ *
+ * queries:
+ * The log store is first queried and if the entry is not found in it the hash
+ * store is queried.
+ * When queried the hash store it will check for the presence of the
+ * QCowHashInfo in every incarnation starting from the youngest to the oldest.
+ *
+ * fifo:
+ * A user configurable setting allow the qcow2_store to act as a fifo.
+ * the oldest QCowHashInfos stored in it will be dropped an incarnation at once.
+ * Loosing the oldest QCowHashInfo won't corrupt the dedup metadata the only
+ * risk if to make to dedup ratio lower.
+ *
+ * algorithm:
+ * This code is an implementation of the first two stages of the SILT paper.
+ * The third stage was dropped to lower the complexity of the code
+ * The idea of behaving as a FIFO and the notion of incarnations comes from
+ * BufferHash and is handy to help reducing RAM consumption.
+ *
+ * SILT: www.cs.cmu.edu/~dga/papers/silt-sosp2011.pdf
+ * BufferHash: research.microsoft.com/en-us/people/sumann/bufferhash-nsdi10.pdf
+ */
+
+/* This function initialize a key value store
+ *
+ * @store: the store to initialize
+ * @order: the bit order
+ */
+static void qcow2_store_init(BlockDriverState *bs,
+                             QCowStore *store,
+                             uint32_t order)
+{
+    store->order = order;
+    qemu_co_mutex_init(&store->insert_lock);
+    qcow2_log_store_init(bs, &store->log_store, order);
+    qcow2_log_store_init(bs, &store->frozen_log_store, order);
+    qcow2_hash_store_init(&store->hash_store, order);
+}
+
+/* This function cleanup a key value store
+ *
+ * @store: the store to cleanup
+ */
+void qcow2_store_cleanup(QCowStore *store)
+{
+    qcow2_log_store_cleanup(&store->log_store);
+    qcow2_log_store_cleanup(&store->frozen_log_store);
+    qcow2_hash_store_cleanup(&store->hash_store);
+}
+
+/* This function look for a given hash info in the store
+ *
+ *
+ * @store:     the QCowStore to lookup into
+ * @hash_info: the QCowHashInfo to complete : at last the hash must be filled.
+ * @ret:       1 on successfull lookup, 0 if not found, -errno on error
+ */
+int qcow2_store_get(BlockDriverState *bs, QCowStore *store,
+                    QCowHashInfo *hash_info)
+{
+    bool found;
+    int ret = 0;
+
+    /* we do the same query from the youngest to the oldest store */
+
+    found = qcow2_log_store_get(&store->log_store, hash_info);
+
+    if (found) {
+        goto exit;
+    }
+
+    if (store->freezing) {
+         found = qcow2_log_store_get(&store->frozen_log_store, hash_info);
+    }
+
+    /* found or error */
+    if (found) {
+        goto exit;
+    }
+
+    ret = qcow2_hash_store_get(bs, &store->hash_store, hash_info);
+
+exit:
+    /* if nothing found or error */
+    if (!found && ret <= 0) {
+        return ret;
+    }
+
+    /* if hash info found but deleted from store return not found */
+    if (hash_info->first_logical_sect & QCOW_DEDUP_DELETED) {
+        return 0;
+    }
+
+    return 1;
+}
+
+/* this structure is used between the two following functions */
+typedef struct {
+    BlockDriverState *bs;
+    QCowStore *store;
+} QCowIncarnateArgs;
+
+/* This coroutine convert a log store into an incarnation
+ *
+ * While doing this convertion we take care of two things :
+ *
+ * -not allocating QCOW2 disk space while the guest is frozen
+ * -not reseting the freezing flag to false while the guest is frozen
+ *
+ * All operations in between these two steps can be done freely as they are only
+ * writes on an already allocated disk space area.
+ *
+ * As long a the freezing flag is set to true the target of the migration would
+ * restart the freeze cleanly.
+ *
+ * @opaque: the function arguments (bs, log_store and hash_store)
+ */
+static void coroutine_fn qcow2_store_co_incarnate(void *opaque)
+{
+    QCowIncarnateArgs *args = (QCowIncarnateArgs *) opaque;
+    int64_t ret = 0;
+    int64_t offset;
+    uint64_t filter_size;
+    uint64_t incarnation_size;
+    uint8_t *filter;
+
+    BlockDriverState *bs               = args->bs;
+    BDRVQcowState    *s                = bs->opaque;
+    QCowStore        *store            = args->store;
+    QCowLogStore     *frozen_log_store = &store->frozen_log_store;
+    QCowHashStore    *hash_store       = &store->hash_store;
+
+    /* avoid disk allocations while the guest is suspended or migrating */
+    co_sleep_ns(vm_clock, 1);
+
+    /* allocate a new incarnation disk space or get it from limbo */
+    offset = qcow2_hash_store_get_incarnation_offset(bs,
+                                                     hash_store);
+
+    if (offset < 0) {
+        /* save the errno so the rest of QCOW2 will know */
+        s->freeze_errno = offset;
+        return;
+    }
+
+    /* save new config */
+    ret = qcow2_store_save(bs, store);
+
+    if (ret < 0) {
+        goto deallocate_exit;
+    }
+
+    /* build the in ram filter and dump it to disk */
+    ret = qcow2_log_store_freeze_filter(bs,
+                                        frozen_log_store,
+                                        offset,
+                                        &filter);
+
+    if (ret < 0) {
+        goto deallocate_exit;
+    }
+
+    /* reorder the journal contained hashes and write them to disk */
+    filter_size = qcow2_hash_store_filter_size(hash_store->order);
+    ret = qcow2_log_store_freeze_hash_table(bs,
+                                            frozen_log_store,
+                                            offset + filter_size);
+
+    if (ret < 0) {
+        goto free_exit;
+    }
+
+    /* delegate the new frozen hash table to the hash store */
+    qcow2_hash_store_add_incarnation(bs,
+                                     hash_store,
+                                     filter,
+                                     offset);
+
+    /* reset the log store and clear journal  */
+    ret = qcow2_log_store_recycle(bs, &store->frozen_log_store);
+
+    if (ret < 0) {
+        goto exit;
+    }
+
+    /* we finished to incarnate the log -> remember it */
+    store->freezing = false;
+    /* avoid modifying the freezing flag while the guest is suspended or
+     * migrating
+     */
+    co_sleep_ns(vm_clock, 1);
+    /* save new config */
+    ret =  qcow2_store_save(bs, store);
+    if (ret < 0) {
+        goto free_exit;
+    }
+
+    free(args);
+    return;
+
+free_exit:
+    qemu_vfree(filter);
+deallocate_exit:
+    incarnation_size = qcow2_hash_store_incarnation_size(hash_store->order);
+    /* postpone deallocation if guest is suspended */
+    co_sleep_ns(vm_clock, 1);
+    /* FIXME: why freeing this does match well with limbo */
+    qcow2_free_clusters(bs, offset, incarnation_size);
+exit:
+    /* save the errno so the rest of QCOW2 will know */
+    s->freeze_errno = ret;
+    free(args);
+}
+
+/* This function start a coroutine convertion a log store into and incarnation
+ *
+ * As the function return void the coroutine store error status in
+ * s->freeze_errno
+ *
+ * @store:  the store to work on
+ */
+static void qcow2_store_incarnate(BlockDriverState *bs,
+                                  QCowStore *store)
+{
+    BDRVQcowState *s = bs->opaque;
+
+    QCowIncarnateArgs *args = g_new0(QCowIncarnateArgs, 1);
+    args->bs = bs;
+    args->store = store;
+
+    s->freeze_co = qemu_coroutine_create(qcow2_store_co_incarnate);
+    qemu_coroutine_enter(s->freeze_co, args);
+}
+
+/* This function freeze the current log store and create a new one
+ *
+ * This swap the two log store
+ *
+ * @store: the QCowStore we work with
+ */
+static int qcow2_store_swap_log_store(BlockDriverState *bs, QCowStore *store)
+{
+    QCowStore swap;
+    int ret = 0;
+
+    /* flush and stop the journal */
+    ret = qcow2_log_store_stop(bs, &store->log_store);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* backup frozen log store */
+    memcpy(&swap,
+           &store->frozen_log_store,
+           sizeof(QCowLogStore));
+
+    /* freeze current log store */
+    memcpy(&store->frozen_log_store,
+           &store->log_store,
+           sizeof(QCowLogStore));
+
+    /* finish the swap */
+    memcpy(&store->log_store,
+           &swap,
+           sizeof(QCowLogStore));
+
+    /* no parallel freeze can occur */
+    assert(!store->freezing);
+    store->freezing = true;
+
+    return 0;
+}
+
+/* this function start the freeze of the current log store into and incarnation
+ *
+ * @store:     the QCowStore to work on
+ * @hash_info: the hash_info to insert into the new log store
+ * @ret:       0 on succes, -errno on error
+ */
+static int qcow2_store_start_freeze(BlockDriverState *bs,
+                                    QCowStore *store,
+                                    QCowHashInfo *hash_info)
+{
+    int ret = 0;
+    bool need_save = false;
+
+    /* if we are already are freezing a log store wait for the operation to end
+     * before starting a new one
+     */
+    while (store->freezing) {
+        co_sleep_ns(rt_clock, QCOW2_STORE_CO_SLEEP_NS);
+    }
+
+    /* log store is full -> prepare the log store freeze and create new one */
+    ret = qcow2_store_swap_log_store(bs, store);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* save new configuration */
+    ret = qcow2_store_save(bs, store);
+
+    /* on error */
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* delegate the insert to the new log store */
+    ret = qcow2_log_store_insert(bs, &store->log_store, hash_info, &need_save);
+
+    /* on error */
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* ret == 1 case is not tested because the log store is new and can't
+     * possibly be full right now
+     */
+
+    /* start to incarnate the previous log store into a hash store
+     * This is the responsibility of the coroutine to get rid of the frozen log
+     * store and save the new configuration to disk.
+     */
+    store->freezing = true;
+    qcow2_store_incarnate(bs, store);
+
+    return 0;
+}
+
+/* This function insert a QCowHashInfo into the store
+ *
+ * @store:     The QCowStore to work with
+ * @hash_info: the QCowHashInfo to insert into the sore
+ * @ret:       0 on success, -errno on error
+ */
+int qcow2_store_insert(BlockDriverState *bs, QCowStore *store,
+                       QCowHashInfo *hash_info)
+{
+    int ret = 0;
+    bool need_save = false;
+
+    /* we take the insert_lock here to prevent concurents inserts to trigger
+     * multiple concurent log store freeze if the log store is full
+     */
+    qemu_co_mutex_lock(&store->insert_lock);
+
+    /* delegate the insert to the log store */
+    ret = qcow2_log_store_insert(bs, &store->log_store, hash_info, &need_save);
+
+    /* on error */
+    if (ret < 0) {
+        goto unlock_exit;
+    }
+
+    /* need_save is true only if case of success -> no need to check ret */
+    if (need_save) {
+        ret = qcow2_store_save(bs, store);
+    }
+
+    /* on success */
+    if (!ret) {
+        goto unlock_exit;
+    }
+
+    /* ret == 1 -> log store is full -> freeze in into an incarnation */
+    ret = qcow2_store_start_freeze(bs, store, hash_info);
+
+unlock_exit:
+    qemu_co_mutex_unlock(&store->insert_lock);
+    return ret;
+}
+
+/* This delegate a flush to the log store
+ *
+ * @store:     The QCowStore to work with
+ * @ret:       0 on success, -errno on error
+ */
+int qcow2_store_flush(BlockDriverState *bs, QCowStore *store)
+{
+    return qcow2_log_store_flush(bs, &store->log_store);
+}
+
+/* This function delete a QCowHashInfo from the store
+ *
+ * @store:     The QCowStore to work with
+ * @hash_info: the QCowHashInfo to insert into the sore
+ * @ret:       0 on success, -errno on error
+ */
+int qcow2_store_delete(BlockDriverState *bs, QCowStore *store,
+                       QCowHashInfo *hash_info)
+{
+    hash_info->first_logical_sect |= QCOW_DEDUP_DELETED;
+    return qcow2_store_insert(bs, store, hash_info);
+}
+
+/* this function compute the size of a dump of a store
+ *
+ * @store: the store to work on
+ * @ret:   the size of a dump
+ */
+static size_t qcow2_store_dump_size(QCowStore *store)
+{
+    return sizeof(store->order) + 1 +
+           qcow2_log_store_dump_size() * 2 + /* current + frozen log store */
+           qcow2_hash_store_dump_size(&store->hash_store);
+}
+
+/* this function dump a store in a buffer
+ *
+ * @buf:   the buffer to dump into
+ * @store: the store to dump
+ * @ret:   the size used for the dump
+ */
+static size_t qcow2_store_dump(uint8_t *buf, QCowStore *store)
+{
+    uint32_t *buf32 = (uint32_t *) buf;
+    size_t offset;
+
+    /* dump order */
+    buf32[0] = cpu_to_be32(store->order);
+    offset = sizeof(store->order);
+
+    /* dump freeze status */
+    buf[offset] = store->freezing;
+    offset++;
+
+    /* dump current log store */
+    offset += qcow2_log_store_dump(buf + offset,
+                                   &store->log_store);
+
+
+    /* dump frozen log store */
+    offset += qcow2_log_store_dump(buf + offset,
+                                   &store->frozen_log_store);
+
+    /* dump hash store */
+    offset += qcow2_hash_store_dump(buf + offset,
+                                    &store->hash_store);
+
+    return offset;
+}
+
+/* this function parse a buffer in a given store
+ *
+ * note: As the parse method is used only on startup it also init the store
+ *
+ * @store: the store to parse into
+ * @buf:   the buffer to parse from
+ * @size:  the size of the buffer
+ * @ret:   0 on success, -1 when buffer is too small to parse all data from
+ */
+static int qcow2_store_parse(BlockDriverState *bs,
+                             QCowStore *store,
+                             uint8_t *buf,
+                             uint32_t size)
+{
+    size_t offset;
+    uint32_t *buf32 = (uint32_t *) buf;
+    uint32_t order;
+    int ret;
+
+    /* parse order and init store */
+    order = be32_to_cpu(buf32[0]);
+    qcow2_store_init(bs, store, order);
+    offset = sizeof(store->order);
+
+    /* parse freeze status */
+    store->freezing = buf[offset];
+    offset++;
+
+    /* parse current log store */
+    offset += qcow2_log_store_parse(&store->log_store, buf + offset);
+
+    /* parse frozen log store i its not NULL */
+    offset += qcow2_log_store_parse(&store->frozen_log_store, buf + offset);
+
+    /* parse hash store */
+    ret = qcow2_hash_store_parse(&store->hash_store,
+                                 buf + offset,
+                                 buf + size);
+
+    /* buffer was too small -> cleanup and return error  */
+    if (ret == -1) {
+        /* free various buffers */
+        qcow2_store_cleanup(store);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int32_t qcow2_store_compute_order(BlockDriverState *bs,
+                                         uint64_t total_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t nb_clusters = total_size / s->cluster_size;
+    uint64_t nb_hash_per_incarnation = nb_clusters / QCOW2_NB_INCARNATION_GOAL;
+    return qcow2_log_store_compute_order(nb_hash_per_incarnation);
+}
+
+static int64_t qcow2_store_alloc_disk_conf(BlockDriverState *bs,
+                                           QCowStore *store,
+                                           size_t *psize)
+{
+    /* compute configuration space dump size * 2 with room for growth */
+    *psize = qcow2_store_dump_size(store) * 2;
+
+    /* allocate the store configuration space */
+    return qcow2_alloc_clusters(bs, *psize);
+}
+
+/* this function save a QCowStore to disk and update header if needeed
+ *
+ * The function handle the need to grow the on disk dump area
+ * The function does rewrite the QCOW2 header extension if needed.
+ *
+ * @store:  the store to save
+ * @ret:    0 on success, -errno on error
+ */
+int64_t qcow2_store_save(BlockDriverState *bs, QCowStore *store)
+{
+    BDRVQcowState *s = bs->opaque;
+    int64_t offset, old_offset = 0;
+    size_t size, old_size = 0;
+    bool alloc = false;
+    uint8_t *buf;
+    int ret = 0;
+
+    /* we use these temporary variable to commit atomically */
+    offset = s->dedup_conf_offset;
+    size = s->dedup_conf_size;
+
+    /* check if we need to grow on disk dump area */
+    if (size < qcow2_store_dump_size(store))  {
+        alloc = true;
+        old_offset = offset;
+        old_size = size;
+        offset = qcow2_store_alloc_disk_conf(bs, store, &size);
+
+        if (offset < 0) {
+            return offset;
+        }
+    }
+
+    /* allocate buffer */
+    buf = qemu_blockalign(bs, size);
+    memset(buf, 0, size);
+
+    /* serialize store config in buffer */
+    ret = qcow2_store_dump(buf, store);
+
+    if (ret < 0) {
+        goto free_dealloc_exit;
+    }
+
+    /* write the conf to disk */
+    ret = bdrv_pwrite(bs->file, offset, buf, size);
+
+    /* no error happened and we grew the config disk space -> save in header */
+    if (alloc && ret > 0) {
+        s->dedup_conf_offset = offset;
+        s->dedup_conf_size = size;
+        qcow2_update_header(bs);
+        /* do not free old disk space on creation */
+        if (old_size) {
+            qcow2_free_clusters(bs, old_offset, old_size);
+        }
+    }
+    ret = 0;
+
+free_dealloc_exit:
+    /* on alloc and error free newly allocated disk space */
+    if (alloc && ret < 0) {
+        qcow2_free_clusters(bs, offset, size);
+    }
+    qemu_vfree(buf);
+    return ret;
+}
+
+/* This function will allocate a journal, init the store and save the config
+ *
+ * this function will be used at QCOW2 image creation time
+ * This code don't bother cleaning up failure since error would make image
+ * creation fail. It just free memory.
+ *
+ * note: s->cluster_size must be filled with correct value for
+ *       qcow2_store_compute_order
+ *
+ * @store:      the store to create
+ * @total_size: the total size of the image
+ * @ret:        0 on success, -errno on error
+ */
+int64_t qcow2_store_create(BlockDriverState *bs,
+                           QCowStore *store,
+                           uint64_t total_size)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret = 0;
+
+    /* compute the bit order required to store the journal and hash tables */
+    uint32_t order = qcow2_store_compute_order(bs, total_size);
+
+    /* initialize the store state */
+    qcow2_store_init(bs, store, order);
+
+    /* create the journal */
+    ret = qcow2_log_store_create(bs, &store->log_store, order);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* create frozen log store we will swap at runtime */
+    ret = qcow2_log_store_create(bs, &store->frozen_log_store, order);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* set size to zero so the save function will start allocating
+     * and will not try to free anything
+     */
+    s->dedup_conf_size = 0;
+
+    /* save new config */
+    return qcow2_store_save(bs, store);
+}
+
+
+/* this function initialize a store and load it's configuration from disk
+ *
+ * note: the journal and the incarnations filters are not loaded from disk
+ *       this work is to be done later.
+ *
+ * @store:  the store to load the configuration into
+ * @ret:    0 on success, -errno on error, -1 if the on disk dump was invalid
+ */
+int qcow2_store_load(BlockDriverState *bs, QCowStore *store)
+{
+    BDRVQcowState *s = bs->opaque;
+    int ret = 0;
+
+    /* allocate read buffer */
+    uint8_t *buf = qemu_blockalign(bs, s->dedup_conf_size);
+
+    /* read conf from disk */
+    ret = bdrv_pread(bs->file,
+                     s->dedup_conf_offset,
+                     buf,
+                     s->dedup_conf_size);
+
+    if (ret < 0) {
+        goto free_exit;
+    }
+
+    /* parse the buffer into a store */
+    ret = qcow2_store_parse(bs, store, buf, s->dedup_conf_size);
+free_exit:
+    qemu_vfree(buf);
+
+    return ret;
+}
+
+/* this function load the in ram store data at startup
+ *
+ * It loads the current journal synchronously so after this the deduplication
+ * will be operational.
+ *
+ * @store: the store to work on
+ * @ret:   0 on succes, -errno on error
+ */
+int qcow2_store_start(BlockDriverState *bs, QCowStore *store)
+{
+    int ret = 0;
+
+    /* reload current journal */
+    ret = qcow2_log_store_rebuild_from_journal(bs, &store->log_store);
+
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* resume freeze in progress */
+    if(store->freezing) {
+        ret = qcow2_log_store_rebuild_from_journal(bs,
+                                                   &store->frozen_log_store);
+
+        if (ret < 0) {
+            return ret;
+        }
+
+        /* do the incarnation in a coroutine */
+        qcow2_store_incarnate(bs, store);
+    }
+
+    /* load incarnations in ram filters in a coroutine */
+    qcow2_hash_store_load_filters(bs, &store->hash_store);
+
+    return 0;
+}
+
+int qcow2_store_forget(BlockDriverState *bs, QCowStore *store)
+{
+     int ret = 0;
+     store->freezing = false;
+
+     /* reset hash store */
+     qcow2_hash_store_forget_all_incarnations(&store->hash_store);
+
+     /* reset log store */
+     ret = qcow2_log_store_create(bs, &store->log_store, store->order);
+
+     if (ret < 0) {
+         return ret;
+     }
+
+     /* reset frozen log store */
+     ret = qcow2_log_store_create(bs, &store->frozen_log_store, store->order);
+
+     if (ret < 0) {
+         return ret;
+     }
+
+     /* save config to disk */
+     return qcow2_store_save(bs, store);
+}
diff --git a/block/qcow2.h b/block/qcow2.h
index d0037bf..c0dbfe3 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -226,9 +226,9 @@ typedef struct {
 
 typedef struct {
     uint32_t      order;
+    bool          freezing;          /* is a log store freeze in progress */
     QCowLogStore  log_store;         /* the current log store */
     QCowLogStore  frozen_log_store;  /* the log store to incarnate */
-    bool          freezing;          /* are we incarnating a log store */
     QCowHashStore hash_store;
     CoMutex       insert_lock;       /* used to prevent multiple freeze attempts
                                       * at the same time
@@ -699,4 +699,22 @@ size_t qcow2_hash_store_parse(QCowHashStore *store,
                                 uint8_t *buf,
                                 uint8_t *buf_end);
 
+/* qcow2-store.c functions (Should be called by dedup.c) */
+
+void qcow2_store_cleanup(QCowStore *store);
+int qcow2_store_get(BlockDriverState *bs, QCowStore *store,
+                    QCowHashInfo *hash_info);
+int qcow2_store_insert(BlockDriverState *bs, QCowStore *store,
+                       QCowHashInfo *hash_info);
+int qcow2_store_flush(BlockDriverState *bs, QCowStore *store);
+int qcow2_store_delete(BlockDriverState *bs, QCowStore *store,
+                       QCowHashInfo *hash_info);
+int64_t qcow2_store_save(BlockDriverState *bs, QCowStore *store);
+int64_t qcow2_store_create(BlockDriverState *bs,
+                           QCowStore *store,
+                           uint64_t total_size);
+int qcow2_store_load(BlockDriverState *bs, QCowStore *store);
+int qcow2_store_start(BlockDriverState *bs, QCowStore *store);
+int qcow2_store_forget(BlockDriverState *bs, QCowStore *store);
+
 #endif
