]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfs: Add iov_iters to (sub)requests to describe various buffers
authorDavid Howells <dhowells@redhat.com>
Tue, 26 Sep 2023 16:42:26 +0000 (17:42 +0100)
committerDavid Howells <dhowells@redhat.com>
Sun, 24 Dec 2023 15:08:52 +0000 (15:08 +0000)
Add three iov_iter structs:

 (1) Add an iov_iter (->iter) to the I/O request to describe the
     unencrypted-side buffer.

 (2) Add an iov_iter (->io_iter) to the I/O request to describe the
     encrypted-side I/O buffer.  This may be a different size to the buffer
     in (1).

 (3) Add an iov_iter (->io_iter) to the I/O subrequest to describe the part
     of the I/O buffer for that subrequest.

This will allow future patches to point to a bounce buffer instead for
purposes of handling oversize writes, decryption (where we want to save the
encrypted data to the cache) and decompression.

These iov_iters persist for the lifetime of the (sub)request, and so can be
accessed multiple times without worrying about them being deallocated upon
return to the caller.

The network filesystem must appropriately advance the iterator before
terminating the request.

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/afs/file.c
fs/netfs/buffered_read.c
fs/netfs/io.c
include/linux/netfs.h

index d152ba451f0ecefb8272da6de03b06b8bd3c8e9a..3403bb792deb8d655114e563d220ae3f0a99ab0e 100644 (file)
@@ -323,11 +323,7 @@ static void afs_issue_read(struct netfs_io_subrequest *subreq)
        fsreq->len      = subreq->len   - subreq->transferred;
        fsreq->key      = key_get(subreq->rreq->netfs_priv);
        fsreq->vnode    = vnode;
-       fsreq->iter     = &fsreq->def_iter;
-
-       iov_iter_xarray(&fsreq->def_iter, ITER_DEST,
-                       &fsreq->vnode->netfs.inode.i_mapping->i_pages,
-                       fsreq->pos, fsreq->len);
+       fsreq->iter     = &subreq->io_iter;
 
        afs_fetch_data(fsreq->vnode, fsreq);
        afs_put_read(fsreq);
index d39d0ffe75d2d29d66fd36a60739e3f256b718c1..751556faa70b1be9d6ab726229c3d246b7269b61 100644 (file)
@@ -199,6 +199,10 @@ void netfs_readahead(struct readahead_control *ractl)
 
        netfs_rreq_expand(rreq, ractl);
 
+       /* Set up the output buffer */
+       iov_iter_xarray(&rreq->iter, ITER_DEST, &ractl->mapping->i_pages,
+                       rreq->start, rreq->len);
+
        /* Drop the refs on the folios here rather than in the cache or
         * filesystem.  The locks will be dropped in netfs_rreq_unlock().
         */
@@ -251,6 +255,11 @@ int netfs_read_folio(struct file *file, struct folio *folio)
 
        netfs_stat(&netfs_n_rh_readpage);
        trace_netfs_read(rreq, rreq->start, rreq->len, netfs_read_trace_readpage);
+
+       /* Set up the output buffer */
+       iov_iter_xarray(&rreq->iter, ITER_DEST, &mapping->i_pages,
+                       rreq->start, rreq->len);
+
        return netfs_begin_read(rreq, true);
 
 discard:
@@ -408,6 +417,10 @@ retry:
        ractl._nr_pages = folio_nr_pages(folio);
        netfs_rreq_expand(rreq, &ractl);
 
+       /* Set up the output buffer */
+       iov_iter_xarray(&rreq->iter, ITER_DEST, &mapping->i_pages,
+                       rreq->start, rreq->len);
+
        /* We hold the folio locks, so we can drop the references */
        folio_get(folio);
        while (readahead_folio(&ractl))
index 7f753380e047ab5102f9908bc2f4a5f99bbdda6e..e9d408e211b83a0917b05f68c23353884abc49fa 100644 (file)
  */
 static void netfs_clear_unread(struct netfs_io_subrequest *subreq)
 {
-       struct iov_iter iter;
-
-       iov_iter_xarray(&iter, ITER_DEST, &subreq->rreq->mapping->i_pages,
-                       subreq->start + subreq->transferred,
-                       subreq->len   - subreq->transferred);
-       iov_iter_zero(iov_iter_count(&iter), &iter);
+       iov_iter_zero(iov_iter_count(&subreq->io_iter), &subreq->io_iter);
 }
 
 static void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error,
@@ -46,14 +41,9 @@ static void netfs_read_from_cache(struct netfs_io_request *rreq,
                                  enum netfs_read_from_hole read_hole)
 {
        struct netfs_cache_resources *cres = &rreq->cache_resources;
-       struct iov_iter iter;
 
        netfs_stat(&netfs_n_rh_read);
-       iov_iter_xarray(&iter, ITER_DEST, &rreq->mapping->i_pages,
-                       subreq->start + subreq->transferred,
-                       subreq->len   - subreq->transferred);
-
-       cres->ops->read(cres, subreq->start, &iter, read_hole,
+       cres->ops->read(cres, subreq->start, &subreq->io_iter, read_hole,
                        netfs_cache_read_terminated, subreq);
 }
 
@@ -88,6 +78,11 @@ static void netfs_read_from_server(struct netfs_io_request *rreq,
                                   struct netfs_io_subrequest *subreq)
 {
        netfs_stat(&netfs_n_rh_download);
+       if (iov_iter_count(&subreq->io_iter) != subreq->len - subreq->transferred)
+               pr_warn("R=%08x[%u] ITER PRE-MISMATCH %zx != %zx-%zx %lx\n",
+                       rreq->debug_id, subreq->debug_index,
+                       iov_iter_count(&subreq->io_iter), subreq->len,
+                       subreq->transferred, subreq->flags);
        rreq->netfs_ops->issue_read(subreq);
 }
 
@@ -259,6 +254,30 @@ static void netfs_rreq_short_read(struct netfs_io_request *rreq,
                netfs_read_from_server(rreq, subreq);
 }
 
+/*
+ * Reset the subrequest iterator prior to resubmission.
+ */
+static void netfs_reset_subreq_iter(struct netfs_io_request *rreq,
+                                   struct netfs_io_subrequest *subreq)
+{
+       size_t remaining = subreq->len - subreq->transferred;
+       size_t count = iov_iter_count(&subreq->io_iter);
+
+       if (count == remaining)
+               return;
+
+       _debug("R=%08x[%u] ITER RESUB-MISMATCH %zx != %zx-%zx-%llx %x\n",
+              rreq->debug_id, subreq->debug_index,
+              iov_iter_count(&subreq->io_iter), subreq->transferred,
+              subreq->len, rreq->i_size,
+              subreq->io_iter.iter_type);
+
+       if (count < remaining)
+               iov_iter_revert(&subreq->io_iter, remaining - count);
+       else
+               iov_iter_advance(&subreq->io_iter, count - remaining);
+}
+
 /*
  * Resubmit any short or failed operations.  Returns true if we got the rreq
  * ref back.
@@ -287,6 +306,7 @@ static bool netfs_rreq_perform_resubmissions(struct netfs_io_request *rreq)
                        trace_netfs_sreq(subreq, netfs_sreq_trace_download_instead);
                        netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
                        atomic_inc(&rreq->nr_outstanding);
+                       netfs_reset_subreq_iter(rreq, subreq);
                        netfs_read_from_server(rreq, subreq);
                } else if (test_bit(NETFS_SREQ_SHORT_IO, &subreq->flags)) {
                        netfs_rreq_short_read(rreq, subreq);
@@ -399,9 +419,9 @@ void netfs_subreq_terminated(struct netfs_io_subrequest *subreq,
        struct netfs_io_request *rreq = subreq->rreq;
        int u;
 
-       _enter("[%u]{%llx,%lx},%zd",
-              subreq->debug_index, subreq->start, subreq->flags,
-              transferred_or_error);
+       _enter("R=%x[%x]{%llx,%lx},%zd",
+              rreq->debug_id, subreq->debug_index,
+              subreq->start, subreq->flags, transferred_or_error);
 
        switch (subreq->source) {
        case NETFS_READ_FROM_CACHE:
@@ -501,7 +521,8 @@ static enum netfs_io_source netfs_cache_prepare_read(struct netfs_io_subrequest
  */
 static enum netfs_io_source
 netfs_rreq_prepare_read(struct netfs_io_request *rreq,
-                       struct netfs_io_subrequest *subreq)
+                       struct netfs_io_subrequest *subreq,
+                       struct iov_iter *io_iter)
 {
        enum netfs_io_source source;
 
@@ -528,9 +549,14 @@ netfs_rreq_prepare_read(struct netfs_io_request *rreq,
                }
        }
 
-       if (WARN_ON(subreq->len == 0))
+       if (WARN_ON(subreq->len == 0)) {
                source = NETFS_INVALID_READ;
+               goto out;
+       }
 
+       subreq->io_iter = *io_iter;
+       iov_iter_truncate(&subreq->io_iter, subreq->len);
+       iov_iter_advance(io_iter, subreq->len);
 out:
        subreq->source = source;
        trace_netfs_sreq(subreq, netfs_sreq_trace_prepare);
@@ -541,6 +567,7 @@ out:
  * Slice off a piece of a read request and submit an I/O request for it.
  */
 static bool netfs_rreq_submit_slice(struct netfs_io_request *rreq,
+                                   struct iov_iter *io_iter,
                                    unsigned int *_debug_index)
 {
        struct netfs_io_subrequest *subreq;
@@ -565,7 +592,7 @@ static bool netfs_rreq_submit_slice(struct netfs_io_request *rreq,
         * (the starts must coincide), in which case, we go around the loop
         * again and ask it to download the next piece.
         */
-       source = netfs_rreq_prepare_read(rreq, subreq);
+       source = netfs_rreq_prepare_read(rreq, subreq, io_iter);
        if (source == NETFS_INVALID_READ)
                goto subreq_failed;
 
@@ -603,6 +630,7 @@ subreq_failed:
  */
 int netfs_begin_read(struct netfs_io_request *rreq, bool sync)
 {
+       struct iov_iter io_iter;
        unsigned int debug_index = 0;
        int ret;
 
@@ -615,6 +643,8 @@ int netfs_begin_read(struct netfs_io_request *rreq, bool sync)
                return -EIO;
        }
 
+       rreq->io_iter = rreq->iter;
+
        INIT_WORK(&rreq->work, netfs_rreq_work);
 
        if (sync)
@@ -624,8 +654,9 @@ int netfs_begin_read(struct netfs_io_request *rreq, bool sync)
         * want and submit each one.
         */
        atomic_set(&rreq->nr_outstanding, 1);
+       io_iter = rreq->io_iter;
        do {
-               if (!netfs_rreq_submit_slice(rreq, &debug_index))
+               if (!netfs_rreq_submit_slice(rreq, &io_iter, &debug_index))
                        break;
 
        } while (rreq->submitted < rreq->len);
index fc6d9756a02948b9555fdb83a9698e97c04b2e2c..3da962e977f5555a519ee4c5c7fecccd84561e53 100644 (file)
@@ -150,6 +150,7 @@ struct netfs_cache_resources {
 struct netfs_io_subrequest {
        struct netfs_io_request *rreq;          /* Supervising I/O request */
        struct list_head        rreq_link;      /* Link in rreq->subrequests */
+       struct iov_iter         io_iter;        /* Iterator for this subrequest */
        loff_t                  start;          /* Where to start the I/O */
        size_t                  len;            /* Size of the I/O */
        size_t                  transferred;    /* Amount of data transferred */
@@ -186,6 +187,8 @@ struct netfs_io_request {
        struct netfs_cache_resources cache_resources;
        struct list_head        proc_link;      /* Link in netfs_iorequests */
        struct list_head        subrequests;    /* Contributory I/O operations */
+       struct iov_iter         iter;           /* Unencrypted-side iterator */
+       struct iov_iter         io_iter;        /* I/O (Encrypted-side) iterator */
        void                    *netfs_priv;    /* Private data for the netfs */
        unsigned int            debug_id;
        atomic_t                nr_outstanding; /* Number of ops in progress */