block: Correct handling of bottom device misaligment
Martin K. Petersen [Mon, 11 Jan 2010 08:21:47 +0000 (03:21 -0500)]
The top device misalignment flag would not be set if the added bottom
device was already misaligned as opposed to causing a stacking failure.

Also massage the reporting so that an error is only returned if adding
the bottom device caused the misalignment.  I.e. don't return an error
if the top is already flagged as misaligned.

Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

block/blk-settings.c

index d52d4ad..127f825 100644 (file)
@@ -528,7 +528,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                     sector_t offset)
 {
        sector_t alignment;
-       unsigned int top, bottom;
+       unsigned int top, bottom, ret = 0;
 
        t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
        t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
@@ -546,6 +546,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
        t->max_segment_size = min_not_zero(t->max_segment_size,
                                           b->max_segment_size);
 
+       t->misaligned |= b->misaligned;
+
        alignment = queue_limit_alignment_offset(b, offset);
 
        /* Bottom device has different alignment.  Check that it is
@@ -558,8 +560,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                bottom = max(b->physical_block_size, b->io_min) + alignment;
 
                /* Verify that top and bottom intervals line up */
-               if (max(top, bottom) & (min(top, bottom) - 1))
+               if (max(top, bottom) & (min(top, bottom) - 1)) {
                        t->misaligned = 1;
+                       ret = -1;
+               }
        }
 
        t->logical_block_size = max(t->logical_block_size,
@@ -578,18 +582,21 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
        if (t->physical_block_size & (t->logical_block_size - 1)) {
                t->physical_block_size = t->logical_block_size;
                t->misaligned = 1;
+               ret = -1;
        }
 
        /* Minimum I/O a multiple of the physical block size? */
        if (t->io_min & (t->physical_block_size - 1)) {
                t->io_min = t->physical_block_size;
                t->misaligned = 1;
+               ret = -1;
        }
 
        /* Optimal I/O a multiple of the physical block size? */
        if (t->io_opt & (t->physical_block_size - 1)) {
                t->io_opt = 0;
                t->misaligned = 1;
+               ret = -1;
        }
 
        /* Find lowest common alignment_offset */
@@ -597,8 +604,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                & (max(t->physical_block_size, t->io_min) - 1);
 
        /* Verify that new alignment_offset is on a logical block boundary */
-       if (t->alignment_offset & (t->logical_block_size - 1))
+       if (t->alignment_offset & (t->logical_block_size - 1)) {
                t->misaligned = 1;
+               ret = -1;
+       }
 
        /* Discard alignment and granularity */
        if (b->discard_granularity) {
@@ -626,7 +635,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                        (t->discard_granularity - 1);
        }
 
-       return t->misaligned ? -1 : 0;
+       return ret;
 }
 EXPORT_SYMBOL(blk_stack_limits);