diff options
author | Mike Snitzer <snitzer@redhat.com> | 2009-06-22 05:12:31 -0400 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2009-06-22 05:12:31 -0400 |
commit | be6d4305db093ad1cc623f7dd3d2470b7bd73fa4 (patch) | |
tree | 27935ca83626cba6ba2fac2cc83deeca0ff15492 /drivers | |
parent | 02acc3a4fa0a6c2a5ccc4fb722b55fb710265882 (diff) |
dm table: validate device logical_block_size
Impose necessary and sufficient conditions on a devices's table such
that any incoming bio which respects its logical_block_size can be
processed successfully.
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/dm-table.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 535fdaf2473d..e3bcfb8b15a1 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -724,6 +724,71 @@ static void check_for_valid_limits(struct io_restrictions *rs) | |||
724 | rs->bounce_pfn = -1; | 724 | rs->bounce_pfn = -1; |
725 | } | 725 | } |
726 | 726 | ||
727 | /* | ||
728 | * Impose necessary and sufficient conditions on a devices's table such | ||
729 | * that any incoming bio which respects its logical_block_size can be | ||
730 | * processed successfully. If it falls across the boundary between | ||
731 | * two or more targets, the size of each piece it gets split into must | ||
732 | * be compatible with the logical_block_size of the target processing it. | ||
733 | */ | ||
734 | static int validate_hardware_logical_block_alignment(struct dm_table *table) | ||
735 | { | ||
736 | /* | ||
737 | * This function uses arithmetic modulo the logical_block_size | ||
738 | * (in units of 512-byte sectors). | ||
739 | */ | ||
740 | unsigned short device_logical_block_size_sects = | ||
741 | table->limits.logical_block_size >> SECTOR_SHIFT; | ||
742 | |||
743 | /* | ||
744 | * Offset of the start of the next table entry, mod logical_block_size. | ||
745 | */ | ||
746 | unsigned short next_target_start = 0; | ||
747 | |||
748 | /* | ||
749 | * Given an aligned bio that extends beyond the end of a | ||
750 | * target, how many sectors must the next target handle? | ||
751 | */ | ||
752 | unsigned short remaining = 0; | ||
753 | |||
754 | struct dm_target *uninitialized_var(ti); | ||
755 | unsigned i = 0; | ||
756 | |||
757 | /* | ||
758 | * Check each entry in the table in turn. | ||
759 | */ | ||
760 | while (i < dm_table_get_num_targets(table)) { | ||
761 | ti = dm_table_get_target(table, i++); | ||
762 | |||
763 | /* | ||
764 | * If the remaining sectors fall entirely within this | ||
765 | * table entry are they compatible with its logical_block_size? | ||
766 | */ | ||
767 | if (remaining < ti->len && | ||
768 | remaining & ((ti->limits.logical_block_size >> | ||
769 | SECTOR_SHIFT) - 1)) | ||
770 | break; /* Error */ | ||
771 | |||
772 | next_target_start = | ||
773 | (unsigned short) ((next_target_start + ti->len) & | ||
774 | (device_logical_block_size_sects - 1)); | ||
775 | remaining = next_target_start ? | ||
776 | device_logical_block_size_sects - next_target_start : 0; | ||
777 | } | ||
778 | |||
779 | if (remaining) { | ||
780 | DMWARN("%s: table line %u (start sect %llu len %llu) " | ||
781 | "not aligned to hardware logical block size %hu", | ||
782 | dm_device_name(table->md), i, | ||
783 | (unsigned long long) ti->begin, | ||
784 | (unsigned long long) ti->len, | ||
785 | table->limits.logical_block_size); | ||
786 | return -EINVAL; | ||
787 | } | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
727 | int dm_table_add_target(struct dm_table *t, const char *type, | 792 | int dm_table_add_target(struct dm_table *t, const char *type, |
728 | sector_t start, sector_t len, char *params) | 793 | sector_t start, sector_t len, char *params) |
729 | { | 794 | { |
@@ -823,6 +888,10 @@ int dm_table_complete(struct dm_table *t) | |||
823 | 888 | ||
824 | check_for_valid_limits(&t->limits); | 889 | check_for_valid_limits(&t->limits); |
825 | 890 | ||
891 | r = validate_hardware_logical_block_alignment(t); | ||
892 | if (r) | ||
893 | return r; | ||
894 | |||
826 | /* how many indexes will the btree have ? */ | 895 | /* how many indexes will the btree have ? */ |
827 | leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); | 896 | leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); |
828 | t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); | 897 | t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); |