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 <dhowe...@redhat.com>
cc: Jeff Layton <jlay...@kernel.org>
cc: linux-cachefs@redhat.com
cc: linux-fsde...@vger.kernel.org
cc: linux...@kvack.org
---
 fs/netfs/io.c                | 18 ++++++++++++++++++
 include/linux/netfs.h        |  1 +
 include/trace/events/netfs.h |  1 +
 3 files changed, 20 insertions(+)

diff --git a/fs/netfs/io.c b/fs/netfs/io.c
index d8e9cd6ce338..c80b8eed1209 100644
--- a/fs/netfs/io.c
+++ b/fs/netfs/io.c
@@ -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);
diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index 2b5e04ea4db2..aaf1c1d4de51 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -163,6 +163,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 */
diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h
index beec534cbaab..fce6d0bc78e5 100644
--- a/include/trace/events/netfs.h
+++ b/include/trace/events/netfs.h
@@ -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")        \
--
Linux-cachefs mailing list
Linux-cachefs@redhat.com
https://listman.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to