lkml.org 
[lkml]   [2023]   [Dec]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 16/39] netfs: Add func to calculate pagecount/size-limited span of an iterator
    Date
    Add a function to work out how much of an ITER_BVEC or ITER_XARRAY iterator
    we can use in a pagecount-limited and size-limited span. This will be
    used, for example, to limit the number of segments in a subrequest to the
    maximum number of elements that an RDMA transfer can handle.

    Signed-off-by: David Howells <dhowells@redhat.com>
    cc: Jeff Layton <jlayton@kernel.org>
    cc: linux-cachefs@redhat.com
    cc: linux-fsdevel@vger.kernel.org
    cc: linux-mm@kvack.org
    ---
    fs/netfs/iterator.c | 97 +++++++++++++++++++++++++++++++++++++++++++
    include/linux/netfs.h | 2 +
    2 files changed, 99 insertions(+)

    diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c
    index 2ff07ba655a0..b781bbbf1d8d 100644
    --- a/fs/netfs/iterator.c
    +++ b/fs/netfs/iterator.c
    @@ -101,3 +101,100 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len,
    return npages;
    }
    EXPORT_SYMBOL_GPL(netfs_extract_user_iter);
    +
    +/*
    + * Select the span of a bvec iterator we're going to use. Limit it by both maximum
    + * size and maximum number of segments. Returns the size of the span in bytes.
    + */
    +static size_t netfs_limit_bvec(const struct iov_iter *iter, size_t start_offset,
    + size_t max_size, size_t max_segs)
    +{
    + const struct bio_vec *bvecs = iter->bvec;
    + unsigned int nbv = iter->nr_segs, ix = 0, nsegs = 0;
    + size_t len, span = 0, n = iter->count;
    + size_t skip = iter->iov_offset + start_offset;
    +
    + if (WARN_ON(!iov_iter_is_bvec(iter)) ||
    + WARN_ON(start_offset > n) ||
    + n == 0)
    + return 0;
    +
    + while (n && ix < nbv && skip) {
    + len = bvecs[ix].bv_len;
    + if (skip < len)
    + break;
    + skip -= len;
    + n -= len;
    + ix++;
    + }
    +
    + while (n && ix < nbv) {
    + len = min3(n, bvecs[ix].bv_len - skip, max_size);
    + span += len;
    + nsegs++;
    + ix++;
    + if (span >= max_size || nsegs >= max_segs)
    + break;
    + skip = 0;
    + n -= len;
    + }
    +
    + return min(span, max_size);
    +}
    +
    +/*
    + * Select the span of an xarray iterator we're going to use. Limit it by both
    + * maximum size and maximum number of segments. It is assumed that segments
    + * can be larger than a page in size, provided they're physically contiguous.
    + * Returns the size of the span in bytes.
    + */
    +static size_t netfs_limit_xarray(const struct iov_iter *iter, size_t start_offset,
    + size_t max_size, size_t max_segs)
    +{
    + struct folio *folio;
    + unsigned int nsegs = 0;
    + loff_t pos = iter->xarray_start + iter->iov_offset;
    + pgoff_t index = pos / PAGE_SIZE;
    + size_t span = 0, n = iter->count;
    +
    + XA_STATE(xas, iter->xarray, index);
    +
    + if (WARN_ON(!iov_iter_is_xarray(iter)) ||
    + WARN_ON(start_offset > n) ||
    + n == 0)
    + return 0;
    + max_size = min(max_size, n - start_offset);
    +
    + rcu_read_lock();
    + xas_for_each(&xas, folio, ULONG_MAX) {
    + size_t offset, flen, len;
    + if (xas_retry(&xas, folio))
    + continue;
    + if (WARN_ON(xa_is_value(folio)))
    + break;
    + if (WARN_ON(folio_test_hugetlb(folio)))
    + break;
    +
    + flen = folio_size(folio);
    + offset = offset_in_folio(folio, pos);
    + len = min(max_size, flen - offset);
    + span += len;
    + nsegs++;
    + if (span >= max_size || nsegs >= max_segs)
    + break;
    + }
    +
    + rcu_read_unlock();
    + return min(span, max_size);
    +}
    +
    +size_t netfs_limit_iter(const struct iov_iter *iter, size_t start_offset,
    + size_t max_size, size_t max_segs)
    +{
    + if (iov_iter_is_bvec(iter))
    + return netfs_limit_bvec(iter, start_offset, max_size, max_segs);
    + if (iov_iter_is_xarray(iter))
    + return netfs_limit_xarray(iter, start_offset, max_size, max_segs);
    + BUG();
    +}
    +EXPORT_SYMBOL(netfs_limit_iter);
    diff --git a/include/linux/netfs.h b/include/linux/netfs.h
    index 8a5b8e7bc358..a30b47e10797 100644
    --- a/include/linux/netfs.h
    +++ b/include/linux/netfs.h
    @@ -324,6 +324,8 @@ void netfs_put_subrequest(struct netfs_io_subrequest *subreq,
    ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len,
    struct iov_iter *new,
    iov_iter_extraction_t extraction_flags);
    +size_t netfs_limit_iter(const struct iov_iter *iter, size_t start_offset,
    + size_t max_size, size_t max_segs);

    int netfs_start_io_read(struct inode *inode);
    void netfs_end_io_read(struct inode *inode);
    \
     
     \ /
      Last update: 2023-12-13 16:26    [W:4.328 / U:0.000 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site