diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-settings.c | 87 |
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) | |||
517 | int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, | 517 | int 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 | } |
596 | EXPORT_SYMBOL(blk_stack_limits); | 609 | EXPORT_SYMBOL(blk_stack_limits); |
597 | 610 | ||