Skip to contentSkip to conversation

raid5: fix possible oops in add_stripe_bio when enable pr_debug

PATCH In review Jianpeng Ma 2 participants 5 messages Sep 20, 2012 – Sep 25, 2012 MD RAID

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 raid5: fix possible oops in add_stripe_bio when enable pr_debug

In func add_stripe_bio:

Quoted 8 lines
Quoted 8 lines

.....

		bip = &sh->dev[dd_idx].toread;

......
spin_unlock_irq(&sh->stripe_lock);

	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
		(unsigned long long)(*bip)->bi_sector,
		(unsigned long long)sh->sector, dd_idx);

After spin_unlock_irq, this thread scheded and toread may become null. So it will be oops.

---
 drivers/md/raid5.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/md/raid5.c +2 -1
index adda94d..f172b1e 100644
@@ -2356,6 +2356,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	struct bio **bip;
 	struct r5conf *conf = sh->raid_conf;
 	int firstwrite=0;
+	sector_t sector = bi->bi_sector;
 
 	pr_debug("adding bi b#%llu to stripe s#%llu\n",
 		(unsigned long long)bi->bi_sector,
@@ -2406,7 +2407,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	spin_unlock_irq(&sh->stripe_lock);
 
 	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
-		(unsigned long long)(*bip)->bi_sector,
+		(unsigned long long)sector,
 		(unsigned long long)sh->sector, dd_idx);
 
 	if (conf->mddev->bitmap && firstwrite) {
Signature · 1 line
1.7.9.5
#1 lore raw
Quoted 30 lines · On Thu, 20 Sep 2012 14:34:00 +0800 "Jianpeng Ma" <[email protected]> wrote:

In func add_stripe_bio:

Quoted 8 lines
Quoted 8 lines

.....

		bip = &sh->dev[dd_idx].toread;

......
spin_unlock_irq(&sh->stripe_lock);

	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
		(unsigned long long)(*bip)->bi_sector,
		(unsigned long long)sh->sector, dd_idx);

After spin_unlock_irq, this thread scheded and toread may become null. So it will be oops.

---
 drivers/md/raid5.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/md/raid5.c +1 -0
index adda94d..f172b1e 100644
@@ -2356,6 +2356,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	struct bio **bip;
 	struct r5conf *conf = sh->raid_conf;
 	int firstwrite=0;
+	sector_t sector = bi->bi_sector;
 
 	pr_debug("adding bi b#%llu to stripe s#%llu\n",
 		(unsigned long long)bi->bi_sector,

drivers/md/raid5.c static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in · line 2413

Quoted 8 lines
drivers/md/raid5.c +1 -1
@@ -2406,7 +2407,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	spin_unlock_irq(&sh->stripe_lock);
 
 	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
-		(unsigned long long)(*bip)->bi_sector,
+		(unsigned long long)sector,
 		(unsigned long long)sh->sector, dd_idx);
 
 	if (conf->mddev->bitmap && firstwrite) {

how about we just move the spin_unlock_irq after the pr_debug??

NeilBrown

#2 lore raw

On 2012-09-20 14:47 NeilBrown <[email protected]> Wrote:

Quoted 39 lines · On Thu, 20 Sep 2012 14:34:00 +0800 "Jianpeng Ma" <[email protected]> wrote:
Quoted 38 lines

In func add_stripe_bio:

Quoted 8 lines
Quoted 8 lines

.....

		bip = &sh->dev[dd_idx].toread;

......
spin_unlock_irq(&sh->stripe_lock);

	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
		(unsigned long long)(*bip)->bi_sector,
		(unsigned long long)sh->sector, dd_idx);

After spin_unlock_irq, this thread scheded and toread may become null. So it will be oops.

---
 drivers/md/raid5.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/md/raid5.c +2 -1
index adda94d..f172b1e 100644
@@ -2356,6 +2356,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	struct bio **bip;
 	struct r5conf *conf = sh->raid_conf;
 	int firstwrite=0;
+	sector_t sector = bi->bi_sector;
 
 	pr_debug("adding bi b#%llu to stripe s#%llu\n",
 		(unsigned long long)bi->bi_sector,
@@ -2406,7 +2407,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	spin_unlock_irq(&sh->stripe_lock);
 
 	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
-		(unsigned long long)(*bip)->bi_sector,
+		(unsigned long long)sector,
 		(unsigned long long)sh->sector, dd_idx);
 
Quoted 5 lines

drivers/md/raid5.c static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in · line 2413

