lkml.org 
[lkml]   [2018]   [Jun]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V6 07/30] block: use bio_for_each_chunk() to map sg
    Date
    It is more efficient to use bio_for_each_chunk() to map sg, meantime
    we have to consider splitting multipage bvec as done in blk_bio_segment_split().

    Signed-off-by: Ming Lei <ming.lei@redhat.com>
    ---
    block/blk-merge.c | 72 +++++++++++++++++++++++++++++++++++++++----------------
    1 file changed, 52 insertions(+), 20 deletions(-)

    diff --git a/block/blk-merge.c b/block/blk-merge.c
    index 2493fe027953..044db0fa2f89 100644
    --- a/block/blk-merge.c
    +++ b/block/blk-merge.c
    @@ -424,6 +424,56 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
    return 0;
    }

    +static struct scatterlist *blk_next_sg(struct scatterlist **sg,
    + struct scatterlist *sglist)
    +{
    + if (!*sg)
    + return sglist;
    + else {
    + /*
    + * If the driver previously mapped a shorter
    + * list, we could see a termination bit
    + * prematurely unless it fully inits the sg
    + * table on each mapping. We KNOW that there
    + * must be more entries here or the driver
    + * would be buggy, so force clear the
    + * termination bit to avoid doing a full
    + * sg_init_table() in drivers for each command.
    + */
    + sg_unmark_end(*sg);
    + return sg_next(*sg);
    + }
    +}
    +
    +static unsigned blk_bvec_map_sg(struct request_queue *q,
    + struct bio_vec *bvec, struct scatterlist *sglist,
    + struct scatterlist **sg)
    +{
    + unsigned nbytes = bvec->bv_len;
    + unsigned nsegs = 0, total = 0;
    +
    + while (nbytes > 0) {
    + unsigned seg_size;
    + struct page *pg;
    + unsigned offset, idx;
    +
    + *sg = blk_next_sg(sg, sglist);
    +
    + seg_size = min(nbytes, queue_max_segment_size(q));
    + offset = (total + bvec->bv_offset) % PAGE_SIZE;
    + idx = (total + bvec->bv_offset) / PAGE_SIZE;
    + pg = nth_page(bvec->bv_page, idx);
    +
    + sg_set_page(*sg, pg, seg_size, offset);
    +
    + total += seg_size;
    + nbytes -= seg_size;
    + nsegs++;
    + }
    +
    + return nsegs;
    +}
    +
    static inline void
    __blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec,
    struct scatterlist *sglist, struct bio_vec *bvprv,
    @@ -444,25 +494,7 @@ __blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec,
    (*sg)->length += nbytes;
    } else {
    new_segment:
    - if (!*sg)
    - *sg = sglist;
    - else {
    - /*
    - * If the driver previously mapped a shorter
    - * list, we could see a termination bit
    - * prematurely unless it fully inits the sg
    - * table on each mapping. We KNOW that there
    - * must be more entries here or the driver
    - * would be buggy, so force clear the
    - * termination bit to avoid doing a full
    - * sg_init_table() in drivers for each command.
    - */
    - sg_unmark_end(*sg);
    - *sg = sg_next(*sg);
    - }
    -
    - sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset);
    - (*nsegs)++;
    + (*nsegs) += blk_bvec_map_sg(q, bvec, sglist, sg);
    }
    *bvprv = *bvec;
    }
    @@ -484,7 +516,7 @@ static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio,
    int cluster = blk_queue_cluster(q), nsegs = 0;

    for_each_bio(bio)
    - bio_for_each_segment(bvec, bio, iter)
    + bio_for_each_chunk(bvec, bio, iter)
    __blk_segment_map_sg(q, &bvec, sglist, &bvprv, sg,
    &nsegs, &cluster);

    --
    2.9.5
    \
     
     \ /
      Last update: 2018-06-09 14:39    [W:4.863 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site