diff options
Diffstat (limited to 'drivers/md/raid0.c')
| -rw-r--r-- | drivers/md/raid0.c | 79 | 
1 files changed, 30 insertions, 49 deletions
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index c4d420b7d2f..407a99e46f6 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -501,10 +501,11 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev,  			unsigned int chunk_sects, struct bio *bio)  {  	if (likely(is_power_of_2(chunk_sects))) { -		return chunk_sects >= ((bio->bi_sector & (chunk_sects-1)) +		return chunk_sects >= +			((bio->bi_iter.bi_sector & (chunk_sects-1))  					+ bio_sectors(bio));  	} else{ -		sector_t sector = bio->bi_sector; +		sector_t sector = bio->bi_iter.bi_sector;  		return chunk_sects >= (sector_div(sector, chunk_sects)  						+ bio_sectors(bio));  	} @@ -512,64 +513,44 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev,  static void raid0_make_request(struct mddev *mddev, struct bio *bio)  { -	unsigned int chunk_sects; -	sector_t sector_offset;  	struct strip_zone *zone;  	struct md_rdev *tmp_dev; +	struct bio *split;  	if (unlikely(bio->bi_rw & REQ_FLUSH)) {  		md_flush_request(mddev, bio);  		return;  	} -	chunk_sects = mddev->chunk_sectors; -	if (unlikely(!is_io_in_chunk_boundary(mddev, chunk_sects, bio))) { -		sector_t sector = bio->bi_sector; -		struct bio_pair *bp; -		/* Sanity check -- queue functions should prevent this happening */ -		if (bio_segments(bio) > 1) -			goto bad_map; -		/* This is a one page bio that upper layers -		 * refuse to split for us, so we need to split it. -		 */ -		if (likely(is_power_of_2(chunk_sects))) -			bp = bio_split(bio, chunk_sects - (sector & -							   (chunk_sects-1))); -		else -			bp = bio_split(bio, chunk_sects - -				       sector_div(sector, chunk_sects)); -		raid0_make_request(mddev, &bp->bio1); -		raid0_make_request(mddev, &bp->bio2); -		bio_pair_release(bp); -		return; -	} +	do { +		sector_t sector = bio->bi_iter.bi_sector; +		unsigned chunk_sects = mddev->chunk_sectors; -	sector_offset = bio->bi_sector; -	zone = find_zone(mddev->private, §or_offset); -	tmp_dev = map_sector(mddev, zone, bio->bi_sector, -			     §or_offset); -	bio->bi_bdev = tmp_dev->bdev; -	bio->bi_sector = sector_offset + zone->dev_start + -		tmp_dev->data_offset; - -	if (unlikely((bio->bi_rw & REQ_DISCARD) && -		     !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) { -		/* Just ignore it */ -		bio_endio(bio, 0); -		return; -	} +		unsigned sectors = chunk_sects - +			(likely(is_power_of_2(chunk_sects)) +			 ? (sector & (chunk_sects-1)) +			 : sector_div(sector, chunk_sects)); -	generic_make_request(bio); -	return; - -bad_map: -	printk("md/raid0:%s: make_request bug: can't convert block across chunks" -	       " or bigger than %dk %llu %d\n", -	       mdname(mddev), chunk_sects / 2, -	       (unsigned long long)bio->bi_sector, bio_sectors(bio) / 2); +		if (sectors < bio_sectors(bio)) { +			split = bio_split(bio, sectors, GFP_NOIO, fs_bio_set); +			bio_chain(split, bio); +		} else { +			split = bio; +		} -	bio_io_error(bio); -	return; +		zone = find_zone(mddev->private, §or); +		tmp_dev = map_sector(mddev, zone, sector, §or); +		split->bi_bdev = tmp_dev->bdev; +		split->bi_iter.bi_sector = sector + zone->dev_start + +			tmp_dev->data_offset; + +		if (unlikely((split->bi_rw & REQ_DISCARD) && +			 !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) { +			/* Just ignore it */ +			bio_endio(split, 0); +		} else +			generic_make_request(split); +	} while (split != bio);  }  static void raid0_status(struct seq_file *seq, struct mddev *mddev)  | 
