]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
md: raid10: Fix null pointer dereference in fix_read_error()
authorPrasanna S. Panchamukhi <prasanna.panchamukhi@riverbed.com>
Thu, 24 Jun 2010 03:31:03 +0000 (13:31 +1000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 2 Aug 2010 17:29:42 +0000 (10:29 -0700)
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

index ad945cc689f75aa7259be663c1ec7aba7dd35350..c81916582a887949a95b969f2cbe88f62112a728 100644 (file)
@@ -1487,14 +1487,14 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
        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)) {
@@ -1534,7 +1534,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
 
                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)) {
@@ -1568,7 +1568,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
                rcu_read_lock();
                while (sl != r10_bio->read_slot) {
                        char b[BDEVNAME_SIZE];
-                       int d;
+
                        if (sl==0)
                                sl = conf->copies;
                        sl--;
@@ -1604,7 +1604,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
                }
                sl = start;
                while (sl != r10_bio->read_slot) {
-                       int d;
+
                        if (sl==0)
                                sl = conf->copies;
                        sl--;