|
@@ -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,
|
|
|
sector_t offset)
|
|
|
{
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = 0;
|
|
|
+ sector_t alignment;
|
|
|
+ unsigned int top, bottom, granularity;
|
|
|
|
|
|
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);
|
|
@@ -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,
|
|
|
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,
|
|
|
b->logical_block_size);
|
|
|
|
|
@@ -544,54 +556,55 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
|
|
|
b->physical_block_size);
|
|
|
|
|
|
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->discard_zeroes_data &= b->discard_zeroes_data;
|
|
|
|
|
|
- /* Bottom device offset aligned? */
|
|
|
- if (offset &&
|
|
|
- (offset & (b->physical_block_size - 1)) != b->alignment_offset) {
|
|
|
+ if (t->physical_block_size & (t->logical_block_size - 1)) {
|
|
|
+ t->physical_block_size = t->logical_block_size;
|
|
|
t->misaligned = 1;
|
|
|
- ret = -1;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Temporarily disable discard granularity. It's currently buggy
|
|
|
- * since we default to 0 for discard_granularity, hence this
|
|
|
- * "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;
|
|
|
+ if (t->io_min & (t->physical_block_size - 1)) {
|
|
|
+ t->io_min = t->physical_block_size;
|
|
|
+ t->misaligned = 1;
|
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
- /* If top has no alignment offset, inherit from bottom */
|
|
|
- if (!t->alignment_offset)
|
|
|
- t->alignment_offset =
|
|
|
- b->alignment_offset & (b->physical_block_size - 1);
|
|
|
+ if (t->io_opt & (t->physical_block_size - 1)) {
|
|
|
+ t->io_opt = 0;
|
|
|
+ t->misaligned = 1;
|
|
|
+ }
|
|
|
|
|
|
- if (!t->discard_alignment)
|
|
|
- t->discard_alignment =
|
|
|
- b->discard_alignment & (b->discard_granularity - 1);
|
|
|
+ t->alignment_offset = lcm(t->alignment_offset, alignment)
|
|
|
+ & (max(t->physical_block_size, t->io_min) - 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;
|
|
|
- ret = -1;
|
|
|
- }
|
|
|
|
|
|
- /* Find lcm() of optimal I/O size and granularity */
|
|
|
- t->io_opt = lcm(t->io_opt, b->io_opt);
|
|
|
- t->discard_granularity = lcm(t->discard_granularity,
|
|
|
- b->discard_granularity);
|
|
|
+ /* 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 optimal I/O size is a multiple of io_min */
|
|
|
- if (t->io_min && t->io_opt % t->io_min)
|
|
|
- ret = -1;
|
|
|
+ /* Verify that top and bottom intervals line up */
|
|
|
+ if (max(top, bottom) & (min(top, bottom) - 1))
|
|
|
+ t->discard_misaligned = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ t->discard_granularity = max(t->discard_granularity,
|
|
|
+ b->discard_granularity);
|
|
|
+ t->discard_alignment = lcm(t->discard_alignment, alignment) &
|
|
|
+ (t->discard_granularity - 1);
|
|
|
+ }
|
|
|
|
|
|
- return ret;
|
|
|
+ return t->misaligned ? -1 : 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(blk_stack_limits);
|
|
|
|