aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2009-12-21 09:55:51 -0500
committerJens Axboe <jens.axboe@oracle.com>2009-12-21 09:55:51 -0500
commit9504e0864b58b4a304820dcf3755f1da80d5e72f (patch)
tree1e5bc5e7b2c57b343fab13709178be3aff6f477e /block
parent65b32a573eefa1cdd3cbe5ea59326308e6c3b9ad (diff)
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>
Diffstat (limited to 'block')
-rw-r--r--block/blk-settings.c87
1 files changed, 50 insertions, 37 deletions
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 6ae118d6e193..e14fcbcedbfa 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -517,9 +517,8 @@ static unsigned int lcm(unsigned int a, unsigned int b)
517int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, 517int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
518 sector_t offset) 518 sector_t offset)
519{ 519{
520 int ret; 520 sector_t alignment;
521 521 unsigned int top, bottom, granularity;
522 ret = 0;
523 522
524 t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); 523 t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
525 t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); 524 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 t->max_segment_size = min_not_zero(t->max_segment_size, 536 t->max_segment_size = min_not_zero(t->max_segment_size,
538 b->max_segment_size); 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 t->logical_block_size = max(t->logical_block_size, 552 t->logical_block_size = max(t->logical_block_size,
541 b->logical_block_size); 553 b->logical_block_size);
542 554
@@ -544,54 +556,55 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
544 b->physical_block_size); 556 b->physical_block_size);
545 557
546 t->io_min = max(t->io_min, b->io_min); 558 t->io_min = max(t->io_min, b->io_min);
559 t->io_opt = lcm(t->io_opt, b->io_opt);
560
547 t->no_cluster |= b->no_cluster; 561 t->no_cluster |= b->no_cluster;
548 t->discard_zeroes_data &= b->discard_zeroes_data; 562 t->discard_zeroes_data &= b->discard_zeroes_data;
549 563
550 /* Bottom device offset aligned? */ 564 if (t->physical_block_size & (t->logical_block_size - 1)) {
551 if (offset && 565 t->physical_block_size = t->logical_block_size;
552 (offset & (b->physical_block_size - 1)) != b->alignment_offset) {
553 t->misaligned = 1; 566 t->misaligned = 1;
554 ret = -1;
555 } 567 }
556 568
557 /* 569 if (t->io_min & (t->physical_block_size - 1)) {
558 * Temporarily disable discard granularity. It's currently buggy 570 t->io_min = t->physical_block_size;
559 * since we default to 0 for discard_granularity, hence this 571 t->misaligned = 1;
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;
567 } 572 }
568#endif
569 573
570 /* If top has no alignment offset, inherit from bottom */ 574 if (t->io_opt & (t->physical_block_size - 1)) {
571 if (!t->alignment_offset) 575 t->io_opt = 0;
572 t->alignment_offset = 576 t->misaligned = 1;
573 b->alignment_offset & (b->physical_block_size - 1); 577 }
574 578
575 if (!t->discard_alignment) 579 t->alignment_offset = lcm(t->alignment_offset, alignment)
576 t->discard_alignment = 580 & (max(t->physical_block_size, t->io_min) - 1);
577 b->discard_alignment & (b->discard_granularity - 1);
578 581
579 /* Top device aligned on logical block boundary? */ 582 if (t->alignment_offset & (t->logical_block_size - 1))
580 if (t->alignment_offset & (t->logical_block_size - 1)) {
581 t->misaligned = 1; 583 t->misaligned = 1;
582 ret = -1;
583 }
584 584
585 /* Find lcm() of optimal I/O size and granularity */ 585 /* Discard alignment and granularity */
586 t->io_opt = lcm(t->io_opt, b->io_opt); 586 if (b->discard_granularity) {
587 t->discard_granularity = lcm(t->discard_granularity, 587
588 b->discard_granularity); 588 alignment = b->discard_alignment -
589 (offset & (b->discard_granularity - 1));
590
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;
589 595
590 /* Verify that optimal I/O size is a multiple of io_min */ 596 /* Verify that top and bottom intervals line up */
591 if (t->io_min && t->io_opt % t->io_min) 597 if (max(top, bottom) & (min(top, bottom) - 1))
592 ret = -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 }
593 606
594 return ret; 607 return t->misaligned ? -1 : 0;
595} 608}
596EXPORT_SYMBOL(blk_stack_limits); 609EXPORT_SYMBOL(blk_stack_limits);
597 610