Quoted 1 line
drivers/md/raid5.c +0 -0
 	if (conf->mddev->bitmap && firstwrite) {

how about we just move the spin_unlock_irq after the pr_debug??

ah! Why are you think ? my method only add a parameter. BTW, in func handle_failed_stripe:

Quoted 7 lines
Quoted 7 lines

if (!test_bit(R5_Wantfill, &sh->dev[i].flags) &&

		    (!test_bit(R5_Insync, &sh->dev[i].flags) ||
		      test_bit(R5_ReadError, &sh->dev[i].flags))) {
			bi = sh->dev[i].toread;
			sh->dev[i].toread = NULL;
			if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
				wake_up(&conf->wait_for_overlap);

Why use stripe_lock to protect toread?

Thanks!

#3 lore raw
Quoted 40 lines · On Thu, 20 Sep 2012 15:17:54 +0800 "Jianpeng Ma" <[email protected]> wrote:

On 2012-09-20 14:47 NeilBrown <[email protected]> Wrote:

Quoted 39 lines · On Thu, 20 Sep 2012 14:34:00 +0800 "Jianpeng Ma" <[email protected]> wrote:
Quoted 38 lines

In func add_stripe_bio:

Quoted 8 lines
Quoted 8 lines

.....

		bip = &sh->dev[dd_idx].toread;

......
spin_unlock_irq(&sh->stripe_lock);

	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
		(unsigned long long)(*bip)->bi_sector,
		(unsigned long long)sh->sector, dd_idx);

After spin_unlock_irq, this thread scheded and toread may become null. So it will be oops.

---
 drivers/md/raid5.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/md/raid5.c +2 -1
index adda94d..f172b1e 100644
@@ -2356,6 +2356,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	struct bio **bip;
 	struct r5conf *conf = sh->raid_conf;
 	int firstwrite=0;
+	sector_t sector = bi->bi_sector;
 
 	pr_debug("adding bi b#%llu to stripe s#%llu\n",
 		(unsigned long long)bi->bi_sector,
@@ -2406,7 +2407,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	spin_unlock_irq(&sh->stripe_lock);
 
 	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
-		(unsigned long long)(*bip)->bi_sector,
+		(unsigned long long)sector,
 		(unsigned long long)sh->sector, dd_idx);
 
Quoted 6 lines
Quoted 5 lines

drivers/md/raid5.c static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in · line 2413

Quoted 1 line
drivers/md/raid5.c +0 -0
 	if (conf->mddev->bitmap && firstwrite) {

how about we just move the spin_unlock_irq after the pr_debug??

ah! Why are you think ? my method only add a parameter.

Yes.

Quoted 9 lines

BTW, in func handle_failed_stripe:

Quoted 7 lines
Quoted 7 lines

if (!test_bit(R5_Wantfill, &sh->dev[i].flags) &&

		    (!test_bit(R5_Insync, &sh->dev[i].flags) ||
		      test_bit(R5_ReadError, &sh->dev[i].flags))) {
			bi = sh->dev[i].toread;
			sh->dev[i].toread = NULL;
			if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
				wake_up(&conf->wait_for_overlap);

Why use stripe_lock to protect toread?

I assume you mean that we should be holding the lock to protect toread, but we aren't.
I've queued a patch to fix that.

Thanks.
NeilBrown

Quoted 2 lines

Thanks!

#4 lore raw

On 2012-09-25 14:45 NeilBrown <[email protected]> Wrote:

Quoted 59 lines · On Thu, 20 Sep 2012 15:17:54 +0800 "Jianpeng Ma" <[email protected]> wrote:
Quoted 41 lines

On 2012-09-20 14:47 NeilBrown <[email protected]> Wrote:

Quoted 39 lines · On Thu, 20 Sep 2012 14:34:00 +0800 "Jianpeng Ma" <[email protected]> wrote:
Quoted 38 lines

In func add_stripe_bio:

Quoted 8 lines
Quoted 8 lines

.....

		bip = &sh->dev[dd_idx].toread;

......
spin_unlock_irq(&sh->stripe_lock);

	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
		(unsigned long long)(*bip)->bi_sector,
		(unsigned long long)sh->sector, dd_idx);

After spin_unlock_irq, this thread scheded and toread may become null. So it will be oops.

---
 drivers/md/raid5.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/md/raid5.c +2 -1
index adda94d..f172b1e 100644
@@ -2356,6 +2356,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	struct bio **bip;
 	struct r5conf *conf = sh->raid_conf;
 	int firstwrite=0;
+	sector_t sector = bi->bi_sector;
 
 	pr_debug("adding bi b#%llu to stripe s#%llu\n",
 		(unsigned long long)bi->bi_sector,
@@ -2406,7 +2407,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
 	spin_unlock_irq(&sh->stripe_lock);
 
 	pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
-		(unsigned long long)(*bip)->bi_sector,
+		(unsigned long long)sector,
 		(unsigned long long)sh->sector, dd_idx);
 
Quoted 6 lines
Quoted 5 lines

drivers/md/raid5.c static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in · line 2413

Quoted 1 line
drivers/md/raid5.c +0 -0
 	if (conf->mddev->bitmap && firstwrite) {

how about we just move the spin_unlock_irq after the pr_debug??

ah! Why are you think ? my method only add a parameter.

Yes.

Quoted 8 lines

BTW, in func handle_failed_stripe:

Quoted 7 lines
Quoted 7 lines

if (!test_bit(R5_Wantfill, &sh->dev[i].flags) &&

		    (!test_bit(R5_Insync, &sh->dev[i].flags) ||
		      test_bit(R5_ReadError, &sh->dev[i].flags))) {
			bi = sh->dev[i].toread;
			sh->dev[i].toread = NULL;
			if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
				wake_up(&conf->wait_for_overlap);
Quoted 6 lines
Quoted 1 line

Why use stripe_lock to protect toread?

I assume you mean that we should be holding the lock to protect toread, but we aren't.
I've queued a patch to fix that.

Hi,
Last Saturday, i sent a patch-set which contained a patch which fix this bug.
You can check your mail!
Thanks!

Quoted 9 lines

Thanks.
NeilBrown

Quoted 2 lines

Thanks!