aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/multipath.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-12-14 20:56:56 -0500
committerNeilBrown <neilb@suse.de>2015-02-03 16:35:52 -0500
commit5c675f83c68fbdf9c0e103c1090b06be747fa62c (patch)
tree9a03f84c7a3bcef7d5e757dc28ce7bd5d205b26a /drivers/md/multipath.c
parent85572d7c75fd5b9fa3fc911e1c99c68ec74903a0 (diff)
md: make ->congested robust against personality changes.
There is currently no locking around calls to the 'congested' bdi function. If called at an awkward time while an array is being converted from one level (or personality) to another, there is a tiny chance of running code in an unreferenced module etc. So add a 'congested' function to the md_personality operations structure, and call it with appropriate locking from a central 'mddev_congested'. When the array personality is changing the array will be 'suspended' so no IO is processed. If mddev_congested detects this, it simply reports that the array is congested, which is a safe guess. As mddev_suspend calls synchronize_rcu(), mddev_congested can avoid races by included the whole call inside an rcu_read_lock() region. This require that the congested functions for all subordinate devices can be run under rcu_lock. Fortunately this is the case. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/multipath.c')
-rw-r--r--drivers/md/multipath.c10
1 files changed, 2 insertions, 8 deletions
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 399272f9c042..fedb1b31877d 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -153,15 +153,11 @@ static void multipath_status (struct seq_file *seq, struct mddev *mddev)
153 seq_printf (seq, "]"); 153 seq_printf (seq, "]");
154} 154}
155 155
156static int multipath_congested(void *data, int bits) 156static int multipath_congested(struct mddev *mddev, int bits)
157{ 157{
158 struct mddev *mddev = data;
159 struct mpconf *conf = mddev->private; 158 struct mpconf *conf = mddev->private;
160 int i, ret = 0; 159 int i, ret = 0;
161 160
162 if (mddev_congested(mddev, bits))
163 return 1;
164
165 rcu_read_lock(); 161 rcu_read_lock();
166 for (i = 0; i < mddev->raid_disks ; i++) { 162 for (i = 0; i < mddev->raid_disks ; i++) {
167 struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev); 163 struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev);
@@ -489,9 +485,6 @@ static int multipath_run (struct mddev *mddev)
489 */ 485 */
490 md_set_array_sectors(mddev, multipath_size(mddev, 0, 0)); 486 md_set_array_sectors(mddev, multipath_size(mddev, 0, 0));
491 487
492 mddev->queue->backing_dev_info.congested_fn = multipath_congested;
493 mddev->queue->backing_dev_info.congested_data = mddev;
494
495 if (md_integrity_register(mddev)) 488 if (md_integrity_register(mddev))
496 goto out_free_conf; 489 goto out_free_conf;
497 490
@@ -533,6 +526,7 @@ static struct md_personality multipath_personality =
533 .hot_add_disk = multipath_add_disk, 526 .hot_add_disk = multipath_add_disk,
534 .hot_remove_disk= multipath_remove_disk, 527 .hot_remove_disk= multipath_remove_disk,
535 .size = multipath_size, 528 .size = multipath_size,
529 .congested = multipath_congested,
536}; 530};
537 531
538static int __init multipath_init (void) 532static int __init multipath_init (void)