aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/raid0.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/raid0.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/raid0.c')
-rw-r--r--drivers/md/raid0.c9
1 files changed, 2 insertions, 7 deletions
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index ba6b85de96d2..4b521eac5b69 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -25,17 +25,13 @@
25#include "raid0.h" 25#include "raid0.h"
26#include "raid5.h" 26#include "raid5.h"
27 27
28static int raid0_congested(void *data, int bits) 28static int raid0_congested(struct mddev *mddev, int bits)
29{ 29{
30 struct mddev *mddev = data;
31 struct r0conf *conf = mddev->private; 30 struct r0conf *conf = mddev->private;
32 struct md_rdev **devlist = conf->devlist; 31 struct md_rdev **devlist = conf->devlist;
33 int raid_disks = conf->strip_zone[0].nb_dev; 32 int raid_disks = conf->strip_zone[0].nb_dev;
34 int i, ret = 0; 33 int i, ret = 0;
35 34
36 if (mddev_congested(mddev, bits))
37 return 1;
38
39 for (i = 0; i < raid_disks && !ret ; i++) { 35 for (i = 0; i < raid_disks && !ret ; i++) {
40 struct request_queue *q = bdev_get_queue(devlist[i]->bdev); 36 struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
41 37
@@ -263,8 +259,6 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
263 mdname(mddev), 259 mdname(mddev),
264 (unsigned long long)smallest->sectors); 260 (unsigned long long)smallest->sectors);
265 } 261 }
266 mddev->queue->backing_dev_info.congested_fn = raid0_congested;
267 mddev->queue->backing_dev_info.congested_data = mddev;
268 262
269 /* 263 /*
270 * now since we have the hard sector sizes, we can make sure 264 * now since we have the hard sector sizes, we can make sure
@@ -729,6 +723,7 @@ static struct md_personality raid0_personality=
729 .size = raid0_size, 723 .size = raid0_size,
730 .takeover = raid0_takeover, 724 .takeover = raid0_takeover,
731 .quiesce = raid0_quiesce, 725 .quiesce = raid0_quiesce,
726 .congested = raid0_congested,
732}; 727};
733 728
734static int __init raid0_init (void) 729static int __init raid0_init (void)