Commit 9504e0864b58b4a304820dcf3755f1da80d5e72f
Committed by
Jens Axboe
1 parent
65b32a573e
Exists in
master
and in
39 other branches
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: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Showing 1 changed file with 50 additions and 37 deletions Side-by-side Diff
block/blk-settings.c
... | ... | @@ -517,10 +517,9 @@ |
517 | 517 | int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, |
518 | 518 | sector_t offset) |
519 | 519 | { |
520 | - int ret; | |
520 | + sector_t alignment; | |
521 | + unsigned int top, bottom, granularity; | |
521 | 522 | |
522 | - ret = 0; | |
523 | - | |
524 | 523 | t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); |
525 | 524 | t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); |
526 | 525 | t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn); |
... | ... | @@ -537,6 +536,19 @@ |
537 | 536 | t->max_segment_size = min_not_zero(t->max_segment_size, |
538 | 537 | b->max_segment_size); |
539 | 538 | |
539 | + granularity = max(b->physical_block_size, b->io_min); | |
540 | + alignment = b->alignment_offset - (offset & (granularity - 1)); | |
541 | + | |
542 | + if (t->alignment_offset != alignment) { | |
543 | + | |
544 | + top = max(t->physical_block_size, t->io_min) | |
545 | + + t->alignment_offset; | |
546 | + bottom = granularity + alignment; | |
547 | + | |
548 | + if (max(top, bottom) & (min(top, bottom) - 1)) | |
549 | + t->misaligned = 1; | |
550 | + } | |
551 | + | |
540 | 552 | t->logical_block_size = max(t->logical_block_size, |
541 | 553 | b->logical_block_size); |
542 | 554 | |
543 | 555 | |
544 | 556 | |
545 | 557 | |
546 | 558 | |
547 | 559 | |
548 | 560 | |
549 | 561 | |
550 | 562 | |
551 | 563 | |
552 | 564 | |
553 | 565 | |
... | ... | @@ -544,54 +556,55 @@ |
544 | 556 | b->physical_block_size); |
545 | 557 | |
546 | 558 | t->io_min = max(t->io_min, b->io_min); |
559 | + t->io_opt = lcm(t->io_opt, b->io_opt); | |
560 | + | |
547 | 561 | t->no_cluster |= b->no_cluster; |
548 | 562 | t->discard_zeroes_data &= b->discard_zeroes_data; |
549 | 563 | |
550 | - /* Bottom device offset aligned? */ | |
551 | - if (offset && | |
552 | - (offset & (b->physical_block_size - 1)) != b->alignment_offset) { | |
564 | + if (t->physical_block_size & (t->logical_block_size - 1)) { | |
565 | + t->physical_block_size = t->logical_block_size; | |
553 | 566 | t->misaligned = 1; |
554 | - ret = -1; | |
555 | 567 | } |
556 | 568 | |
557 | - /* | |
558 | - * Temporarily disable discard granularity. It's currently buggy | |
559 | - * since we default to 0 for discard_granularity, hence this | |
560 | - * "failure" will always trigger for non-zero offsets. | |
561 | - */ | |
562 | -#if 0 | |
563 | - if (offset && | |
564 | - (offset & (b->discard_granularity - 1)) != b->discard_alignment) { | |
565 | - t->discard_misaligned = 1; | |
566 | - ret = -1; | |
569 | + if (t->io_min & (t->physical_block_size - 1)) { | |
570 | + t->io_min = t->physical_block_size; | |
571 | + t->misaligned = 1; | |
567 | 572 | } |
568 | -#endif | |
569 | 573 | |
570 | - /* If top has no alignment offset, inherit from bottom */ | |
571 | - if (!t->alignment_offset) | |
572 | - t->alignment_offset = | |
573 | - b->alignment_offset & (b->physical_block_size - 1); | |
574 | + if (t->io_opt & (t->physical_block_size - 1)) { | |
575 | + t->io_opt = 0; | |
576 | + t->misaligned = 1; | |
577 | + } | |
574 | 578 | |
575 | - if (!t->discard_alignment) | |
576 | - t->discard_alignment = | |
577 | - b->discard_alignment & (b->discard_granularity - 1); | |
579 | + t->alignment_offset = lcm(t->alignment_offset, alignment) | |
580 | + & (max(t->physical_block_size, t->io_min) - 1); | |
578 | 581 | |
579 | - /* Top device aligned on logical block boundary? */ | |
580 | - if (t->alignment_offset & (t->logical_block_size - 1)) { | |
582 | + if (t->alignment_offset & (t->logical_block_size - 1)) | |
581 | 583 | t->misaligned = 1; |
582 | - ret = -1; | |
583 | - } | |
584 | 584 | |
585 | - /* Find lcm() of optimal I/O size and granularity */ | |
586 | - t->io_opt = lcm(t->io_opt, b->io_opt); | |
587 | - t->discard_granularity = lcm(t->discard_granularity, | |
588 | - b->discard_granularity); | |
585 | + /* Discard alignment and granularity */ | |
586 | + if (b->discard_granularity) { | |
589 | 587 | |
590 | - /* Verify that optimal I/O size is a multiple of io_min */ | |
591 | - if (t->io_min && t->io_opt % t->io_min) | |
592 | - ret = -1; | |
588 | + alignment = b->discard_alignment - | |
589 | + (offset & (b->discard_granularity - 1)); | |
593 | 590 | |
594 | - return ret; | |
591 | + if (t->discard_granularity != 0 && | |
592 | + t->discard_alignment != alignment) { | |
593 | + top = t->discard_granularity + t->discard_alignment; | |
594 | + bottom = b->discard_granularity + alignment; | |
595 | + | |
596 | + /* Verify that top and bottom intervals line up */ | |
597 | + if (max(top, bottom) & (min(top, bottom) - 1)) | |
598 | + t->discard_misaligned = 1; | |
599 | + } | |
600 | + | |
601 | + t->discard_granularity = max(t->discard_granularity, | |
602 | + b->discard_granularity); | |
603 | + t->discard_alignment = lcm(t->discard_alignment, alignment) & | |
604 | + (t->discard_granularity - 1); | |
605 | + } | |
606 | + | |
607 | + return t->misaligned ? -1 : 0; | |
595 | 608 | } |
596 | 609 | EXPORT_SYMBOL(blk_stack_limits); |
597 | 610 |