md: add proper merge_bvec handling to RAID0 and Linear.
[firefly-linux-kernel-4.4.55.git] / drivers / md / linear.c
index 67940741b19d5f7f2ec9c438cb058580d0437406..b0fcc7d02adb49b37275ccf9caa2c48465e886ad 100644 (file)
@@ -68,10 +68,19 @@ static int linear_mergeable_bvec(struct request_queue *q,
        struct dev_info *dev0;
        unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9;
        sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
+       int maxbytes = biovec->bv_len;
+       struct request_queue *subq;
 
        rcu_read_lock();
        dev0 = which_dev(mddev, sector);
        maxsectors = dev0->end_sector - sector;
+       subq = bdev_get_queue(dev0->rdev->bdev);
+       if (subq->merge_bvec_fn) {
+               bvm->bi_bdev = dev0->rdev->bdev;
+               bvm->bi_sector -= dev0->end_sector - dev0->rdev->sectors;
+               maxbytes = min(maxbytes, subq->merge_bvec_fn(subq, bvm,
+                                                            biovec));
+       }
        rcu_read_unlock();
 
        if (maxsectors < bio_sectors)
@@ -80,12 +89,12 @@ static int linear_mergeable_bvec(struct request_queue *q,
                maxsectors -= bio_sectors;
 
        if (maxsectors <= (PAGE_SIZE >> 9 ) && bio_sectors == 0)
-               return biovec->bv_len;
-       /* The bytes available at this offset could be really big,
-        * so we cap at 2^31 to avoid overflow */
-       if (maxsectors > (1 << (31-9)))
-               return 1<<31;
-       return maxsectors << 9;
+               return maxbytes;
+
+       if (maxsectors > (maxbytes >> 9))
+               return maxbytes;
+       else
+               return maxsectors << 9;
 }
 
 static int linear_congested(void *data, int bits)
@@ -158,15 +167,6 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
 
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
-               /* as we don't honour merge_bvec_fn, we must never risk
-                * violating it, so limit max_segments to 1 lying within
-                * a single page.
-                */
-               if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
-                       blk_queue_max_segments(mddev->queue, 1);
-                       blk_queue_segment_boundary(mddev->queue,
-                                                  PAGE_CACHE_SIZE - 1);
-               }
 
                conf->array_sectors += rdev->sectors;
                cnt++;