Commit 9504e086 authored by Martin K. Petersen's avatar Martin K. Petersen Committed by Jens Axboe

block: Fix topology stacking for data and discard alignment

The stacking code incorrectly scaled up the data offset in some cases
causing misaligned devices to report alignment.  Rewrite the stacking
algorithm to remedy this and apply the same alignment principles to the
discard handling.
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 65b32a57
...@@ -517,9 +517,8 @@ static unsigned int lcm(unsigned int a, unsigned int b) ...@@ -517,9 +517,8 @@ static unsigned int lcm(unsigned int a, unsigned int b)
int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
sector_t offset) sector_t offset)
{ {
int ret; sector_t alignment;
unsigned int top, bottom, granularity;
ret = 0;
t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
...@@ -537,6 +536,19 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, ...@@ -537,6 +536,19 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
t->max_segment_size = min_not_zero(t->max_segment_size, t->max_segment_size = min_not_zero(t->max_segment_size,
b->max_segment_size); b->max_segment_size);
granularity = max(b->physical_block_size, b->io_min);
alignment = b->alignment_offset - (offset & (granularity - 1));
if (t->alignment_offset != alignment) {
top = max(t->physical_block_size, t->io_min)
+ t->alignment_offset;
bottom = granularity + alignment;
if (max(top, bottom) & (min(top, bottom) - 1))
t->misaligned = 1;
}
t->logical_block_size = max(t->logical_block_size, t->logical_block_size = max(t->logical_block_size,
b->logical_block_size); b->logical_block_size);
...@@ -544,54 +556,55 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, ...@@ -544,54 +556,55 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
b->physical_block_size); b->physical_block_size);
t->io_min = max(t->io_min, b->io_min); t->io_min = max(t->io_min, b->io_min);
t->io_opt = lcm(t->io_opt, b->io_opt);
t->no_cluster |= b->no_cluster; t->no_cluster |= b->no_cluster;
t->discard_zeroes_data &= b->discard_zeroes_data; t->discard_zeroes_data &= b->discard_zeroes_data;
/* Bottom device offset aligned? */ if (t->physical_block_size & (t->logical_block_size - 1)) {
if (offset && t->physical_block_size = t->logical_block_size;
(offset & (b->physical_block_size - 1)) != b->alignment_offset) {
t->misaligned = 1; t->misaligned = 1;
ret = -1;
} }
/* if (t->io_min & (t->physical_block_size - 1)) {
* Temporarily disable discard granularity. It's currently buggy t->io_min = t->physical_block_size;
* since we default to 0 for discard_granularity, hence this t->misaligned = 1;
* "failure" will always trigger for non-zero offsets.
*/
#if 0
if (offset &&
(offset & (b->discard_granularity - 1)) != b->discard_alignment) {
t->discard_misaligned = 1;
ret = -1;
} }
#endif
/* If top has no alignment offset, inherit from bottom */ if (t->io_opt & (t->physical_block_size - 1)) {
if (!t->alignment_offset) t->io_opt = 0;
t->alignment_offset = t->misaligned = 1;
b->alignment_offset & (b->physical_block_size - 1); }
if (!t->discard_alignment) t->alignment_offset = lcm(t->alignment_offset, alignment)
t->discard_alignment = & (max(t->physical_block_size, t->io_min) - 1);
b->discard_alignment & (b->discard_granularity - 1);
/* Top device aligned on logical block boundary? */ if (t->alignment_offset & (t->logical_block_size - 1))
if (t->alignment_offset & (t->logical_block_size - 1)) {
t->misaligned = 1; t->misaligned = 1;
ret = -1;
/* Discard alignment and granularity */
if (b->discard_granularity) {
alignment = b->discard_alignment -
(offset & (b->discard_granularity - 1));
if (t->discard_granularity != 0 &&
t->discard_alignment != alignment) {
top = t->discard_granularity + t->discard_alignment;
bottom = b->discard_granularity + alignment;
/* Verify that top and bottom intervals line up */
if (max(top, bottom) & (min(top, bottom) - 1))
t->discard_misaligned = 1;
} }
/* Find lcm() of optimal I/O size and granularity */ t->discard_granularity = max(t->discard_granularity,
t->io_opt = lcm(t->io_opt, b->io_opt);
t->discard_granularity = lcm(t->discard_granularity,
b->discard_granularity); b->discard_granularity);
t->discard_alignment = lcm(t->discard_alignment, alignment) &
(t->discard_granularity - 1);
}
/* Verify that optimal I/O size is a multiple of io_min */ return t->misaligned ? -1 : 0;
if (t->io_min && t->io_opt % t->io_min)
ret = -1;
return ret;
} }
EXPORT_SYMBOL(blk_stack_limits); EXPORT_SYMBOL(blk_stack_limits);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment