Commit 9504e0864b58b4a304820dcf3755f1da80d5e72f

Authored by Martin K. Petersen
Committed by Jens Axboe
1 parent 65b32a573e

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