[PATCH 029 of 35] Teach md/raid10 to split arbitrarily large bios.

From: NeilBrown
Date: Mon Jul 30 2007 - 22:28:52 EST



.. using the new bio_multi_split.

Signed-off-by: Neil Brown <neilb@xxxxxxx>

### Diffstat output
./drivers/md/raid10.c | 70 ++++++++++----------------------------------------
1 file changed, 14 insertions(+), 56 deletions(-)

diff .prev/drivers/md/raid10.c ./drivers/md/raid10.c
--- .prev/drivers/md/raid10.c 2007-07-31 11:21:22.000000000 +1000
+++ ./drivers/md/raid10.c 2007-07-31 11:21:24.000000000 +1000
@@ -436,33 +436,6 @@ static sector_t raid10_find_virt(conf_t
return (vchunk << conf->chunk_shift) + offset;
}

-/**
- * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged
- * @q: request queue
- * @bio: the buffer head that's been built up so far
- * @biovec: the request that could be merged to it.
- *
- * Return amount of bytes we can accept at this offset
- * If near_copies == raid_disk, there are no striping issues,
- * but in that case, the function isn't called at all.
- */
-static int raid10_mergeable_bvec(struct request_queue *q, struct bio *bio,
- struct bio_vec *bio_vec)
-{
- mddev_t *mddev = q->queuedata;
- sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
- int max;
- unsigned int chunk_sectors = mddev->chunk_size >> 9;
- unsigned int bio_sectors = bio->bi_size >> 9;
-
- max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
- if (max < 0) max = 0; /* bio_add cannot handle a negative return */
- if (max <= bio_vec->bv_len && bio_sectors == 0)
- return bio_vec->bv_len;
- else
- return max;
-}
-
/*
* This routine returns the disk from which the requested read should
* be done. There is a per-array 'next expected sequential IO' sector
@@ -772,6 +745,7 @@ static int make_request(struct request_q
mirror_info_t *mirror;
r10bio_t *r10_bio;
struct bio *read_bio;
+ struct bio *remainder = bio;
int i;
int chunk_sects = conf->chunk_mask + 1;
const int rw = bio_data_dir(bio);
@@ -785,35 +759,21 @@ static int make_request(struct request_q
}

/* If this request crosses a chunk boundary, we need to
- * split it. This will only happen for 1 PAGE (or less) requests.
+ * split it.
*/
- if (unlikely( (bio->bi_sector & conf->chunk_mask) + (bio->bi_size >> 9)
- > chunk_sects &&
- conf->near_copies < conf->raid_disks)) {
- struct bio_pair *bp;
- /* Sanity check -- queue functions should prevent this happening */
- if (bio->bi_vcnt != 1)
- goto bad_map;
- /* This is a one page bio that upper layers
- * refuse to split for us, so we need to split it.
- */
- bp = bio_split(bio, bio_split_pool,
- chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
- if (make_request(q, &bp->bio1))
- generic_make_request(&bp->bio1);
- if (make_request(q, &bp->bio2))
- generic_make_request(&bp->bio2);
-
- bio_pair_release(bp);
- return 0;
- bad_map:
- printk("raid10_make_request bug: can't convert block across chunks"
- " or bigger than %dk %llu %d\n", chunk_sects/2,
- (unsigned long long)bio->bi_sector, bio->bi_size >> 10);
-
- bio_io_error(bio);
- return 0;
+ while ((remainder->bi_sector & conf->chunk_mask)
+ + (remainder->bi_size >> 9)
+ > chunk_sects &&
+ conf->near_copies < conf->raid_disks) {
+ struct bio *new =
+ bio_multi_split(bio,
+ chunk_sects
+ - (remainder->bi_sector
+ & (chunk_sects - 1)),
+ &remainder);
+ make_request(q, new);
}
+ bio = remainder;

md_write_start(mddev, bio);

@@ -2116,8 +2076,6 @@ static int run(mddev_t *mddev)
mddev->queue->backing_dev_info.ra_pages = 2* stripe;
}

- if (conf->near_copies < mddev->raid_disks)
- blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
return 0;

out_free_conf:
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/