[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);