From: Mike Snitzer Each mapping in a DM table must be properly aligned on HW sector boundaries. This is particularly important when a DM table is composed of mappings for devices with different HW sector sizes. Signed-off-by: Mike Snitzer --- drivers/md/dm-table.c | 43 +++++++++++++++++++++++++++++++------------ 1 files changed, 31 insertions(+), 12 deletions(-) Index: linux-2.6.29/drivers/md/dm-table.c =================================================================== --- linux-2.6.29.orig/drivers/md/dm-table.c 2009-04-03 23:13:18.000000000 +0100 +++ linux-2.6.29/drivers/md/dm-table.c 2009-04-08 10:50:57.000000000 +0100 @@ -384,15 +384,34 @@ static void close_dev(struct dm_dev_inte /* * If possible, this checks an area of a destination device is valid. */ -static int check_device_area(struct dm_dev_internal *dd, sector_t start, - sector_t len) +static int check_device_area(struct dm_target *ti, struct block_device *bdev, + sector_t start, sector_t len) { - sector_t dev_size = dd->dm_dev.bdev->bd_inode->i_size >> SECTOR_SHIFT; + sector_t dev_size = bdev->bd_inode->i_size >> SECTOR_SHIFT; + struct io_restrictions *rs = &ti->limits; + sector_t dev_hardsectors = rs->hardsect_size >> SECTOR_SHIFT; + char b[BDEVNAME_SIZE]; if (!dev_size) return 1; - return ((start < dev_size) && (len <= (dev_size - start))); + if (!((start < dev_size) && (len <= (dev_size - start)))) { + DMWARN("device %s too small for target", bdevname(bdev, b)); + return 0; + } + + if (dev_hardsectors > 1) { + if ((ti->begin % dev_hardsectors) || + (start % dev_hardsectors) || + (len % dev_hardsectors)) { + DMWARN("device %s mapping (%lu %lu ... %lu) " + "is not HW sector aligned", + bdevname(bdev, b), ti->begin, len, start); + return 0; + } + } + + return 1; } /* @@ -478,14 +497,7 @@ static int __table_get_device(struct dm_ } atomic_inc(&dd->count); - if (!check_device_area(dd, start, len)) { - DMWARN("device %s too small for target", path); - dm_put_device(ti, &dd->dm_dev); - return -EINVAL; - } - *result = &dd->dm_dev; - return 0; } @@ -553,9 +565,16 @@ int dm_get_device(struct dm_target *ti, int r = __table_get_device(ti->table, ti, path, start, len, mode, result); - if (!r) + if (!r) { dm_set_device_limits(ti, (*result)->bdev); + if (!check_device_area(ti, (*result)->bdev, + start, len)) { + dm_put_device(ti, *result); + return -EINVAL; + } + } + return r; }