lkml.org 
[lkml]   [2012]   [Jul]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 2/4] fuse: re-work fuse_get_user_pages() to operate on iovec[]
    From
    Date
    Now fuse_get_user_pages() takes iovec[] as argument and packs so much data
    from it to req->pages[] as possible.

    Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
    ---
    fs/fuse/file.c | 64 +++++++++++++++++++++++++++++++++++++++++---------------
    1 files changed, 47 insertions(+), 17 deletions(-)

    diff --git a/fs/fuse/file.c b/fs/fuse/file.c
    index b321a68..d84416d 100644
    --- a/fs/fuse/file.c
    +++ b/fs/fuse/file.c
    @@ -1020,41 +1020,71 @@ static void fuse_release_user_pages(struct fuse_req *req, int write)
    }
    }

    -static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
    +static int fuse_get_user_pages(struct fuse_req *req,
    + const struct iovec **iov_pp,
    + unsigned long *nr_segs_p,
    + size_t *iov_offset_p,
    size_t *nbytesp, int write)
    {
    - size_t nbytes = *nbytesp;
    - unsigned long user_addr = (unsigned long) buf;
    - unsigned offset = user_addr & ~PAGE_MASK;
    - int npages;
    + size_t nbytes = 0; /* # bytes already packed in req */

    /* Special case for kernel I/O: can copy directly into the buffer */
    if (segment_eq(get_fs(), KERNEL_DS)) {
    + BUG_ON(*iov_offset_p);
    if (write)
    - req->in.args[1].value = (void *) user_addr;
    + req->in.args[1].value = (*iov_pp)->iov_base;
    else
    - req->out.args[0].value = (void *) user_addr;
    + req->out.args[0].value = (*iov_pp)->iov_base;

    + (*iov_pp)++;
    + (*nr_segs_p)--;
    return 0;
    }

    - nbytes = min_t(size_t, nbytes, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
    - npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
    - npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ);
    - npages = get_user_pages_fast(user_addr, npages, !write, req->pages);
    - if (npages < 0)
    - return npages;
    + req->iovec = *iov_pp;
    + req->iov_offset = *iov_offset_p;

    - req->num_pages = npages;
    - req->page_offset = offset;
    + while (nbytes < *nbytesp && req->num_pages < FUSE_MAX_PAGES_PER_REQ) {
    + int npages;
    + unsigned long user_addr = (unsigned long)(*iov_pp)->iov_base +
    + *iov_offset_p;
    + unsigned offset = user_addr & ~PAGE_MASK;
    + size_t frag_size = min_t(size_t,
    + (*iov_pp)->iov_len - *iov_offset_p,
    + *nbytesp - nbytes);
    +
    + int n = FUSE_MAX_PAGES_PER_REQ - req->num_pages;
    + frag_size = min_t(size_t, frag_size, n << PAGE_SHIFT);
    +
    + npages = (frag_size + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
    + npages = clamp(npages, 1, n);
    +
    + npages = get_user_pages_fast(user_addr, npages, !write,
    + &req->pages[req->num_pages]);
    + if (npages < 0)
    + return npages;
    +
    + frag_size = min_t(size_t, frag_size,
    + (npages << PAGE_SHIFT) - offset);
    + nbytes += frag_size;
    +
    + if (frag_size < (*iov_pp)->iov_len - *iov_offset_p) {
    + *iov_offset_p += frag_size;
    + } else {
    + (*iov_pp)++;
    + (*nr_segs_p)--;
    + *iov_offset_p = 0;
    + }
    +
    + req->num_pages += npages;
    + }

    if (write)
    req->in.argpages = 1;
    else
    req->out.argpages = 1;

    - nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
    - *nbytesp = min(*nbytesp, nbytes);
    + *nbytesp = nbytes;

    return 0;
    }


    \
     
     \ /
      Last update: 2012-07-20 14:21    [W:0.026 / U:0.232 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site