Commit 400aa2cc authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] md: make sure md_check_recovery will remove a faulty device when ->nr_pending hits 0

md_check_recovery only locks a device and does stuff when it thinks there is a
real likelyhood that something needs doing.  So the test at the top must cover
all possibilities.

But it didn't cover the possibility that the last outstanding request on a
failed device had finished and so the device needed to be removed.

As a result, a failed drive might not get removed from the personalities
perspective on the array, and so it could never be removed from the array as a
whole.

With this patch, whenever ->nr_pending hits zero on a faulty device,
MD_RECOVERY_NEEDED is set so that md_check_recovery will do stuff.
Signed-off-by: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5de6af14
...@@ -131,7 +131,7 @@ int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error) ...@@ -131,7 +131,7 @@ int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error)
(unsigned long long)bio->bi_sector); (unsigned long long)bio->bi_sector);
multipath_reschedule_retry(mp_bh); multipath_reschedule_retry(mp_bh);
} }
atomic_dec(&rdev->nr_pending); rdev_dec_pending(rdev, conf->mddev);
return 0; return 0;
} }
......
...@@ -296,7 +296,7 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int ...@@ -296,7 +296,7 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int
reschedule_retry(r1_bio); reschedule_retry(r1_bio);
} }
atomic_dec(&conf->mirrors[mirror].rdev->nr_pending); rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
return 0; return 0;
} }
...@@ -343,7 +343,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int ...@@ -343,7 +343,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
raid_end_bio_io(r1_bio); raid_end_bio_io(r1_bio);
} }
atomic_dec(&conf->mirrors[mirror].rdev->nr_pending); rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
return 0; return 0;
} }
...@@ -805,7 +805,7 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) ...@@ -805,7 +805,7 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
conf->mirrors[r1_bio->read_disk].rdev); conf->mirrors[r1_bio->read_disk].rdev);
else else
set_bit(R1BIO_Uptodate, &r1_bio->state); set_bit(R1BIO_Uptodate, &r1_bio->state);
atomic_dec(&conf->mirrors[r1_bio->read_disk].rdev->nr_pending); rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev);
reschedule_retry(r1_bio); reschedule_retry(r1_bio);
return 0; return 0;
} }
...@@ -835,7 +835,7 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) ...@@ -835,7 +835,7 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
md_done_sync(mddev, r1_bio->sectors, uptodate); md_done_sync(mddev, r1_bio->sectors, uptodate);
put_buf(r1_bio); put_buf(r1_bio);
} }
atomic_dec(&conf->mirrors[mirror].rdev->nr_pending); rdev_dec_pending(conf->mirrors[mirror].rdev, mddev);
return 0; return 0;
} }
......
...@@ -395,7 +395,7 @@ static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done, ...@@ -395,7 +395,7 @@ static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done,
md_error(conf->mddev, conf->disks[i].rdev); md_error(conf->mddev, conf->disks[i].rdev);
clear_bit(R5_UPTODATE, &sh->dev[i].flags); clear_bit(R5_UPTODATE, &sh->dev[i].flags);
} }
atomic_dec(&conf->disks[i].rdev->nr_pending); rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
#if 0 #if 0
/* must restore b_page before unlocking buffer... */ /* must restore b_page before unlocking buffer... */
if (sh->bh_page[i] != bh->b_page) { if (sh->bh_page[i] != bh->b_page) {
...@@ -438,7 +438,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, ...@@ -438,7 +438,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
if (!uptodate) if (!uptodate)
md_error(conf->mddev, conf->disks[i].rdev); md_error(conf->mddev, conf->disks[i].rdev);
atomic_dec(&conf->disks[i].rdev->nr_pending); rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
clear_bit(R5_LOCKED, &sh->dev[i].flags); clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state); set_bit(STRIPE_HANDLE, &sh->state);
......
...@@ -414,7 +414,7 @@ static int raid6_end_read_request (struct bio * bi, unsigned int bytes_done, ...@@ -414,7 +414,7 @@ static int raid6_end_read_request (struct bio * bi, unsigned int bytes_done,
md_error(conf->mddev, conf->disks[i].rdev); md_error(conf->mddev, conf->disks[i].rdev);
clear_bit(R5_UPTODATE, &sh->dev[i].flags); clear_bit(R5_UPTODATE, &sh->dev[i].flags);
} }
atomic_dec(&conf->disks[i].rdev->nr_pending); rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
#if 0 #if 0
/* must restore b_page before unlocking buffer... */ /* must restore b_page before unlocking buffer... */
if (sh->bh_page[i] != bh->b_page) { if (sh->bh_page[i] != bh->b_page) {
...@@ -457,7 +457,7 @@ static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done, ...@@ -457,7 +457,7 @@ static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done,
if (!uptodate) if (!uptodate)
md_error(conf->mddev, conf->disks[i].rdev); md_error(conf->mddev, conf->disks[i].rdev);
atomic_dec(&conf->disks[i].rdev->nr_pending); rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
clear_bit(R5_LOCKED, &sh->dev[i].flags); clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state); set_bit(STRIPE_HANDLE, &sh->state);
......
...@@ -255,6 +255,14 @@ struct mddev_s ...@@ -255,6 +255,14 @@ struct mddev_s
struct list_head all_mddevs; struct list_head all_mddevs;
}; };
static inline void rdev_dec_pending(mdk_rdev_t *rdev, mddev_t *mddev)
{
int faulty = rdev->faulty;
if (atomic_dec_and_test(&rdev->nr_pending) && faulty)
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
}
struct mdk_personality_s struct mdk_personality_s
{ {
char *name; char *name;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment