| From 0544a21db02c1d8883158fd6f323364f830a120a Mon Sep 17 00:00:00 2001 |
| From: Prasanna S. Panchamukhi <prasanna.panchamukhi@riverbed.com> |
| Date: Thu, 24 Jun 2010 13:31:03 +1000 |
| Subject: md: raid10: Fix null pointer dereference in fix_read_error() |
| |
| From: Prasanna S. Panchamukhi <prasanna.panchamukhi@riverbed.com> |
| |
| commit 0544a21db02c1d8883158fd6f323364f830a120a upstream. |
| |
| Such NULL pointer dereference can occur when the driver was fixing the |
| read errors/bad blocks and the disk was physically removed |
| causing a system crash. This patch check if the |
| rcu_dereference() returns valid rdev before accessing it in fix_read_error(). |
| |
| Signed-off-by: Prasanna S. Panchamukhi <prasanna.panchamukhi@riverbed.com> |
| Signed-off-by: Rob Becker <rbecker@riverbed.com> |
| Signed-off-by: NeilBrown <neilb@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/md/raid10.c | 12 ++++++------ |
| 1 file changed, 6 insertions(+), 6 deletions(-) |
| |
| --- a/drivers/md/raid10.c |
| +++ b/drivers/md/raid10.c |
| @@ -1486,14 +1486,14 @@ static void fix_read_error(conf_t *conf, |
| int sectors = r10_bio->sectors; |
| mdk_rdev_t*rdev; |
| int max_read_errors = atomic_read(&mddev->max_corr_read_errors); |
| + int d = r10_bio->devs[r10_bio->read_slot].devnum; |
| |
| rcu_read_lock(); |
| - { |
| - int d = r10_bio->devs[r10_bio->read_slot].devnum; |
| + rdev = rcu_dereference(conf->mirrors[d].rdev); |
| + if (rdev) { /* If rdev is not NULL */ |
| char b[BDEVNAME_SIZE]; |
| int cur_read_error_count = 0; |
| |
| - rdev = rcu_dereference(conf->mirrors[d].rdev); |
| bdevname(rdev->bdev, b); |
| |
| if (test_bit(Faulty, &rdev->flags)) { |
| @@ -1533,7 +1533,7 @@ static void fix_read_error(conf_t *conf, |
| |
| rcu_read_lock(); |
| do { |
| - int d = r10_bio->devs[sl].devnum; |
| + d = r10_bio->devs[sl].devnum; |
| rdev = rcu_dereference(conf->mirrors[d].rdev); |
| if (rdev && |
| test_bit(In_sync, &rdev->flags)) { |
| @@ -1567,7 +1567,7 @@ static void fix_read_error(conf_t *conf, |
| rcu_read_lock(); |
| while (sl != r10_bio->read_slot) { |
| char b[BDEVNAME_SIZE]; |
| - int d; |
| + |
| if (sl==0) |
| sl = conf->copies; |
| sl--; |
| @@ -1603,7 +1603,7 @@ static void fix_read_error(conf_t *conf, |
| } |
| sl = start; |
| while (sl != r10_bio->read_slot) { |
| - int d; |
| + |
| if (sl==0) |
| sl = conf->copies; |
| sl--; |