aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/linear.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/linear.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/linear.c')
-rw-r--r--drivers/md/linear.c9
1 files changed, 2 insertions, 7 deletions
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 64713b77df1c..05108510d9cd 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -97,15 +97,11 @@ static int linear_mergeable_bvec(struct request_queue *q,
97 return maxsectors << 9; 97 return maxsectors << 9;
98} 98}
99 99
100static int linear_congested(void *data, int bits) 100static int linear_congested(struct mddev *mddev, int bits)
101{ 101{
102 struct mddev *mddev = data;
103 struct linear_conf *conf; 102 struct linear_conf *conf;
104 int i, ret = 0; 103 int i, ret = 0;
105 104
106 if (mddev_congested(mddev, bits))
107 return 1;
108
109 rcu_read_lock(); 105 rcu_read_lock();
110 conf = rcu_dereference(mddev->private); 106 conf = rcu_dereference(mddev->private);
111 107
@@ -218,8 +214,6 @@ static int linear_run (struct mddev *mddev)
218 md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); 214 md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
219 215
220 blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); 216 blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
221 mddev->queue->backing_dev_info.congested_fn = linear_congested;
222 mddev->queue->backing_dev_info.congested_data = mddev;
223 217
224 ret = md_integrity_register(mddev); 218 ret = md_integrity_register(mddev);
225 if (ret) { 219 if (ret) {
@@ -366,6 +360,7 @@ static struct md_personality linear_personality =
366 .status = linear_status, 360 .status = linear_status,
367 .hot_add_disk = linear_add, 361 .hot_add_disk = linear_add,
368 .size = linear_size, 362 .size = linear_size,
363 .congested = linear_congested,
369}; 364};
370 365
371static int __init linear_init (void) 366static int __init linear_init (void)