netfs: Limit subrequest by size or number of segments
authorDavid Howells <dhowells@redhat.com>
Fri, 27 May 2022 12:45:28 +0000 (13:45 +0100)
committerDavid Howells <dhowells@redhat.com>
Thu, 28 Dec 2023 09:45:19 +0000 (09:45 +0000)
Limit a subrequest to a maximum size and/or a maximum number of contiguous
physical regions.  This permits, for instance, an subreq's iterator to be
limited to the number of DMA'able segments that a large RDMA request can
handle.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
cc: linux-fsdevel@vger.kernel.org
cc: linux-mm@kvack.org

fs/netfs/io.c
include/linux/netfs.h
include/trace/events/netfs.h

index e9d408e..e228bfb 100644 (file)
@@ -525,6 +525,7 @@ netfs_rreq_prepare_read(struct netfs_io_request *rreq,
                        struct iov_iter *io_iter)
 {
        enum netfs_io_source source;
+       size_t lsize;
 
        _enter("%llx-%llx,%llx", subreq->start, subreq->start + subreq->len, rreq->i_size);
 
@@ -547,13 +548,30 @@ netfs_rreq_prepare_read(struct netfs_io_request *rreq,
                        source = NETFS_INVALID_READ;
                        goto out;
                }
+
+               if (subreq->max_nr_segs) {
+                       lsize = netfs_limit_iter(io_iter, 0, subreq->len,
+                                                subreq->max_nr_segs);
+                       if (subreq->len > lsize) {
+                               subreq->len = lsize;
+                               trace_netfs_sreq(subreq, netfs_sreq_trace_limited);
+                       }
+               }
        }
 
+       if (subreq->len > rreq->len)
+               pr_warn("R=%08x[%u] SREQ>RREQ %zx > %zx\n",
+                       rreq->debug_id, subreq->debug_index,
+                       subreq->len, rreq->len);
+
        if (WARN_ON(subreq->len == 0)) {
                source = NETFS_INVALID_READ;
                goto out;
        }
 
+       subreq->source = source;
+       trace_netfs_sreq(subreq, netfs_sreq_trace_prepare);
+
        subreq->io_iter = *io_iter;
        iov_iter_truncate(&subreq->io_iter, subreq->len);
        iov_iter_advance(io_iter, subreq->len);
index d673d07..44cd13a 100644 (file)
@@ -161,6 +161,7 @@ struct netfs_io_subrequest {
        refcount_t              ref;
        short                   error;          /* 0 or error that occurred */
        unsigned short          debug_index;    /* Index in list (for debugging output) */
+       unsigned int            max_nr_segs;    /* 0 or max number of segments in an iterator */
        enum netfs_io_source    source;         /* Where to read from/write to */
        unsigned long           flags;
 #define NETFS_SREQ_COPY_TO_CACHE       0       /* Set if should copy the data to the cache */
index beec534..fce6d0b 100644 (file)
@@ -44,6 +44,7 @@
 #define netfs_sreq_traces                                      \
        EM(netfs_sreq_trace_download_instead,   "RDOWN")        \
        EM(netfs_sreq_trace_free,               "FREE ")        \
+       EM(netfs_sreq_trace_limited,            "LIMIT")        \
        EM(netfs_sreq_trace_prepare,            "PREP ")        \
        EM(netfs_sreq_trace_resubmit_short,     "SHORT")        \
        EM(netfs_sreq_trace_submit,             "SUBMT")        \