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 | |
| 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>
| -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) |
