[Fold into 2]
---
 drivers/md/persistent-data/dm-block-manager.c |   30 ++++++++++++++++++++++++++
 drivers/md/persistent-data/dm-block-manager.h |   12 ++++++++++
 2 files changed, 42 insertions(+)

Index: linux-3.0-rc7/drivers/md/persistent-data/dm-block-manager.c
===================================================================
--- linux-3.0-rc7.orig/drivers/md/persistent-data/dm-block-manager.c
+++ linux-3.0-rc7/drivers/md/persistent-data/dm-block-manager.c
@@ -426,6 +426,14 @@ static int __wait_all_writes(struct dm_b
 		     !bm->writing_count);
 }
 
+static int __wait_all_io(struct dm_block_manager *bm, unsigned long *flags)
+	__retains(&bm->lock)
+{
+	unplug();
+	__wait_block(&bm->io_q, &bm->lock, *flags, io_schedule,
+		     !bm->writing_count && !bm->reading_count);
+}
+
 static int __wait_clean(struct dm_block_manager *bm, unsigned long *flags)
 	__retains(&bm->lock)
 {
@@ -928,4 +936,26 @@ int dm_bm_flush_and_unlock(struct dm_blo
 }
 EXPORT_SYMBOL_GPL(dm_bm_flush_and_unlock);
 
+int dm_bm_rebind_block_device(struct dm_block_manager *bm, struct block_device *bdev)
+{
+	unsigned long flags;
+	dm_block_t nr_blocks = i_size_read(bdev->bd_inode);
+	do_div(nr_blocks, bm->block_size);
+
+	spin_lock_irqsave(&bm->lock, flags);
+	if (nr_blocks < bm->nr_blocks) {
+		spin_unlock_irqrestore(&bm->lock, flags);
+		return -EINVAL;
+	}
+
+	bm->bdev = bdev;
+	bm->nr_blocks = nr_blocks;
+
+	/* wait for any in-flight io that may be using the old bdev */
+	__wait_all_io(bm, &flags);
+	spin_unlock_irqrestore(&bm->lock, flags);
+
+	return 0;
+}
+
 /*----------------------------------------------------------------*/
Index: linux-3.0-rc7/drivers/md/persistent-data/dm-block-manager.h
===================================================================
--- linux-3.0-rc7.orig/drivers/md/persistent-data/dm-block-manager.h
+++ linux-3.0-rc7/drivers/md/persistent-data/dm-block-manager.h
@@ -101,6 +101,18 @@ int dm_bm_flush_and_unlock(struct dm_blo
 			   struct dm_block *superblock);
 
 /*
+ * The client may wish to change which block device the block manager
+ * points at.  If you use this function then the cache remains intact, so
+ * make sure your data is identical on the new device.  The new device must
+ * be at least as long as the old.
+ *
+ * This function guarantees that once it returns, no further IO will occur
+ * on the old device.
+ */
+int dm_bm_rebind_block_device(struct dm_block_manager *bm,
+			      struct block_device *bdev);
+
+/*
  * Debug routines.
  */
 unsigned dm_bm_locks_held(struct dm_block_manager *bm);