Skip to content

Commit

Permalink
netfs: Add iov_iters to (sub)requests to describe various buffers
Browse files Browse the repository at this point in the history
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
  • Loading branch information
David Howells committed Dec 24, 2023
1 parent 46ed60d commit 92b6cc5
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 24 deletions.
6 changes: 1 addition & 5 deletions fs/afs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions fs/netfs/buffered_read.c
Original file line number Diff line number Diff line change
Expand Up @@ -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().
*/
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -408,6 +417,10 @@ int netfs_write_begin(struct netfs_inode *ctx,
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))
Expand Down
69 changes: 50 additions & 19 deletions fs/netfs/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,7 @@
*/
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,
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -541,6 +567,7 @@ netfs_rreq_prepare_read(struct netfs_io_request *rreq,
* 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;
Expand All @@ -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;

Expand Down Expand Up @@ -603,6 +630,7 @@ static bool netfs_rreq_submit_slice(struct netfs_io_request *rreq,
*/
int netfs_begin_read(struct netfs_io_request *rreq, bool sync)
{
struct iov_iter io_iter;
unsigned int debug_index = 0;
int ret;

Expand All @@ -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)
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions include/linux/netfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit 92b6cc5

Please sign in to comment.