diff options
author | NeilBrown <neilb@suse.de> | 2014-12-14 20:56:57 -0500 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2015-02-03 16:35:52 -0500 |
commit | 64590f45ddc7147fa1968147a1f5b5c436b728fe (patch) | |
tree | c33e8ce09d739bac929e8ca943a253cb03cafd12 /drivers/md | |
parent | 5c675f83c68fbdf9c0e103c1090b06be747fa62c (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.c | 6 | ||||
-rw-r--r-- | drivers/md/md.c | 24 | ||||
-rw-r--r-- | drivers/md/md.h | 4 | ||||
-rw-r--r-- | drivers/md/raid0.c | 7 | ||||
-rw-r--r-- | drivers/md/raid1.c | 6 | ||||
-rw-r--r-- | drivers/md/raid10.c | 7 | ||||
-rw-r--r-- | drivers/md/raid5.c | 8 |
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 | */ |
63 | static int linear_mergeable_bvec(struct request_queue *q, | 63 | static 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 | ||
366 | static int __init linear_init (void) | 364 | static 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 | ||
342 | static 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 | ||
504 | struct md_sysfs_entry { | 508 | struct 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 | */ |
359 | static int raid0_mergeable_bvec(struct request_queue *q, | 359 | static 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 | ||
729 | static int __init raid0_init (void) | 728 | static 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 | ||
704 | static int raid1_mergeable_bvec(struct request_queue *q, | 704 | static 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 | ||
3188 | static int __init raid_init(void) | 3186 | static 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 | */ |
685 | static int raid10_mergeable_bvec(struct request_queue *q, | 685 | static 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 | ||
4722 | static int __init raid_init(void) | 4721 | static 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 | */ |
4173 | static int raid5_mergeable_bvec(struct request_queue *q, | 4173 | static 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 | }; |
7117 | static struct md_personality raid5_personality = | 7115 | static 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 | ||
7141 | static struct md_personality raid4_personality = | 7140 | static 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 | ||
7165 | static int __init raid5_init(void) | 7165 | static int __init raid5_init(void) |