diff options
| -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); |
