Thread (5 messages) 5 messages, 3 authors, 2010-06-24

Re: [PATCH] drivers/md: raid10: Fix null pointer dereference in fix_read_error()

From: Prasanna Panchamukhi <hidden>
Date: 2010-06-21 23:10:51

On 06/21/2010 03:55 PM, Neil Brown wrote:
On Mon, 21 Jun 2010 15:14:35 -0700
prasanna.panchamukhi@riverbed.com wrote:

   
quoted
From: Prasanna S. Panchamukhi<redacted>

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<redacted>
Signed-off-by: Rob Becker<redacted>
     
Thanks for the patch.
However all that extra indenting is rather painful - and we already have more
than we should.

How about this instead?
   
Looks good to me.

Thanks
Prasanna
quoted hunk ↗ jump to hunk
Thanks,
NeilBrown
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index aa9f7b6..0334655 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1482,14 +1482,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) {
  		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)) {
@@ -1530,7 +1530,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)) {
@@ -1601,7 +1601,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--;

   
quoted
---
  drivers/md/raid10.c |   51 +++++++++++++++++++++++++++------------------------
  1 files changed, 27 insertions(+), 24 deletions(-)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 0372499..9556faa 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1490,31 +1490,34 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
  		int cur_read_error_count = 0;

  		rdev = rcu_dereference(conf->mirrors[d].rdev);
-		bdevname(rdev->bdev, b);
+		if (rdev) { /* Check if the mirror raid device is not NULL*/
+			bdevname(rdev->bdev, b);

-		if (test_bit(Faulty,&rdev->flags)) {
-			rcu_read_unlock();
-			/* drive has already been failed, just ignore any
-			   more fix_read_error() attempts */
-			return;
-		}
+			if (test_bit(Faulty,&rdev->flags)) {
+				rcu_read_unlock();
+				/* drive has already been failed, just ignore
+				   any more fix_read_error() attempts */
+				return;
+			}

-		check_decay_read_errors(mddev, rdev);
-		atomic_inc(&rdev->read_errors);
-		cur_read_error_count = atomic_read(&rdev->read_errors);
-		if (cur_read_error_count>  max_read_errors) {
-			rcu_read_unlock();
-			printk(KERN_NOTICE
-			       "md/raid10:%s: %s: Raid device exceeded "
-			       "read_error threshold "
-			       "[cur %d:max %d]\n",
-			       mdname(mddev),
-			       b, cur_read_error_count, max_read_errors);
-			printk(KERN_NOTICE
-			       "md/raid10:%s: %s: Failing raid "
-			       "device\n", mdname(mddev), b);
-			md_error(mddev, conf->mirrors[d].rdev);
-			return;
+			check_decay_read_errors(mddev, rdev);
+			atomic_inc(&rdev->read_errors);
+			cur_read_error_count = atomic_read(&rdev->read_errors);
+			if (cur_read_error_count>  max_read_errors) {
+				rcu_read_unlock();
+				printk(KERN_NOTICE
+				       "md/raid10:%s: %s: Raid device exceeded "
+				       "read_error threshold "
+				       "[cur %d:max %d]\n",
+				       mdname(mddev),
+				       b, cur_read_error_count,
+				       max_read_errors);
+				printk(KERN_NOTICE
+				       "md/raid10:%s: %s: Failing raid "
+				       "device\n", mdname(mddev), b);
+				md_error(mddev, conf->mirrors[d].rdev);
+				return;
+			}
  		}
  	}
  	rcu_read_unlock();
     
   
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help