diff options
Diffstat (limited to 'drivers/md/raid5.c')
| -rw-r--r-- | drivers/md/raid5.c | 59 | 
1 files changed, 32 insertions, 27 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 23ac880bba9..f351422938e 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2471,39 +2471,41 @@ handle_failed_sync(struct r5conf *conf, struct stripe_head *sh,  	int abort = 0;  	int i; -	md_done_sync(conf->mddev, STRIPE_SECTORS, 0);  	clear_bit(STRIPE_SYNCING, &sh->state);  	s->syncing = 0;  	s->replacing = 0;  	/* There is nothing more to do for sync/check/repair. +	 * Don't even need to abort as that is handled elsewhere +	 * if needed, and not always wanted e.g. if there is a known +	 * bad block here.  	 * For recover/replace we need to record a bad block on all  	 * non-sync devices, or abort the recovery  	 */ -	if (!test_bit(MD_RECOVERY_RECOVER, &conf->mddev->recovery)) -		return; -	/* During recovery devices cannot be removed, so locking and -	 * refcounting of rdevs is not needed -	 */ -	for (i = 0; i < conf->raid_disks; i++) { -		struct md_rdev *rdev = conf->disks[i].rdev; -		if (rdev -		    && !test_bit(Faulty, &rdev->flags) -		    && !test_bit(In_sync, &rdev->flags) -		    && !rdev_set_badblocks(rdev, sh->sector, -					   STRIPE_SECTORS, 0)) -			abort = 1; -		rdev = conf->disks[i].replacement; -		if (rdev -		    && !test_bit(Faulty, &rdev->flags) -		    && !test_bit(In_sync, &rdev->flags) -		    && !rdev_set_badblocks(rdev, sh->sector, -					   STRIPE_SECTORS, 0)) -			abort = 1; -	} -	if (abort) { -		conf->recovery_disabled = conf->mddev->recovery_disabled; -		set_bit(MD_RECOVERY_INTR, &conf->mddev->recovery); +	if (test_bit(MD_RECOVERY_RECOVER, &conf->mddev->recovery)) { +		/* During recovery devices cannot be removed, so +		 * locking and refcounting of rdevs is not needed +		 */ +		for (i = 0; i < conf->raid_disks; i++) { +			struct md_rdev *rdev = conf->disks[i].rdev; +			if (rdev +			    && !test_bit(Faulty, &rdev->flags) +			    && !test_bit(In_sync, &rdev->flags) +			    && !rdev_set_badblocks(rdev, sh->sector, +						   STRIPE_SECTORS, 0)) +				abort = 1; +			rdev = conf->disks[i].replacement; +			if (rdev +			    && !test_bit(Faulty, &rdev->flags) +			    && !test_bit(In_sync, &rdev->flags) +			    && !rdev_set_badblocks(rdev, sh->sector, +						   STRIPE_SECTORS, 0)) +				abort = 1; +		} +		if (abort) +			conf->recovery_disabled = +				conf->mddev->recovery_disabled;  	} +	md_done_sync(conf->mddev, STRIPE_SECTORS, !abort);  }  static int want_replace(struct stripe_head *sh, int disk_idx) @@ -3203,7 +3205,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)  			/* Not in-sync */;  		else if (is_bad) {  			/* also not in-sync */ -			if (!test_bit(WriteErrorSeen, &rdev->flags)) { +			if (!test_bit(WriteErrorSeen, &rdev->flags) && +			    test_bit(R5_UPTODATE, &dev->flags)) {  				/* treat as in-sync, but with a read error  				 * which we can now try to correct  				 */ @@ -3276,12 +3279,14 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)  		/* If there is a failed device being replaced,  		 *     we must be recovering.  		 * else if we are after recovery_cp, we must be syncing +		 * else if MD_RECOVERY_REQUESTED is set, we also are syncing.  		 * else we can only be replacing  		 * sync and recovery both need to read all devices, and so  		 * use the same flag.  		 */  		if (do_recovery || -		    sh->sector >= conf->mddev->recovery_cp) +		    sh->sector >= conf->mddev->recovery_cp || +		    test_bit(MD_RECOVERY_REQUESTED, &(conf->mddev->recovery)))  			s->syncing = 1;  		else  			s->replacing = 1;  |