diff options
Diffstat (limited to 'drivers/md/raid1.c')
| -rw-r--r-- | drivers/md/raid1.c | 89 | 
1 files changed, 51 insertions, 38 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 34e26834ad28..0466ee2453b4 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -447,19 +447,21 @@ static void raid1_end_write_request(struct bio *bio)  		    /* We never try FailFast to WriteMostly devices */  		    !test_bit(WriteMostly, &rdev->flags)) {  			md_error(r1_bio->mddev, rdev); -			if (!test_bit(Faulty, &rdev->flags)) -				/* This is the only remaining device, -				 * We need to retry the write without -				 * FailFast -				 */ -				set_bit(R1BIO_WriteError, &r1_bio->state); -			else { -				/* Finished with this branch */ -				r1_bio->bios[mirror] = NULL; -				to_put = bio; -			} -		} else +		} + +		/* +		 * When the device is faulty, it is not necessary to +		 * handle write error. +		 * For failfast, this is the only remaining device, +		 * We need to retry the write without FailFast. +		 */ +		if (!test_bit(Faulty, &rdev->flags))  			set_bit(R1BIO_WriteError, &r1_bio->state); +		else { +			/* Finished with this branch */ +			r1_bio->bios[mirror] = NULL; +			to_put = bio; +		}  	} else {  		/*  		 * Set R1BIO_Uptodate in our master bio, so that we @@ -872,8 +874,11 @@ static void flush_pending_writes(struct r1conf *conf)   * backgroup IO calls must call raise_barrier.  Once that returns   *    there is no normal IO happeing.  It must arrange to call   *    lower_barrier when the particular background IO completes. + * + * If resync/recovery is interrupted, returns -EINTR; + * Otherwise, returns 0.   */ -static sector_t raise_barrier(struct r1conf *conf, sector_t sector_nr) +static int raise_barrier(struct r1conf *conf, sector_t sector_nr)  {  	int idx = sector_to_idx(sector_nr); @@ -1612,12 +1617,12 @@ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev)  	/*  	 * If it is not operational, then we have already marked it as dead -	 * else if it is the last working disks, ignore the error, let the -	 * next level up know. +	 * else if it is the last working disks with "fail_last_dev == false", +	 * ignore the error, let the next level up know.  	 * else mark the drive as failed  	 */  	spin_lock_irqsave(&conf->device_lock, flags); -	if (test_bit(In_sync, &rdev->flags) +	if (test_bit(In_sync, &rdev->flags) && !mddev->fail_last_dev  	    && (conf->raid_disks - mddev->degraded) == 1) {  		/*  		 * Don't fail the drive, act as though we were just a @@ -1901,6 +1906,22 @@ static void abort_sync_write(struct mddev *mddev, struct r1bio *r1_bio)  	} while (sectors_to_go > 0);  } +static void put_sync_write_buf(struct r1bio *r1_bio, int uptodate) +{ +	if (atomic_dec_and_test(&r1_bio->remaining)) { +		struct mddev *mddev = r1_bio->mddev; +		int s = r1_bio->sectors; + +		if (test_bit(R1BIO_MadeGood, &r1_bio->state) || +		    test_bit(R1BIO_WriteError, &r1_bio->state)) +			reschedule_retry(r1_bio); +		else { +			put_buf(r1_bio); +			md_done_sync(mddev, s, uptodate); +		} +	} +} +  static void end_sync_write(struct bio *bio)  {  	int uptodate = !bio->bi_status; @@ -1927,16 +1948,7 @@ static void end_sync_write(struct bio *bio)  		)  		set_bit(R1BIO_MadeGood, &r1_bio->state); -	if (atomic_dec_and_test(&r1_bio->remaining)) { -		int s = r1_bio->sectors; -		if (test_bit(R1BIO_MadeGood, &r1_bio->state) || -		    test_bit(R1BIO_WriteError, &r1_bio->state)) -			reschedule_retry(r1_bio); -		else { -			put_buf(r1_bio); -			md_done_sync(mddev, s, uptodate); -		} -	} +	put_sync_write_buf(r1_bio, uptodate);  }  static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector, @@ -2219,17 +2231,7 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio)  		generic_make_request(wbio);  	} -	if (atomic_dec_and_test(&r1_bio->remaining)) { -		/* if we're here, all write(s) have completed, so clean up */ -		int s = r1_bio->sectors; -		if (test_bit(R1BIO_MadeGood, &r1_bio->state) || -		    test_bit(R1BIO_WriteError, &r1_bio->state)) -			reschedule_retry(r1_bio); -		else { -			put_buf(r1_bio); -			md_done_sync(mddev, s, 1); -		} -	} +	put_sync_write_buf(r1_bio, 1);  }  /* @@ -3127,6 +3129,13 @@ static int raid1_run(struct mddev *mddev)  		    !test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||  		    test_bit(Faulty, &conf->mirrors[i].rdev->flags))  			mddev->degraded++; +	/* +	 * RAID1 needs at least one disk in active +	 */ +	if (conf->raid_disks - mddev->degraded < 1) { +		ret = -EINVAL; +		goto abort; +	}  	if (conf->raid_disks - mddev->degraded == 1)  		mddev->recovery_cp = MaxSector; @@ -3160,8 +3169,12 @@ static int raid1_run(struct mddev *mddev)  	ret = md_integrity_register(mddev);  	if (ret) {  		md_unregister_thread(&mddev->thread); -		raid1_free(mddev, conf); +		goto abort;  	} +	return 0; + +abort: +	raid1_free(mddev, conf);  	return ret;  }  |