lkml.org 
[lkml]   [2008]   [Sep]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 12/42] bio: fix bio_copy_kern() handling of bio->bv_len
    2.6.26-stable review patch.  If anyone has any objections, please let us know.

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

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

    commit 76029ff37f31dad64641489c610d98955217bb68 upstream

    The commit 68154e90c9d1492d570671ae181d9a8f8530da55 introduced
    bio_copy_kern() to add bounce support to blk_rq_map_kern.

    bio_copy_kern() uses bio->bv_len to copy data for READ commands after
    the completion but it doesn't work with a request that partially
    completed. SCSI always completes a PC request as a whole but seems
    some don't.

    This patch fixes bio_copy_kern to handle the above case. As
    bio_copy_user does, bio_copy_kern uses struct bio_map_data to store
    struct bio_vec.

    Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
    Reported-by: Nix <nix@esperi.org.uk>
    Tested-by: Nix <nix@esperi.org.uk>
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    fs/bio.c | 38 ++++++++++++++++++++++++++++----------
    1 file changed, 28 insertions(+), 10 deletions(-)

    --- a/fs/bio.c
    +++ b/fs/bio.c
    @@ -464,20 +464,21 @@ static void bio_free_map_data(struct bio
    kfree(bmd);
    }

    -static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count)
    +static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
    + gfp_t gfp_mask)
    {
    - struct bio_map_data *bmd = kmalloc(sizeof(*bmd), GFP_KERNEL);
    + struct bio_map_data *bmd = kmalloc(sizeof(*bmd), gfp_mask);

    if (!bmd)
    return NULL;

    - bmd->iovecs = kmalloc(sizeof(struct bio_vec) * nr_segs, GFP_KERNEL);
    + bmd->iovecs = kmalloc(sizeof(struct bio_vec) * nr_segs, gfp_mask);
    if (!bmd->iovecs) {
    kfree(bmd);
    return NULL;
    }

    - bmd->sgvecs = kmalloc(sizeof(struct sg_iovec) * iov_count, GFP_KERNEL);
    + bmd->sgvecs = kmalloc(sizeof(struct sg_iovec) * iov_count, gfp_mask);
    if (bmd->sgvecs)
    return bmd;

    @@ -591,7 +592,7 @@ struct bio *bio_copy_user_iov(struct req
    len += iov[i].iov_len;
    }

    - bmd = bio_alloc_map_data(nr_pages, iov_count);
    + bmd = bio_alloc_map_data(nr_pages, iov_count, GFP_KERNEL);
    if (!bmd)
    return ERR_PTR(-ENOMEM);

    @@ -941,19 +942,22 @@ static void bio_copy_kern_endio(struct b
    {
    struct bio_vec *bvec;
    const int read = bio_data_dir(bio) == READ;
    - char *p = bio->bi_private;
    + struct bio_map_data *bmd = bio->bi_private;
    int i;
    + char *p = bmd->sgvecs[0].iov_base;

    __bio_for_each_segment(bvec, bio, i, 0) {
    char *addr = page_address(bvec->bv_page);
    + int len = bmd->iovecs[i].bv_len;

    if (read && !err)
    - memcpy(p, addr, bvec->bv_len);
    + memcpy(p, addr, len);

    __free_page(bvec->bv_page);
    - p += bvec->bv_len;
    + p += len;
    }

    + bio_free_map_data(bmd);
    bio_put(bio);
    }

    @@ -977,11 +981,21 @@ struct bio *bio_copy_kern(struct request
    const int nr_pages = end - start;
    struct bio *bio;
    struct bio_vec *bvec;
    + struct bio_map_data *bmd;
    int i, ret;
    + struct sg_iovec iov;

    + iov.iov_base = data;
    + iov.iov_len = len;
    +
    + bmd = bio_alloc_map_data(nr_pages, 1, gfp_mask);
    + if (!bmd)
    + return ERR_PTR(-ENOMEM);
    +
    + ret = -ENOMEM;
    bio = bio_alloc(gfp_mask, nr_pages);
    if (!bio)
    - return ERR_PTR(-ENOMEM);
    + goto out_bmd;

    while (len) {
    struct page *page;
    @@ -1015,14 +1029,18 @@ struct bio *bio_copy_kern(struct request
    }
    }

    - bio->bi_private = data;
    + bio->bi_private = bmd;
    bio->bi_end_io = bio_copy_kern_endio;
    +
    + bio_set_map_data(bmd, bio, &iov, 1);
    return bio;
    cleanup:
    bio_for_each_segment(bvec, bio, i)
    __free_page(bvec->bv_page);

    bio_put(bio);
    +out_bmd:
    + bio_free_map_data(bmd);

    return ERR_PTR(ret);
    }
    --


    \
     
     \ /
      Last update: 2008-09-03 19:39    [W:4.016 / U:0.768 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site