lkml.org 
[lkml]   [2020]   [Aug]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 1/5] iov_iter: introduce iov_iter_pin_user_pages*() routines
    Date
    The new routines are:
    iov_iter_pin_user_pages()
    iov_iter_pin_user_pages_alloc()

    and those correspond to these pre-existing routines:
    iov_iter_get_pages()
    iov_iter_get_pages_alloc()

    Unlike the iov_iter_get_pages*() routines, the
    iov_iter_pin_user_pages*() routines assert that only ITER_IOVEC items
    are passed in. They then call pin_user_pages_fast(), instead of
    get_user_pages_fast().

    Why: In order to incrementally change Direct IO callers from calling
    get_user_pages_fast() and put_page(), over to calling
    pin_user_pages_fast() and unpin_user_page(), there need to be mid-level
    routines that specifically call one or the other systems, for both page
    acquisition and page release.

    Signed-off-by: John Hubbard <jhubbard@nvidia.com>
    ---
    include/linux/uio.h | 5 +++
    lib/iov_iter.c | 80 +++++++++++++++++++++++++++++++++++++++++++++
    2 files changed, 85 insertions(+)

    diff --git a/include/linux/uio.h b/include/linux/uio.h
    index 3835a8a8e9ea..29b0504a27cc 100644
    --- a/include/linux/uio.h
    +++ b/include/linux/uio.h
    @@ -229,6 +229,11 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages);

    const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags);

    +ssize_t iov_iter_pin_user_pages(struct iov_iter *i, struct page **pages,
    + size_t maxsize, unsigned int maxpages, size_t *start);
    +ssize_t iov_iter_pin_user_pages_alloc(struct iov_iter *i, struct page ***pages,
    + size_t maxsize, size_t *start);
    +
    static inline size_t iov_iter_count(const struct iov_iter *i)
    {
    return i->count;
    diff --git a/lib/iov_iter.c b/lib/iov_iter.c
    index 5e40786c8f12..d818b16d136b 100644
    --- a/lib/iov_iter.c
    +++ b/lib/iov_iter.c
    @@ -1309,6 +1309,44 @@ static ssize_t pipe_get_pages(struct iov_iter *i,
    return __pipe_get_pages(i, min(maxsize, capacity), pages, iter_head, start);
    }

    +ssize_t iov_iter_pin_user_pages(struct iov_iter *i,
    + struct page **pages, size_t maxsize, unsigned int maxpages,
    + size_t *start)
    +{
    + size_t skip = i->iov_offset;
    + const struct iovec *iov;
    + struct iovec v;
    +
    + if (WARN_ON_ONCE(!iter_is_iovec(i)))
    + return -EFAULT;
    +
    + if (unlikely(!maxsize))
    + return 0;
    + maxsize = min(maxsize, i->count);
    +
    + iterate_iovec(i, maxsize, v, iov, skip, ({
    + unsigned long addr = (unsigned long)v.iov_base;
    + size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
    + int n;
    + int res;
    +
    + if (len > maxpages * PAGE_SIZE)
    + len = maxpages * PAGE_SIZE;
    + addr &= ~(PAGE_SIZE - 1);
    + n = DIV_ROUND_UP(len, PAGE_SIZE);
    +
    + res = pin_user_pages_fast(addr, n,
    + iov_iter_rw(i) != WRITE ? FOLL_WRITE : 0,
    + pages);
    + if (unlikely(res < 0))
    + return res;
    + return (res == n ? len : res * PAGE_SIZE) - *start;
    + 0;
    + }))
    + return 0;
    +}
    +EXPORT_SYMBOL(iov_iter_pin_user_pages);
    +
    ssize_t iov_iter_get_pages(struct iov_iter *i,
    struct page **pages, size_t maxsize, unsigned maxpages,
    size_t *start)
    @@ -1388,6 +1426,48 @@ static ssize_t pipe_get_pages_alloc(struct iov_iter *i,
    return n;
    }

    +ssize_t iov_iter_pin_user_pages_alloc(struct iov_iter *i,
    + struct page ***pages, size_t maxsize,
    + size_t *start)
    +{
    + struct page **p;
    + size_t skip = i->iov_offset;
    + const struct iovec *iov;
    + struct iovec v;
    +
    + if (WARN_ON_ONCE(!iter_is_iovec(i)))
    + return -EFAULT;
    +
    + if (unlikely(!maxsize))
    + return 0;
    + maxsize = min(maxsize, i->count);
    +
    + iterate_iovec(i, maxsize, v, iov, skip, ({
    + unsigned long addr = (unsigned long)v.iov_base;
    + size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
    + int n;
    + int res;
    +
    + addr &= ~(PAGE_SIZE - 1);
    + n = DIV_ROUND_UP(len, PAGE_SIZE);
    + p = get_pages_array(n);
    + if (!p)
    + return -ENOMEM;
    +
    + res = pin_user_pages_fast(addr, n,
    + iov_iter_rw(i) != WRITE ? FOLL_WRITE : 0, p);
    + if (unlikely(res < 0)) {
    + kvfree(p);
    + return res;
    + }
    + *pages = p;
    + return (res == n ? len : res * PAGE_SIZE) - *start;
    + 0;
    + }))
    + return 0;
    +}
    +EXPORT_SYMBOL(iov_iter_pin_user_pages_alloc);
    +
    ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
    struct page ***pages, size_t maxsize,
    size_t *start)
    --
    2.28.0
    \
     
     \ /
      Last update: 2020-08-22 06:22    [W:2.890 / U:0.156 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site