diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 5859d69d6944..c591bef61671 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -1968,6 +1968,49 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c)
 }
 EXPORT_SYMBOL_GPL(dm_bufio_client_destroy);
 
+/*
+ * Reset the buffering interface
+ * Besides @c->shrinker, destroy and re-initialize all members in
+ * dm_bufio_client. The dm_bufio_client instance should be detroyed
+ * by caller even reset failed.
+ */
+int dm_bufio_client_reset(struct dm_bufio_client *c, struct block_device *bdev,
+			  unsigned int block_size,
+			  unsigned int reserved_buffers, unsigned int aux_size,
+			  void (*alloc_callback)(struct dm_buffer *),
+			  void (*write_callback)(struct dm_buffer *),
+			  unsigned int flags)
+{
+	int r;
+
+	if (!block_size || block_size & ((1 << SECTOR_SHIFT) - 1)) {
+		DMERR("%s: block size not specified or is not multiple of 512b", __func__);
+		return -EINVAL;
+	}
+
+	drop_buffers(c);
+	flush_work(&c->shrink_work);
+	mutex_lock(&dm_bufio_clients_lock);
+	list_del(&c->client_list);
+	dm_bufio_client_count--;
+	__cache_size_refresh();
+	mutex_unlock(&dm_bufio_clients_lock);
+	__do_destroy(c);
+
+	r = __do_init(c, bdev, block_size, reserved_buffers, aux_size,
+		      alloc_callback, write_callback, flags);
+
+	/* The instance should still be added list back if __do_init failed. */
+	mutex_lock(&dm_bufio_clients_lock);
+	dm_bufio_client_count++;
+	list_add(&c->client_list, &dm_bufio_all_clients);
+	__cache_size_refresh();
+	mutex_unlock(&dm_bufio_clients_lock);
+
+	return r;
+}
+EXPORT_SYMBOL_GPL(dm_bufio_client_reset);
+
 void dm_bufio_set_sector_offset(struct dm_bufio_client *c, sector_t start)
 {
 	c->start = start;
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index a27395c8621f..6c3096fdb4e8 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -1857,23 +1857,53 @@ static void __set_abort_with_changes_flags(struct dm_pool_metadata *pmd)
 		td->aborted_with_changes = td->changed;
 }
 
+static int __reset_persistent_data_objects(struct dm_pool_metadata *pmd)
+{
+	int r;
+
+	dm_sm_destroy(pmd->data_sm);
+	dm_sm_destroy(pmd->metadata_sm);
+	dm_tm_destroy(pmd->nb_tm);
+	dm_tm_destroy(pmd->tm);
+
+	r = dm_block_manager_reset(pmd->bm, pmd->bdev,
+				   THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
+				   THIN_MAX_CONCURRENT_LOCKS);
+	if (r) {
+		DMERR("could not reset block manager");
+		return r;
+	}
+
+	return __open_or_format_metadata(pmd, false);
+}
+
 int dm_pool_abort_metadata(struct dm_pool_metadata *pmd)
 {
 	int r = -EINVAL;
+	struct dm_block_manager *bm = NULL;
 
 	pmd_write_lock(pmd);
 	if (pmd->fail_io)
 		goto out;
 
 	__set_abort_with_changes_flags(pmd);
-	__destroy_persistent_data_objects(pmd);
-	r = __create_persistent_data_objects(pmd, false);
-	if (r)
+	r = __reset_persistent_data_objects(pmd);
+	if (r) {
 		pmd->fail_io = true;
+		bm = pmd->bm;
+		pmd->bm = NULL;
+		goto out_destroy_manager;
+	}
 
 out:
 	pmd_write_unlock(pmd);
 
+	return r;
+
+out_destroy_manager:
+	pmd_write_unlock(pmd);
+	dm_block_manager_destroy(bm);
+
 	return r;
 }
 
diff --git a/drivers/md/persistent-data/dm-block-manager.c b/drivers/md/persistent-data/dm-block-manager.c
index 11935864f50f..c02bc56f3f71 100644
--- a/drivers/md/persistent-data/dm-block-manager.c
+++ b/drivers/md/persistent-data/dm-block-manager.c
@@ -415,6 +415,27 @@ void dm_block_manager_destroy(struct dm_block_manager *bm)
 }
 EXPORT_SYMBOL_GPL(dm_block_manager_destroy);
 
+int dm_block_manager_reset(struct dm_block_manager *bm,
+			   struct block_device *bdev, unsigned int block_size,
+			   unsigned int max_held_per_thread)
+{
+	int r;
+
+	r = dm_bufio_client_reset(bm->bufio, bdev, block_size,
+				  max_held_per_thread,
+				  sizeof(struct buffer_aux),
+				  dm_block_manager_alloc_callback,
+				  dm_block_manager_write_callback, 0);
+	if (r)
+		goto out;
+
+	bm->read_only = false;
+
+out:
+	return r;
+}
+EXPORT_SYMBOL_GPL(dm_block_manager_reset);
+
 unsigned dm_bm_block_size(struct dm_block_manager *bm)
 {
 	return dm_bufio_get_block_size(bm->bufio);
diff --git a/drivers/md/persistent-data/dm-block-manager.h b/drivers/md/persistent-data/dm-block-manager.h
index e728937f376a..596f3d65f670 100644
--- a/drivers/md/persistent-data/dm-block-manager.h
+++ b/drivers/md/persistent-data/dm-block-manager.h
@@ -36,6 +36,10 @@ struct dm_block_manager *dm_block_manager_create(
 	unsigned max_held_per_thread);
 void dm_block_manager_destroy(struct dm_block_manager *bm);
 
+int dm_block_manager_reset(struct dm_block_manager *bm,
+	struct block_device *bdev, unsigned int block_size,
+	unsigned int max_held_per_thread);
+
 unsigned dm_bm_block_size(struct dm_block_manager *bm);
 dm_block_t dm_bm_nr_blocks(struct dm_block_manager *bm);
 
diff --git a/include/linux/dm-bufio.h b/include/linux/dm-bufio.h
index ee4f19c170ab..5af88b28a258 100644
--- a/include/linux/dm-bufio.h
+++ b/include/linux/dm-bufio.h
@@ -37,6 +37,16 @@ dm_bufio_client_create(struct block_device *bdev, unsigned int block_size,
  */
 void dm_bufio_client_destroy(struct dm_bufio_client *c);
 
+/*
+ * Reset a buffered IO cache on a given device
+ */
+int dm_bufio_client_reset(struct dm_bufio_client *c, struct block_device *bdev,
+			  unsigned int block_size,
+			  unsigned int reserved_buffers, unsigned int aux_size,
+			  void (*alloc_callback)(struct dm_buffer *),
+			  void (*write_callback)(struct dm_buffer *),
+			  unsigned int flags);
+
 /*
  * Set the sector range.
  * When this function is called, there must be no I/O in progress on the bufio
