diff options
Diffstat (limited to 'block/blk-settings.c')
-rw-r--r-- | block/blk-settings.c | 140 |
1 files changed, 103 insertions, 37 deletions
diff --git a/block/blk-settings.c b/block/blk-settings.c index 6ae118d6e193..5eeb9e0d256e 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c | |||
@@ -505,21 +505,30 @@ static unsigned int lcm(unsigned int a, unsigned int b) | |||
505 | 505 | ||
506 | /** | 506 | /** |
507 | * blk_stack_limits - adjust queue_limits for stacked devices | 507 | * blk_stack_limits - adjust queue_limits for stacked devices |
508 | * @t: the stacking driver limits (top) | 508 | * @t: the stacking driver limits (top device) |
509 | * @b: the underlying queue limits (bottom) | 509 | * @b: the underlying queue limits (bottom, component device) |
510 | * @offset: offset to beginning of data within component device | 510 | * @offset: offset to beginning of data within component device |
511 | * | 511 | * |
512 | * Description: | 512 | * Description: |
513 | * Merges two queue_limit structs. Returns 0 if alignment didn't | 513 | * This function is used by stacking drivers like MD and DM to ensure |
514 | * change. Returns -1 if adding the bottom device caused | 514 | * that all component devices have compatible block sizes and |
515 | * misalignment. | 515 | * alignments. The stacking driver must provide a queue_limits |
516 | * struct (top) and then iteratively call the stacking function for | ||
517 | * all component (bottom) devices. The stacking function will | ||
518 | * attempt to combine the values and ensure proper alignment. | ||
519 | * | ||
520 | * Returns 0 if the top and bottom queue_limits are compatible. The | ||
521 | * top device's block sizes and alignment offsets may be adjusted to | ||
522 | * ensure alignment with the bottom device. If no compatible sizes | ||
523 | * and alignments exist, -1 is returned and the resulting top | ||
524 | * queue_limits will have the misaligned flag set to indicate that | ||
525 | * the alignment_offset is undefined. | ||
516 | */ | 526 | */ |
517 | int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, | 527 | int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, |
518 | sector_t offset) | 528 | sector_t offset) |
519 | { | 529 | { |
520 | int ret; | 530 | sector_t alignment; |
521 | 531 | unsigned int top, bottom, ret = 0; | |
522 | ret = 0; | ||
523 | 532 | ||
524 | t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); | 533 | 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); | 534 | t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); |
@@ -537,6 +546,26 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, | |||
537 | t->max_segment_size = min_not_zero(t->max_segment_size, | 546 | t->max_segment_size = min_not_zero(t->max_segment_size, |
538 | b->max_segment_size); | 547 | b->max_segment_size); |
539 | 548 | ||
549 | t->misaligned |= b->misaligned; | ||
550 | |||
551 | alignment = queue_limit_alignment_offset(b, offset); | ||
552 | |||
553 | /* Bottom device has different alignment. Check that it is | ||
554 | * compatible with the current top alignment. | ||
555 | */ | ||
556 | if (t->alignment_offset != alignment) { | ||
557 | |||
558 | top = max(t->physical_block_size, t->io_min) | ||
559 | + t->alignment_offset; | ||
560 | bottom = max(b->physical_block_size, b->io_min) + alignment; | ||
561 | |||
562 | /* Verify that top and bottom intervals line up */ | ||
563 | if (max(top, bottom) & (min(top, bottom) - 1)) { | ||
564 | t->misaligned = 1; | ||
565 | ret = -1; | ||
566 | } | ||
567 | } | ||
568 | |||
540 | t->logical_block_size = max(t->logical_block_size, | 569 | t->logical_block_size = max(t->logical_block_size, |
541 | b->logical_block_size); | 570 | b->logical_block_size); |
542 | 571 | ||
@@ -544,58 +573,95 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, | |||
544 | b->physical_block_size); | 573 | b->physical_block_size); |
545 | 574 | ||
546 | t->io_min = max(t->io_min, b->io_min); | 575 | t->io_min = max(t->io_min, b->io_min); |
576 | t->io_opt = lcm(t->io_opt, b->io_opt); | ||
577 | |||
547 | t->no_cluster |= b->no_cluster; | 578 | t->no_cluster |= b->no_cluster; |
548 | t->discard_zeroes_data &= b->discard_zeroes_data; | 579 | t->discard_zeroes_data &= b->discard_zeroes_data; |
549 | 580 | ||
550 | /* Bottom device offset aligned? */ | 581 | /* Physical block size a multiple of the logical block size? */ |
551 | if (offset && | 582 | if (t->physical_block_size & (t->logical_block_size - 1)) { |
552 | (offset & (b->physical_block_size - 1)) != b->alignment_offset) { | 583 | t->physical_block_size = t->logical_block_size; |
553 | t->misaligned = 1; | 584 | t->misaligned = 1; |
554 | ret = -1; | 585 | ret = -1; |
555 | } | 586 | } |
556 | 587 | ||
557 | /* | 588 | /* Minimum I/O a multiple of the physical block size? */ |
558 | * Temporarily disable discard granularity. It's currently buggy | 589 | if (t->io_min & (t->physical_block_size - 1)) { |
559 | * since we default to 0 for discard_granularity, hence this | 590 | t->io_min = t->physical_block_size; |
560 | * "failure" will always trigger for non-zero offsets. | 591 | t->misaligned = 1; |
561 | */ | ||
562 | #if 0 | ||
563 | if (offset && | ||
564 | (offset & (b->discard_granularity - 1)) != b->discard_alignment) { | ||
565 | t->discard_misaligned = 1; | ||
566 | ret = -1; | 592 | ret = -1; |
567 | } | 593 | } |
568 | #endif | ||
569 | 594 | ||
570 | /* If top has no alignment offset, inherit from bottom */ | 595 | /* Optimal I/O a multiple of the physical block size? */ |
571 | if (!t->alignment_offset) | 596 | if (t->io_opt & (t->physical_block_size - 1)) { |
572 | t->alignment_offset = | 597 | t->io_opt = 0; |
573 | b->alignment_offset & (b->physical_block_size - 1); | 598 | t->misaligned = 1; |
599 | ret = -1; | ||
600 | } | ||
574 | 601 | ||
575 | if (!t->discard_alignment) | 602 | /* Find lowest common alignment_offset */ |
576 | t->discard_alignment = | 603 | t->alignment_offset = lcm(t->alignment_offset, alignment) |
577 | b->discard_alignment & (b->discard_granularity - 1); | 604 | & (max(t->physical_block_size, t->io_min) - 1); |
578 | 605 | ||
579 | /* Top device aligned on logical block boundary? */ | 606 | /* Verify that new alignment_offset is on a logical block boundary */ |
580 | if (t->alignment_offset & (t->logical_block_size - 1)) { | 607 | if (t->alignment_offset & (t->logical_block_size - 1)) { |
581 | t->misaligned = 1; | 608 | t->misaligned = 1; |
582 | ret = -1; | 609 | ret = -1; |
583 | } | 610 | } |
584 | 611 | ||
585 | /* Find lcm() of optimal I/O size and granularity */ | 612 | /* Discard alignment and granularity */ |
586 | t->io_opt = lcm(t->io_opt, b->io_opt); | 613 | if (b->discard_granularity) { |
587 | t->discard_granularity = lcm(t->discard_granularity, | 614 | unsigned int granularity = b->discard_granularity; |
588 | b->discard_granularity); | 615 | offset &= granularity - 1; |
589 | 616 | ||
590 | /* Verify that optimal I/O size is a multiple of io_min */ | 617 | alignment = (granularity + b->discard_alignment - offset) |
591 | if (t->io_min && t->io_opt % t->io_min) | 618 | & (granularity - 1); |
592 | ret = -1; | 619 | |
620 | if (t->discard_granularity != 0 && | ||
621 | t->discard_alignment != alignment) { | ||
622 | top = t->discard_granularity + t->discard_alignment; | ||
623 | bottom = b->discard_granularity + alignment; | ||
624 | |||
625 | /* Verify that top and bottom intervals line up */ | ||
626 | if (max(top, bottom) & (min(top, bottom) - 1)) | ||
627 | t->discard_misaligned = 1; | ||
628 | } | ||
629 | |||
630 | t->max_discard_sectors = min_not_zero(t->max_discard_sectors, | ||
631 | b->max_discard_sectors); | ||
632 | t->discard_granularity = max(t->discard_granularity, | ||
633 | b->discard_granularity); | ||
634 | t->discard_alignment = lcm(t->discard_alignment, alignment) & | ||
635 | (t->discard_granularity - 1); | ||
636 | } | ||
593 | 637 | ||
594 | return ret; | 638 | return ret; |
595 | } | 639 | } |
596 | EXPORT_SYMBOL(blk_stack_limits); | 640 | EXPORT_SYMBOL(blk_stack_limits); |
597 | 641 | ||
598 | /** | 642 | /** |
643 | * bdev_stack_limits - adjust queue limits for stacked drivers | ||
644 | * @t: the stacking driver limits (top device) | ||
645 | * @bdev: the component block_device (bottom) | ||
646 | * @start: first data sector within component device | ||
647 | * | ||
648 | * Description: | ||
649 | * Merges queue limits for a top device and a block_device. Returns | ||
650 | * 0 if alignment didn't change. Returns -1 if adding the bottom | ||
651 | * device caused misalignment. | ||
652 | */ | ||
653 | int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, | ||
654 | sector_t start) | ||
655 | { | ||
656 | struct request_queue *bq = bdev_get_queue(bdev); | ||
657 | |||
658 | start += get_start_sect(bdev); | ||
659 | |||
660 | return blk_stack_limits(t, &bq->limits, start << 9); | ||
661 | } | ||
662 | EXPORT_SYMBOL(bdev_stack_limits); | ||
663 | |||
664 | /** | ||
599 | * disk_stack_limits - adjust queue limits for stacked drivers | 665 | * disk_stack_limits - adjust queue limits for stacked drivers |
600 | * @disk: MD/DM gendisk (top) | 666 | * @disk: MD/DM gendisk (top) |
601 | * @bdev: the underlying block device (bottom) | 667 | * @bdev: the underlying block device (bottom) |