aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-12-14 20:56:57 -0500
committerNeilBrown <neilb@suse.de>2015-02-03 16:35:52 -0500
commit64590f45ddc7147fa1968147a1f5b5c436b728fe (patch)
treec33e8ce09d739bac929e8ca943a253cb03cafd12 /drivers/md
parent5c675f83c68fbdf9c0e103c1090b06be747fa62c (diff)
md: make merge_bvec_fn more robust in face of personality changes.
There is no locking around calls to merge_bvec_fn(), so it is possible that calls which coincide with a level (or personality) change could go wrong. So create a central dispatch point for these functions and use rcu_read_lock(). If the array is suspended, reject any merge that can be rejected. If not, we know it is safe to call the function. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/linear.c6
-rw-r--r--drivers/md/md.c24
-rw-r--r--drivers/md/md.h4
-rw-r--r--drivers/md/raid0.c7
-rw-r--r--drivers/md/raid1.c6
-rw-r--r--drivers/md/raid10.c7
-rw-r--r--drivers/md/raid5.c8
7 files changed, 42 insertions, 20 deletions
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 05108510d9cd..4c2a92ce2b0b 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -60,11 +60,10 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector)
60 * 60 *
61 * Return amount of bytes we can take at this offset 61 * Return amount of bytes we can take at this offset
62 */ 62 */
63static int linear_mergeable_bvec(struct request_queue *q, 63static int linear_mergeable_bvec(struct mddev *mddev,
64 struct bvec_merge_data *bvm, 64 struct bvec_merge_data *bvm,
65 struct bio_vec *biovec) 65 struct bio_vec *biovec)
66{ 66{
67 struct mddev *mddev = q->queuedata;
68 struct dev_info *dev0; 67 struct dev_info *dev0;
69 unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9; 68 unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9;
70 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); 69 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
@@ -213,8 +212,6 @@ static int linear_run (struct mddev *mddev)
213 mddev->private = conf; 212 mddev->private = conf;
214 md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); 213 md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
215 214
216 blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
217
218 ret = md_integrity_register(mddev); 215 ret = md_integrity_register(mddev);
219 if (ret) { 216 if (ret) {
220 kfree(conf); 217 kfree(conf);
@@ -361,6 +358,7 @@ static struct md_personality linear_personality =
361 .hot_add_disk = linear_add, 358 .hot_add_disk = linear_add,
362 .size = linear_size, 359 .size = linear_size,
363 .congested = linear_congested, 360 .congested = linear_congested,
361 .mergeable_bvec = linear_mergeable_bvec,
364}; 362};
365 363
366static int __init linear_init (void) 364static int __init linear_init (void)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index d45f52edb314..9f0ff7187136 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -339,6 +339,29 @@ static int md_congested(void *data, int bits)
339 return mddev_congested(mddev, bits); 339 return mddev_congested(mddev, bits);
340} 340}
341 341
342static int md_mergeable_bvec(struct request_queue *q,
343 struct bvec_merge_data *bvm,
344 struct bio_vec *biovec)
345{
346 struct mddev *mddev = q->queuedata;
347 int ret;
348 rcu_read_lock();
349 if (mddev->suspended) {
350 /* Must always allow one vec */
351 if (bvm->bi_size == 0)
352 ret = biovec->bv_len;
353 else
354 ret = 0;
355 } else {
356 struct md_personality *pers = mddev->pers;
357 if (pers && pers->mergeable_bvec)
358 ret = pers->mergeable_bvec(mddev, bvm, biovec);
359 else
360 ret = biovec->bv_len;
361 }
362 rcu_read_unlock();
363 return ret;
364}
342/* 365/*
343 * Generic flush handling for md 366 * Generic flush handling for md
344 */ 367 */
@@ -4925,6 +4948,7 @@ int md_run(struct mddev *mddev)
4925 if (mddev->queue) { 4948 if (mddev->queue) {
4926 mddev->queue->backing_dev_info.congested_data = mddev; 4949 mddev->queue->backing_dev_info.congested_data = mddev;
4927 mddev->queue->backing_dev_info.congested_fn = md_congested; 4950 mddev->queue->backing_dev_info.congested_fn = md_congested;
4951 blk_queue_merge_bvec(mddev->queue, md_mergeable_bvec);
4928 } 4952 }
4929 if (mddev->pers->sync_request) { 4953 if (mddev->pers->sync_request) {
4930 if (mddev->kobj.sd && 4954 if (mddev->kobj.sd &&
diff --git a/drivers/md/md.h b/drivers/md/md.h
index f2602280fac1..bee5b852c33f 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -499,6 +499,10 @@ struct md_personality
499 /* congested implements bdi.congested_fn(). 499 /* congested implements bdi.congested_fn().
500 * Will not be called while array is 'suspended' */ 500 * Will not be called while array is 'suspended' */
501 int (*congested)(struct mddev *mddev, int bits); 501 int (*congested)(struct mddev *mddev, int bits);
502 /* mergeable_bvec is use to implement ->merge_bvec_fn */
503 int (*mergeable_bvec)(struct mddev *mddev,
504 struct bvec_merge_data *bvm,
505 struct bio_vec *biovec);
502}; 506};
503 507
504struct md_sysfs_entry { 508struct md_sysfs_entry {
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 4b521eac5b69..3770c9675b17 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -350,17 +350,16 @@ static struct md_rdev *map_sector(struct mddev *mddev, struct strip_zone *zone,
350 350
351/** 351/**
352 * raid0_mergeable_bvec -- tell bio layer if two requests can be merged 352 * raid0_mergeable_bvec -- tell bio layer if two requests can be merged
353 * @q: request queue 353 * @mddev: the md device
354 * @bvm: properties of new bio 354 * @bvm: properties of new bio
355 * @biovec: the request that could be merged to it. 355 * @biovec: the request that could be merged to it.
356 * 356 *
357 * Return amount of bytes we can accept at this offset 357 * Return amount of bytes we can accept at this offset
358 */ 358 */
359static int raid0_mergeable_bvec(struct request_queue *q, 359static int raid0_mergeable_bvec(struct mddev *mddev,
360 struct bvec_merge_data *bvm, 360 struct bvec_merge_data *bvm,
361 struct bio_vec *biovec) 361 struct bio_vec *biovec)
362{ 362{
363 struct mddev *mddev = q->queuedata;
364 struct r0conf *conf = mddev->private; 363 struct r0conf *conf = mddev->private;
365 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); 364 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
366 sector_t sector_offset = sector; 365 sector_t sector_offset = sector;
@@ -465,7 +464,6 @@ static int raid0_run(struct mddev *mddev)
465 mddev->queue->backing_dev_info.ra_pages = 2* stripe; 464 mddev->queue->backing_dev_info.ra_pages = 2* stripe;
466 } 465 }
467 466
468 blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec);
469 dump_zones(mddev); 467 dump_zones(mddev);
470 468
471 ret = md_integrity_register(mddev); 469 ret = md_integrity_register(mddev);
@@ -724,6 +722,7 @@ static struct md_personality raid0_personality=
724 .takeover = raid0_takeover, 722 .takeover = raid0_takeover,
725 .quiesce = raid0_quiesce, 723 .quiesce = raid0_quiesce,
726 .congested = raid0_congested, 724 .congested = raid0_congested,
725 .mergeable_bvec = raid0_mergeable_bvec,
727}; 726};
728 727
729static int __init raid0_init (void) 728static int __init raid0_init (void)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 9ad7ce7091be..45c512a4b75d 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -701,11 +701,10 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
701 return best_disk; 701 return best_disk;
702} 702}
703 703
704static int raid1_mergeable_bvec(struct request_queue *q, 704static int raid1_mergeable_bvec(struct mddev *mddev,
705 struct bvec_merge_data *bvm, 705 struct bvec_merge_data *bvm,
706 struct bio_vec *biovec) 706 struct bio_vec *biovec)
707{ 707{
708 struct mddev *mddev = q->queuedata;
709 struct r1conf *conf = mddev->private; 708 struct r1conf *conf = mddev->private;
710 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); 709 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
711 int max = biovec->bv_len; 710 int max = biovec->bv_len;
@@ -2946,8 +2945,6 @@ static int run(struct mddev *mddev)
2946 md_set_array_sectors(mddev, raid1_size(mddev, 0, 0)); 2945 md_set_array_sectors(mddev, raid1_size(mddev, 0, 0));
2947 2946
2948 if (mddev->queue) { 2947 if (mddev->queue) {
2949 blk_queue_merge_bvec(mddev->queue, raid1_mergeable_bvec);
2950
2951 if (discard_supported) 2948 if (discard_supported)
2952 queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, 2949 queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
2953 mddev->queue); 2950 mddev->queue);
@@ -3183,6 +3180,7 @@ static struct md_personality raid1_personality =
3183 .quiesce = raid1_quiesce, 3180 .quiesce = raid1_quiesce,
3184 .takeover = raid1_takeover, 3181 .takeover = raid1_takeover,
3185 .congested = raid1_congested, 3182 .congested = raid1_congested,
3183 .mergeable_bvec = raid1_mergeable_bvec,
3186}; 3184};
3187 3185
3188static int __init raid_init(void) 3186static int __init raid_init(void)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index fb6b88674e87..407c81a820f4 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -674,7 +674,7 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev)
674 674
675/** 675/**
676 * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged 676 * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged
677 * @q: request queue 677 * @mddev: the md device
678 * @bvm: properties of new bio 678 * @bvm: properties of new bio
679 * @biovec: the request that could be merged to it. 679 * @biovec: the request that could be merged to it.
680 * 680 *
@@ -682,11 +682,10 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev)
682 * This requires checking for end-of-chunk if near_copies != raid_disks, 682 * This requires checking for end-of-chunk if near_copies != raid_disks,
683 * and for subordinate merge_bvec_fns if merge_check_needed. 683 * and for subordinate merge_bvec_fns if merge_check_needed.
684 */ 684 */
685static int raid10_mergeable_bvec(struct request_queue *q, 685static int raid10_mergeable_bvec(struct mddev *mddev,
686 struct bvec_merge_data *bvm, 686 struct bvec_merge_data *bvm,
687 struct bio_vec *biovec) 687 struct bio_vec *biovec)
688{ 688{
689 struct mddev *mddev = q->queuedata;
690 struct r10conf *conf = mddev->private; 689 struct r10conf *conf = mddev->private;
691 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); 690 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
692 int max; 691 int max;
@@ -3756,7 +3755,6 @@ static int run(struct mddev *mddev)
3756 stripe /= conf->geo.near_copies; 3755 stripe /= conf->geo.near_copies;
3757 if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) 3756 if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
3758 mddev->queue->backing_dev_info.ra_pages = 2 * stripe; 3757 mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
3759 blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
3760 } 3758 }
3761 3759
3762 if (md_integrity_register(mddev)) 3760 if (md_integrity_register(mddev))
@@ -4717,6 +4715,7 @@ static struct md_personality raid10_personality =
4717 .start_reshape = raid10_start_reshape, 4715 .start_reshape = raid10_start_reshape,
4718 .finish_reshape = raid10_finish_reshape, 4716 .finish_reshape = raid10_finish_reshape,
4719 .congested = raid10_congested, 4717 .congested = raid10_congested,
4718 .mergeable_bvec = raid10_mergeable_bvec,
4720}; 4719};
4721 4720
4722static int __init raid_init(void) 4721static int __init raid_init(void)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 502a908149c6..2d4a2cc85eb2 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -4170,11 +4170,10 @@ static int raid5_congested(struct mddev *mddev, int bits)
4170/* We want read requests to align with chunks where possible, 4170/* We want read requests to align with chunks where possible,
4171 * but write requests don't need to. 4171 * but write requests don't need to.
4172 */ 4172 */
4173static int raid5_mergeable_bvec(struct request_queue *q, 4173static int raid5_mergeable_bvec(struct mddev *mddev,
4174 struct bvec_merge_data *bvm, 4174 struct bvec_merge_data *bvm,
4175 struct bio_vec *biovec) 4175 struct bio_vec *biovec)
4176{ 4176{
4177 struct mddev *mddev = q->queuedata;
4178 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); 4177 sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
4179 int max; 4178 int max;
4180 unsigned int chunk_sectors = mddev->chunk_sectors; 4179 unsigned int chunk_sectors = mddev->chunk_sectors;
@@ -6237,8 +6236,6 @@ static int run(struct mddev *mddev)
6237 if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) 6236 if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
6238 mddev->queue->backing_dev_info.ra_pages = 2 * stripe; 6237 mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
6239 6238
6240 blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
6241
6242 chunk_size = mddev->chunk_sectors << 9; 6239 chunk_size = mddev->chunk_sectors << 9;
6243 blk_queue_io_min(mddev->queue, chunk_size); 6240 blk_queue_io_min(mddev->queue, chunk_size);
6244 blk_queue_io_opt(mddev->queue, chunk_size * 6241 blk_queue_io_opt(mddev->queue, chunk_size *
@@ -7113,6 +7110,7 @@ static struct md_personality raid6_personality =
7113 .quiesce = raid5_quiesce, 7110 .quiesce = raid5_quiesce,
7114 .takeover = raid6_takeover, 7111 .takeover = raid6_takeover,
7115 .congested = raid5_congested, 7112 .congested = raid5_congested,
7113 .mergeable_bvec = raid5_mergeable_bvec,
7116}; 7114};
7117static struct md_personality raid5_personality = 7115static struct md_personality raid5_personality =
7118{ 7116{
@@ -7136,6 +7134,7 @@ static struct md_personality raid5_personality =
7136 .quiesce = raid5_quiesce, 7134 .quiesce = raid5_quiesce,
7137 .takeover = raid5_takeover, 7135 .takeover = raid5_takeover,
7138 .congested = raid5_congested, 7136 .congested = raid5_congested,
7137 .mergeable_bvec = raid5_mergeable_bvec,
7139}; 7138};
7140 7139
7141static struct md_personality raid4_personality = 7140static struct md_personality raid4_personality =
@@ -7160,6 +7159,7 @@ static struct md_personality raid4_personality =
7160 .quiesce = raid5_quiesce, 7159 .quiesce = raid5_quiesce,
7161 .takeover = raid4_takeover, 7160 .takeover = raid4_takeover,
7162 .congested = raid5_congested, 7161 .congested = raid5_congested,
7162 .mergeable_bvec = raid5_mergeable_bvec,
7163}; 7163};
7164 7164
7165static int __init raid5_init(void) 7165static int __init raid5_init(void)