diff options
Diffstat (limited to 'drivers/md/dm-raid1.c')
| -rw-r--r-- | drivers/md/dm-raid1.c | 23 | 
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index a95cbb80fb34..4da8858856fb 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -145,6 +145,7 @@ static void dispatch_bios(void *context, struct bio_list *bio_list)  struct dm_raid1_bio_record {  	struct mirror *m; +	/* if details->bi_bdev == NULL, details were not saved */  	struct dm_bio_details details;  	region_t write_region;  }; @@ -260,7 +261,7 @@ static int mirror_flush(struct dm_target *ti)  	struct mirror *m;  	struct dm_io_request io_req = {  		.bi_op = REQ_OP_WRITE, -		.bi_op_flags = REQ_PREFLUSH, +		.bi_op_flags = REQ_PREFLUSH | REQ_SYNC,  		.mem.type = DM_IO_KMEM,  		.mem.ptr.addr = NULL,  		.client = ms->io_client, @@ -1198,6 +1199,8 @@ static int mirror_map(struct dm_target *ti, struct bio *bio)  	struct dm_raid1_bio_record *bio_record =  	  dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record)); +	bio_record->details.bi_bdev = NULL; +  	if (rw == WRITE) {  		/* Save region for mirror_end_io() handler */  		bio_record->write_region = dm_rh_bio_to_region(ms->rh, bio); @@ -1256,12 +1259,22 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)  	}  	if (error == -EOPNOTSUPP) -		return error; +		goto out;  	if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD)) -		return error; +		goto out;  	if (unlikely(error)) { +		if (!bio_record->details.bi_bdev) { +			/* +			 * There wasn't enough memory to record necessary +			 * information for a retry or there was no other +			 * mirror in-sync. +			 */ +			DMERR_LIMIT("Mirror read failed."); +			return -EIO; +		} +  		m = bio_record->m;  		DMERR("Mirror read failed from %s. Trying alternative device.", @@ -1277,6 +1290,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)  			bd = &bio_record->details;  			dm_bio_restore(bd, bio); +			bio_record->details.bi_bdev = NULL;  			bio->bi_error = 0;  			queue_bio(ms, bio, rw); @@ -1285,6 +1299,9 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)  		DMERR("All replicated volumes dead, failing I/O");  	} +out: +	bio_record->details.bi_bdev = NULL; +  	return error;  }  | 
