aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/blk-settings.c')
-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