aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2009-06-22 05:12:30 -0400
committerAlasdair G Kergon <agk@redhat.com>2009-06-22 05:12:30 -0400
commit02acc3a4fa0a6c2a5ccc4fb722b55fb710265882 (patch)
tree5abd5bf61c8fe1a9bed391c828ffff34384f6b20
parent60935eb21d3c5bac79618000f38f92c249d153c4 (diff)
dm table: ensure targets are aligned to logical_block_size
Ensure I/O is aligned to the logical block size of target devices. Rename check_device_area() to device_area_is_valid() for clarity and establish the device limits including the logical block size prior to calling it. Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
-rw-r--r--drivers/md/dm-table.c58
1 files changed, 44 insertions, 14 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index af1ceae2582a..535fdaf2473d 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -383,16 +383,45 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
383/* 383/*
384 * If possible, this checks an area of a destination device is valid. 384 * If possible, this checks an area of a destination device is valid.
385 */ 385 */
386static int check_device_area(struct dm_dev_internal *dd, sector_t start, 386static int device_area_is_valid(struct dm_target *ti, struct block_device *bdev,
387 sector_t len) 387 sector_t start, sector_t len)
388{ 388{
389 sector_t dev_size = i_size_read(dd->dm_dev.bdev->bd_inode) >> 389 sector_t dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
390 SECTOR_SHIFT; 390 unsigned short logical_block_size_sectors =
391 ti->limits.logical_block_size >> SECTOR_SHIFT;
392 char b[BDEVNAME_SIZE];
391 393
392 if (!dev_size) 394 if (!dev_size)
393 return 1; 395 return 1;
394 396
395 return ((start < dev_size) && (len <= (dev_size - start))); 397 if ((start >= dev_size) || (start + len > dev_size)) {
398 DMWARN("%s: %s too small for target",
399 dm_device_name(ti->table->md), bdevname(bdev, b));
400 return 0;
401 }
402
403 if (logical_block_size_sectors <= 1)
404 return 1;
405
406 if (start & (logical_block_size_sectors - 1)) {
407 DMWARN("%s: start=%llu not aligned to h/w "
408 "logical block size %hu of %s",
409 dm_device_name(ti->table->md),
410 (unsigned long long)start,
411 ti->limits.logical_block_size, bdevname(bdev, b));
412 return 0;
413 }
414
415 if (len & (logical_block_size_sectors - 1)) {
416 DMWARN("%s: len=%llu not aligned to h/w "
417 "logical block size %hu of %s",
418 dm_device_name(ti->table->md),
419 (unsigned long long)len,
420 ti->limits.logical_block_size, bdevname(bdev, b));
421 return 0;
422 }
423
424 return 1;
396} 425}
397 426
398/* 427/*
@@ -478,14 +507,7 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
478 } 507 }
479 atomic_inc(&dd->count); 508 atomic_inc(&dd->count);
480 509
481 if (!check_device_area(dd, start, len)) {
482 DMWARN("device %s too small for target", path);
483 dm_put_device(ti, &dd->dm_dev);
484 return -EINVAL;
485 }
486
487 *result = &dd->dm_dev; 510 *result = &dd->dm_dev;
488
489 return 0; 511 return 0;
490} 512}
491 513
@@ -554,8 +576,16 @@ int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
554 int r = __table_get_device(ti->table, ti, path, 576 int r = __table_get_device(ti->table, ti, path,
555 start, len, mode, result); 577 start, len, mode, result);
556 578
557 if (!r) 579 if (r)
558 dm_set_device_limits(ti, (*result)->bdev); 580 return r;
581
582 dm_set_device_limits(ti, (*result)->bdev);
583
584 if (!device_area_is_valid(ti, (*result)->bdev, start, len)) {
585 dm_put_device(ti, *result);
586 *result = NULL;
587 return -EINVAL;
588 }
559 589
560 return r; 590 return r;
561} 591}