lkml.org 
[lkml]   [2002]   [Dec]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    Subject18/19
    From
    The block layer does not honour bio->bi_size when issuing io, instead
    it performs io to the complete bvecs. This means we have to change
    the bio splitting code slightly.

    Given a bio we repeatedly apply one of the following three operations
    until there is no more io left in the bio:

    1) The remaining io does not cross an io/target boundary, so just
    create a clone and issue all of the io.

    2) There are some bvecs at the start of the bio that are not split by
    a target boundary. Create a clone for these bvecs only.

    3) The first bvec needs splitting, use bio_alloc() to create *two*
    bios, one for the first half of the bvec, the other for the second
    half. A bvec can never contain more than one boundary.
    --- diff/drivers/md/dm.c 2002-12-16 09:41:39.000000000 +0000
    +++ source/drivers/md/dm.c 2002-12-16 09:42:31.000000000 +0000
    @@ -228,6 +228,15 @@
    * interests of getting something for people to use I give
    * you this clearly demarcated crap.
    *---------------------------------------------------------------*/
    +static inline sector_t to_sector(unsigned int bytes)
    +{
    + return bytes >> SECTOR_SHIFT;
    +}
    +
    +static inline unsigned int to_bytes(sector_t sector)
    +{
    + return sector << SECTOR_SHIFT;
    +}

    /*
    * Decrements the number of outstanding ios that a bio has been
    @@ -270,16 +279,17 @@
    static sector_t max_io_len(struct mapped_device *md,
    sector_t sector, struct dm_target *ti)
    {
    - sector_t len = ti->len;
    + sector_t offset = sector - ti->begin;
    + sector_t len = ti->len - offset;

    /* FIXME: obey io_restrictions ! */

    +
    /*
    * Does the target need to split even further ?
    */
    if (ti->split_io) {
    sector_t boundary;
    - sector_t offset = sector - ti->begin;
    boundary = dm_round_up(offset + 1, ti->split_io) - offset;

    if (len > boundary)
    @@ -289,16 +299,17 @@
    return len;
    }

    -static void __map_bio(struct dm_target *ti, struct bio *clone)
    +static void __map_bio(struct dm_target *ti, struct bio *clone, struct dm_io *io)
    {
    - struct dm_io *io = clone->bi_private;
    int r;

    /*
    * Sanity checks.
    */
    - if (!clone->bi_size)
    - BUG();
    + BUG_ON(!clone->bi_size);
    +
    + clone->bi_end_io = clone_endio;
    + clone->bi_private = io;

    /*
    * Map the clone. If r == 0 we don't need to do
    @@ -326,77 +337,125 @@
    };

    /*
    - * Issues a little bio that just does the back end of a split page.
    + * Creates a little bio that is just does part of a bvec.
    */
    -static void __split_page(struct clone_info *ci, unsigned int len)
    +static struct bio *split_bvec(struct bio *bio, sector_t sector,
    + unsigned short idx, unsigned int offset,
    + unsigned int len)
    {
    - struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector);
    - struct bio *clone, *bio = ci->bio;
    - struct bio_vec *bv = bio->bi_io_vec + ci->idx;
    -
    - if (len > ci->sector_count)
    - len = ci->sector_count;
    + struct bio *clone;
    + struct bio_vec *bv = bio->bi_io_vec + idx;

    clone = bio_alloc(GFP_NOIO, 1);
    - memcpy(clone->bi_io_vec, bv, sizeof(*bv));

    - clone->bi_sector = ci->sector;
    - clone->bi_bdev = bio->bi_bdev;
    - clone->bi_rw = bio->bi_rw;
    - clone->bi_vcnt = 1;
    - clone->bi_size = len << SECTOR_SHIFT;
    - clone->bi_end_io = clone_endio;
    - clone->bi_private = ci->io;
    - clone->bi_io_vec->bv_offset = bv->bv_len - clone->bi_size;
    - clone->bi_io_vec->bv_len = clone->bi_size;
    + if (clone) {
    + memcpy(clone->bi_io_vec, bv, sizeof(*bv));

    - ci->sector += len;
    - ci->sector_count -= len;
    + clone->bi_sector = sector;
    + clone->bi_bdev = bio->bi_bdev;
    + clone->bi_rw = bio->bi_rw;
    + clone->bi_vcnt = 1;
    + clone->bi_size = to_bytes(len);
    + clone->bi_io_vec->bv_offset = offset;
    + clone->bi_io_vec->bv_len = clone->bi_size;
    + }

    - __map_bio(ti, clone);
    + return clone;
    +}
    +
    +/*
    + * Creates a bio that consists of range of complete bvecs.
    + */
    +static struct bio *clone_bio(struct bio *bio, sector_t sector,
    + unsigned short idx, unsigned short bv_count,
    + unsigned int len)
    +{
    + struct bio *clone;
    +
    + clone = bio_clone(bio, GFP_NOIO);
    + clone->bi_sector = sector;
    + clone->bi_idx = idx;
    + clone->bi_vcnt = idx + bv_count;
    + clone->bi_size = to_bytes(len);
    +
    + return clone;
    }

    static void __clone_and_map(struct clone_info *ci)
    {
    struct bio *clone, *bio = ci->bio;
    struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector);
    - sector_t len = max_io_len(ci->md, bio->bi_sector, ti);
    + sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti);

    - /* shorter than current target ? */
    - if (ci->sector_count < len)
    - len = ci->sector_count;
    + if (ci->sector_count <= max) {
    + /*
    + * Optimise for the simple case where we can do all of
    + * the remaining io with a single clone.
    + */
    + clone = clone_bio(bio, ci->sector, ci->idx,
    + bio->bi_vcnt - ci->idx, ci->sector_count);
    + __map_bio(ti, clone, ci->io);
    + ci->sector_count = 0;

    - /* create the clone */
    - clone = bio_clone(ci->bio, GFP_NOIO);
    - clone->bi_sector = ci->sector;
    - clone->bi_idx = ci->idx;
    - clone->bi_size = len << SECTOR_SHIFT;
    - clone->bi_end_io = clone_endio;
    - clone->bi_private = ci->io;
    + } else if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) {
    + /*
    + * There are some bvecs that don't span targets.
    + * Do as many of these as possible.
    + */
    + int i;
    + sector_t remaining = max;
    + sector_t bv_len;

    - /* adjust the remaining io */
    - ci->sector += len;
    - ci->sector_count -= len;
    - __map_bio(ti, clone);
    + for (i = ci->idx; remaining && (i < bio->bi_vcnt); i++) {
    + bv_len = to_sector(bio->bi_io_vec[i].bv_len);

    - /*
    - * If we are not performing all remaining io in this
    - * clone then we need to calculate ci->idx for the next
    - * time round.
    - */
    - if (ci->sector_count) {
    - while (len) {
    - struct bio_vec *bv = clone->bi_io_vec + ci->idx;
    - sector_t bv_len = bv->bv_len >> SECTOR_SHIFT;
    - if (bv_len <= len)
    - len -= bv_len;
    + if (bv_len > remaining)
    + break;

    - else {
    - __split_page(ci, bv_len - len);
    - len = 0;
    - }
    - ci->idx++;
    + remaining -= bv_len;
    + len += bv_len;
    }
    +
    + clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len);
    + __map_bio(ti, clone, ci->io);
    +
    + ci->sector += len;
    + ci->sector_count -= len;
    + ci->idx = i;
    +
    + } else {
    + /*
    + * Create two copy bios to deal with io that has
    + * been split across a target.
    + */
    + struct bio_vec *bv = bio->bi_io_vec + ci->idx;
    +
    + clone = split_bvec(bio, ci->sector, ci->idx,
    + bv->bv_offset, max);
    + if (!clone) {
    + dec_pending(ci->io, -ENOMEM);
    + return;
    + }
    +
    + __map_bio(ti, clone, ci->io);
    +
    + ci->sector += max;
    + ci->sector_count -= max;
    + ti = dm_table_find_target(ci->md->map, ci->sector);
    +
    + len = to_sector(bv->bv_len) - max;
    + clone = split_bvec(bio, ci->sector, ci->idx,
    + bv->bv_offset + to_bytes(max), len);
    + if (!clone) {
    + dec_pending(ci->io, -ENOMEM);
    + return;
    + }
    +
    + __map_bio(ti, clone, ci->io);
    +
    + ci->sector += len;
    + ci->sector_count -= len;
    + ci->idx++;
    }
    }

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2005-03-22 13:31    [W:0.032 / U:29.588 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site