diff options
| author | Mike Snitzer <snitzer@redhat.com> | 2009-06-22 05:12:30 -0400 |
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2009-06-22 05:12:30 -0400 |
| commit | 02acc3a4fa0a6c2a5ccc4fb722b55fb710265882 (patch) | |
| tree | 5abd5bf61c8fe1a9bed391c828ffff34384f6b20 | |
| parent | 60935eb21d3c5bac79618000f38f92c249d153c4 (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.c | 58 |
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 | */ |
| 386 | static int check_device_area(struct dm_dev_internal *dd, sector_t start, | 386 | static 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 | } |
