[PATCH 17/19] netfs: Change ->init_rreq() to return an error code

From: David Howells
Date: Wed Mar 02 2022 - 09:10:22 EST


Change the read-request initialisation function to return an error code so
that the network filesystem can return a failure (ENOMEM, for example).

This will also allow ceph to abort a ->readahead() op if the server refuses
to give it a cap allowing local caching from within the netfslib framework
(errors aren't passed back through ->readahead(), so returning, say,
-ENOBUFS will cause the op to be aborted).

Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
cc: linux-cachefs@xxxxxxxxxx
---

fs/9p/vfs_addr.c | 3 ++-
fs/afs/file.c | 3 ++-
fs/netfs/buffered_read.c | 15 +++++++++------
fs/netfs/objects.c | 40 ++++++++++++++++++++++++----------------
include/linux/netfs.h | 2 +-
5 files changed, 38 insertions(+), 25 deletions(-)

diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 840111da1172..e50326d11e8f 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -56,12 +56,13 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
* @rreq: The read request
* @file: The file being read from
*/
-static void v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
+static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
{
struct p9_fid *fid = file->private_data;

refcount_inc(&fid->count);
rreq->netfs_priv = fid;
+ return 0;
}

/**
diff --git a/fs/afs/file.c b/fs/afs/file.c
index aef0fbbd834d..2b68b2070248 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -357,9 +357,10 @@ static int afs_symlink_readpage(struct file *file, struct page *page)
return ret;
}

-static void afs_init_request(struct netfs_io_request *rreq, struct file *file)
+static int afs_init_request(struct netfs_io_request *rreq, struct file *file)
{
rreq->netfs_priv = key_get(afs_file_key(file));
+ return 0;
}

static int afs_begin_cache_operation(struct netfs_io_request *rreq)
diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c
index 343c0957ae27..64049e123185 100644
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -167,7 +167,7 @@ void netfs_readahead(struct readahead_control *ractl)
readahead_pos(ractl),
readahead_length(ractl),
NETFS_READAHEAD);
- if (!rreq)
+ if (IS_ERR(rreq))
return;

if (ctx->ops->begin_cache_operation) {
@@ -223,8 +223,10 @@ int netfs_readpage(struct file *file, struct page *subpage)

rreq = netfs_alloc_request(mapping, file, folio_file_pos(folio),
folio_size(folio), NETFS_READPAGE);
- if (!rreq)
- goto nomem;
+ if (IS_ERR(rreq)) {
+ ret = PTR_ERR(rreq);
+ goto alloc_error;
+ }

if (ctx->ops->begin_cache_operation) {
ret = ctx->ops->begin_cache_operation(rreq);
@@ -238,7 +240,7 @@ int netfs_readpage(struct file *file, struct page *subpage)

discard:
netfs_put_request(rreq, false, netfs_rreq_trace_put_discard);
-nomem:
+alloc_error:
folio_unlock(folio);
return ret;
}
@@ -371,11 +373,12 @@ int netfs_write_begin(struct file *file, struct address_space *mapping,
goto have_folio_no_wait;
}

- ret = -ENOMEM;
rreq = netfs_alloc_request(mapping, file, folio_file_pos(folio),
folio_size(folio), NETFS_READ_FOR_WRITE);
- if (!rreq)
+ if (IS_ERR(rreq)) {
+ ret = PTR_ERR(rreq);
goto error;
+ }
rreq->start = folio_file_pos(folio);
rreq->len = folio_size(folio);
rreq->no_unlock_folio = folio_index(folio);
diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c
index 8f99269c5344..d8a07df03427 100644
--- a/fs/netfs/objects.c
+++ b/fs/netfs/objects.c
@@ -20,26 +20,34 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
struct inode *inode = file ? file_inode(file) : mapping->host;
struct netfs_i_context *ctx = netfs_i_context(inode);
struct netfs_io_request *rreq;
+ int ret;

rreq = kzalloc(sizeof(struct netfs_io_request), GFP_KERNEL);
- if (rreq) {
- rreq->start = start;
- rreq->len = len;
- rreq->mapping = mapping;
- rreq->inode = inode;
- rreq->origin = origin;
- rreq->netfs_ops = ctx->ops;
- rreq->i_size = i_size_read(inode);
- rreq->debug_id = atomic_inc_return(&debug_ids);
- INIT_LIST_HEAD(&rreq->subrequests);
- INIT_WORK(&rreq->work, NULL);
- refcount_set(&rreq->ref, 1);
- __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
- if (ctx->ops->init_request)
- ctx->ops->init_request(rreq, file);
- netfs_stat(&netfs_n_rh_rreq);
+ if (!rreq)
+ return ERR_PTR(-ENOMEM);
+
+ rreq->start = start;
+ rreq->len = len;
+ rreq->mapping = mapping;
+ rreq->inode = inode;
+ rreq->origin = origin;
+ rreq->netfs_ops = ctx->ops;
+ rreq->i_size = i_size_read(inode);
+ rreq->debug_id = atomic_inc_return(&debug_ids);
+ INIT_LIST_HEAD(&rreq->subrequests);
+ INIT_WORK(&rreq->work, NULL);
+ refcount_set(&rreq->ref, 1);
+ __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
+
+ if (ctx->ops->init_request) {
+ ret = ctx->ops->init_request(rreq, file);
+ if (ret < 0) {
+ kfree(rreq);
+ return ERR_PTR(ret);
+ }
}

+ netfs_stat(&netfs_n_rh_rreq);
return rreq;
}

diff --git a/include/linux/netfs.h b/include/linux/netfs.h
index 725b8fb8e4bb..c925596c1bb3 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -202,7 +202,7 @@ struct netfs_io_request {
* Operations the network filesystem can/must provide to the helpers.
*/
struct netfs_request_ops {
- void (*init_request)(struct netfs_io_request *rreq, struct file *file);
+ int (*init_request)(struct netfs_io_request *rreq, struct file *file);
int (*begin_cache_operation)(struct netfs_io_request *rreq);
void (*expand_readahead)(struct netfs_io_request *rreq);
bool (*clamp_length)(struct netfs_io_subrequest *subreq);