lkml.org 
[lkml]   [2008]   [Nov]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 17/22] block: fix nr_phys_segments miscalculation bug
    2.6.27-stable review patch.  If anyone has any objections, please let us know.

    ------------------

    From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>

    commit 8677142710516d986d932d6f1fba7be8382c1fec upstream
    backported by Nikanth Karthikesan <knikanth@suse.de> to the 2.6.27.y tree.

    block: fix nr_phys_segments miscalculation bug

    This fixes the bug reported by Nikanth Karthikesan <knikanth@suse.de>:

    http://lkml.org/lkml/2008/10/2/203

    The root cause of the bug is that blk_phys_contig_segment
    miscalculates q->max_segment_size.

    blk_phys_contig_segment checks:

    req->biotail->bi_size + next_req->bio->bi_size > q->max_segment_size

    But blk_recalc_rq_segments might expect that req->biotail and the
    previous bio in the req are supposed be merged into one
    segment. blk_recalc_rq_segments might also expect that next_req->bio
    and the next bio in the next_req are supposed be merged into one
    segment. In such case, we merge two requests that can't be merged
    here. Later, blk_rq_map_sg gives more segments than it should.

    We need to keep track of segment size in blk_recalc_rq_segments and
    use it to see if two requests can be merged. This patch implements it
    in the similar way that we used to do for hw merging (virtual
    merging).

    Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
    Cc: Nikanth Karthikesan <knikanth@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    block/blk-merge.c | 19 +++++++++++++++++--
    include/linux/bio.h | 7 +++++++
    2 files changed, 24 insertions(+), 2 deletions(-)

    --- a/block/blk-merge.c
    +++ b/block/blk-merge.c
    @@ -95,6 +95,9 @@ new_hw_segment:
    nr_hw_segs++;
    }

    + if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
    + rq->bio->bi_seg_front_size = seg_size;
    +
    nr_phys_segs++;
    bvprv = bv;
    seg_size = bv->bv_len;
    @@ -106,6 +109,10 @@ new_hw_segment:
    rq->bio->bi_hw_front_size = hw_seg_size;
    if (hw_seg_size > rq->biotail->bi_hw_back_size)
    rq->biotail->bi_hw_back_size = hw_seg_size;
    + if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
    + rq->bio->bi_seg_front_size = seg_size;
    + if (seg_size > rq->biotail->bi_seg_back_size)
    + rq->biotail->bi_seg_back_size = seg_size;
    rq->nr_phys_segments = nr_phys_segs;
    rq->nr_hw_segments = nr_hw_segs;
    }
    @@ -133,7 +140,8 @@ static int blk_phys_contig_segment(struc

    if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)))
    return 0;
    - if (bio->bi_size + nxt->bi_size > q->max_segment_size)
    + if (bio->bi_seg_back_size + nxt->bi_seg_front_size >
    + q->max_segment_size)
    return 0;

    /*
    @@ -377,6 +385,8 @@ static int ll_merge_requests_fn(struct r
    {
    int total_phys_segments;
    int total_hw_segments;
    + unsigned int seg_size =
    + req->biotail->bi_seg_back_size + next->bio->bi_seg_front_size;

    /*
    * First check if the either of the requests are re-queued
    @@ -392,8 +402,13 @@ static int ll_merge_requests_fn(struct r
    return 0;

    total_phys_segments = req->nr_phys_segments + next->nr_phys_segments;
    - if (blk_phys_contig_segment(q, req->biotail, next->bio))
    + if (blk_phys_contig_segment(q, req->biotail, next->bio)) {
    + if (req->nr_phys_segments == 1)
    + req->bio->bi_seg_front_size = seg_size;
    + if (next->nr_phys_segments == 1)
    + next->biotail->bi_seg_back_size = seg_size;
    total_phys_segments--;
    + }

    if (total_phys_segments > q->max_phys_segments)
    return 0;
    --- a/include/linux/bio.h
    +++ b/include/linux/bio.h
    @@ -98,6 +98,13 @@ struct bio {
    unsigned int bi_size; /* residual I/O count */

    /*
    + * To keep track of the max segment size, we account for the
    + * sizes of the first and last mergeable segments in this bio.
    + */
    + unsigned int bi_seg_front_size;
    + unsigned int bi_seg_back_size;
    +
    + /*
    * To keep track of the max hw size, we account for the
    * sizes of the first and last virtually mergeable segments
    * in this bio
    --


    \
     
     \ /
      Last update: 2008-11-15 06:33    [W:0.051 / U:29.500 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site