md/raid5: make chunk_aligned_read() split bios more cleanly.
authorNeilBrown <neilb@suse.com>
Wed, 5 Apr 2017 04:05:51 +0000 (14:05 +1000)
committerShaohua Li <shli@fb.com>
Tue, 11 Apr 2017 17:16:50 +0000 (10:16 -0700)
chunk_aligned_read() currently uses fs_bio_set - which is meant for
filesystems to use - and loops if multiple splits are needed, which is
not best practice.
As this is only used for READ requests, not writes, it is unlikely
to cause a problem.  However it is best to be consistent in how
we split bios, and to follow the pattern used in raid1/raid10.

So create a private bioset, bio_split, and use it to perform a single
split, submitting the remainder to generic_make_request() for later
processing.

Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Shaohua Li <shli@fb.com>
drivers/md/raid5.c
drivers/md/raid5.h

index f3692ff4262bce87e1cbf0fdeaaae4e5a4df0a73..356cd9c7c753eb656030d68cc4435f911d3ba18c 100644 (file)
@@ -5246,24 +5246,20 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
 static struct bio *chunk_aligned_read(struct mddev *mddev, struct bio *raid_bio)
 {
        struct bio *split;
+       sector_t sector = raid_bio->bi_iter.bi_sector;
+       unsigned chunk_sects = mddev->chunk_sectors;
+       unsigned sectors = chunk_sects - (sector & (chunk_sects-1));
 
-       do {
-               sector_t sector = raid_bio->bi_iter.bi_sector;
-               unsigned chunk_sects = mddev->chunk_sectors;
-               unsigned sectors = chunk_sects - (sector & (chunk_sects-1));
-
-               if (sectors < bio_sectors(raid_bio)) {
-                       split = bio_split(raid_bio, sectors, GFP_NOIO, fs_bio_set);
-                       bio_chain(split, raid_bio);
-               } else
-                       split = raid_bio;
+       if (sectors < bio_sectors(raid_bio)) {
+               struct r5conf *conf = mddev->private;
+               split = bio_split(raid_bio, sectors, GFP_NOIO, conf->bio_split);
+               bio_chain(split, raid_bio);
+               generic_make_request(raid_bio);
+               raid_bio = split;
+       }
 
-               if (!raid5_read_one_chunk(mddev, split)) {
-                       if (split != raid_bio)
-                               generic_make_request(raid_bio);
-                       return split;
-               }
-       } while (split != raid_bio);
+       if (!raid5_read_one_chunk(mddev, raid_bio))
+               return raid_bio;
 
        return NULL;
 }
@@ -6747,6 +6743,8 @@ static void free_conf(struct r5conf *conf)
                if (conf->disks[i].extra_page)
                        put_page(conf->disks[i].extra_page);
        kfree(conf->disks);
+       if (conf->bio_split)
+               bioset_free(conf->bio_split);
        kfree(conf->stripe_hashtbl);
        kfree(conf->pending_data);
        kfree(conf);
@@ -6922,6 +6920,9 @@ static struct r5conf *setup_conf(struct mddev *mddev)
                        goto abort;
        }
 
+       conf->bio_split = bioset_create(BIO_POOL_SIZE, 0);
+       if (!conf->bio_split)
+               goto abort;
        conf->mddev = mddev;
 
        if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
index cdc7f92e18065f9f8e67487c724aa0a9f242003b..625c7f16fd6b3e0db7e439f31a44c66ed3e1b8ba 100644 (file)
@@ -646,6 +646,7 @@ struct r5conf {
        int                     pool_size; /* number of disks in stripeheads in pool */
        spinlock_t              device_lock;
        struct disk_info        *disks;
+       struct bio_set          *bio_split;
 
        /* When taking over an array from a different personality, we store
         * the new thread here until we fully activate the array.