Message ID | 164678212401.1200972.16537041523832944934.stgit@warthog.procyon.org.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | netfs: Prep for write helpers | expand |
On Tue, 2022-03-08 at 23:28 +0000, David Howells wrote: > Change the 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@redhat.com> > cc: linux-cachefs@redhat.com > --- > > fs/9p/vfs_addr.c | 3 ++- > fs/afs/file.c | 3 ++- > fs/netfs/objects.c | 41 ++++++++++++++++++++++++----------------- > fs/netfs/read_helper.c | 20 ++++++++++++-------- > include/linux/netfs.h | 2 +- > 5 files changed, 41 insertions(+), 28 deletions(-) > > diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c > index fdc1033a1546..91d3926c9559 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 b19d635eed12..6469d7f98ef5 100644 > --- a/fs/afs/file.c > +++ b/fs/afs/file.c > @@ -359,9 +359,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 bool afs_is_cache_enabled(struct inode *inode) > diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c > index 986d7a9d25dd..ae18827e156b 100644 > --- a/fs/netfs/objects.c > +++ b/fs/netfs/objects.c > @@ -20,27 +20,34 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, > { > static atomic_t debug_ids; > 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->origin = origin; > - rreq->netfs_ops = ops; > - rreq->netfs_priv = netfs_priv; > - rreq->mapping = mapping; > - rreq->inode = file_inode(file); > - rreq->i_size = i_size_read(rreq->inode); > - rreq->debug_id = atomic_inc_return(&debug_ids); > - INIT_LIST_HEAD(&rreq->subrequests); > - INIT_WORK(&rreq->work, netfs_rreq_work); > - refcount_set(&rreq->ref, 1); > - __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags); > - if (ops->init_request) > - ops->init_request(rreq, file); > - netfs_stat(&netfs_n_rh_rreq); > + if (!rreq) > + return ERR_PTR(-ENOMEM); > + > + rreq->start = start; > + rreq->len = len; > + rreq->origin = origin; > + rreq->netfs_ops = ops; > + rreq->netfs_priv = netfs_priv; > + rreq->mapping = mapping; > + rreq->inode = file_inode(file); > + rreq->i_size = i_size_read(rreq->inode); > + rreq->debug_id = atomic_inc_return(&debug_ids); > + INIT_LIST_HEAD(&rreq->subrequests); > + INIT_WORK(&rreq->work, netfs_rreq_work); > + refcount_set(&rreq->ref, 1); > + __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags); > + if (rreq->netfs_ops->init_request) { > + ret = rreq->netfs_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/fs/netfs/read_helper.c b/fs/netfs/read_helper.c > index dea085715286..b5176f4320f4 100644 > --- a/fs/netfs/read_helper.c > +++ b/fs/netfs/read_helper.c > @@ -768,7 +768,7 @@ void netfs_readahead(struct readahead_control *ractl, > readahead_pos(ractl), > readahead_length(ractl), > NETFS_READAHEAD); > - if (!rreq) > + if (IS_ERR(rreq)) > goto cleanup; > > if (ops->begin_cache_operation) { > @@ -842,11 +842,9 @@ int netfs_readpage(struct file *file, > rreq = netfs_alloc_request(folio->mapping, file, ops, netfs_priv, > folio_file_pos(folio), folio_size(folio), > NETFS_READPAGE); > - if (!rreq) { > - if (netfs_priv) > - ops->cleanup(folio_file_mapping(folio), netfs_priv); > - folio_unlock(folio); > - return -ENOMEM; > + if (IS_ERR(rreq)) { > + ret = PTR_ERR(rreq); > + goto alloc_error; > } > > if (ops->begin_cache_operation) { > @@ -887,6 +885,11 @@ int netfs_readpage(struct file *file, > out: > netfs_put_request(rreq, false, netfs_rreq_trace_put_hold); > return ret; > +alloc_error: > + if (netfs_priv) > + ops->cleanup(folio_file_mapping(folio), netfs_priv); > + folio_unlock(folio); > + return ret; > } > EXPORT_SYMBOL(netfs_readpage); > > @@ -1007,12 +1010,13 @@ int netfs_write_begin(struct file *file, struct address_space *mapping, > goto have_folio_no_wait; > } > > - ret = -ENOMEM; > rreq = netfs_alloc_request(mapping, file, ops, netfs_priv, > folio_file_pos(folio), folio_size(folio), > NETFS_READ_FOR_WRITE); > - if (!rreq) > + if (IS_ERR(rreq)) { > + ret = PTR_ERR(rreq); > goto error; > + } > rreq->no_unlock_folio = folio_index(folio); > __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); > netfs_priv = NULL; > diff --git a/include/linux/netfs.h b/include/linux/netfs.h > index 7dc741d9b21b..4b99e38f73d9 100644 > --- a/include/linux/netfs.h > +++ b/include/linux/netfs.h > @@ -193,7 +193,7 @@ struct netfs_io_request { > */ > struct netfs_request_ops { > bool (*is_cache_enabled)(struct inode *inode); > - 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); > > Reviewed-by: Jeff Layton <jlayton@kernel.org>
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index fdc1033a1546..91d3926c9559 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 b19d635eed12..6469d7f98ef5 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -359,9 +359,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 bool afs_is_cache_enabled(struct inode *inode) diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c index 986d7a9d25dd..ae18827e156b 100644 --- a/fs/netfs/objects.c +++ b/fs/netfs/objects.c @@ -20,27 +20,34 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, { static atomic_t debug_ids; 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->origin = origin; - rreq->netfs_ops = ops; - rreq->netfs_priv = netfs_priv; - rreq->mapping = mapping; - rreq->inode = file_inode(file); - rreq->i_size = i_size_read(rreq->inode); - rreq->debug_id = atomic_inc_return(&debug_ids); - INIT_LIST_HEAD(&rreq->subrequests); - INIT_WORK(&rreq->work, netfs_rreq_work); - refcount_set(&rreq->ref, 1); - __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags); - if (ops->init_request) - ops->init_request(rreq, file); - netfs_stat(&netfs_n_rh_rreq); + if (!rreq) + return ERR_PTR(-ENOMEM); + + rreq->start = start; + rreq->len = len; + rreq->origin = origin; + rreq->netfs_ops = ops; + rreq->netfs_priv = netfs_priv; + rreq->mapping = mapping; + rreq->inode = file_inode(file); + rreq->i_size = i_size_read(rreq->inode); + rreq->debug_id = atomic_inc_return(&debug_ids); + INIT_LIST_HEAD(&rreq->subrequests); + INIT_WORK(&rreq->work, netfs_rreq_work); + refcount_set(&rreq->ref, 1); + __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags); + if (rreq->netfs_ops->init_request) { + ret = rreq->netfs_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/fs/netfs/read_helper.c b/fs/netfs/read_helper.c index dea085715286..b5176f4320f4 100644 --- a/fs/netfs/read_helper.c +++ b/fs/netfs/read_helper.c @@ -768,7 +768,7 @@ void netfs_readahead(struct readahead_control *ractl, readahead_pos(ractl), readahead_length(ractl), NETFS_READAHEAD); - if (!rreq) + if (IS_ERR(rreq)) goto cleanup; if (ops->begin_cache_operation) { @@ -842,11 +842,9 @@ int netfs_readpage(struct file *file, rreq = netfs_alloc_request(folio->mapping, file, ops, netfs_priv, folio_file_pos(folio), folio_size(folio), NETFS_READPAGE); - if (!rreq) { - if (netfs_priv) - ops->cleanup(folio_file_mapping(folio), netfs_priv); - folio_unlock(folio); - return -ENOMEM; + if (IS_ERR(rreq)) { + ret = PTR_ERR(rreq); + goto alloc_error; } if (ops->begin_cache_operation) { @@ -887,6 +885,11 @@ int netfs_readpage(struct file *file, out: netfs_put_request(rreq, false, netfs_rreq_trace_put_hold); return ret; +alloc_error: + if (netfs_priv) + ops->cleanup(folio_file_mapping(folio), netfs_priv); + folio_unlock(folio); + return ret; } EXPORT_SYMBOL(netfs_readpage); @@ -1007,12 +1010,13 @@ int netfs_write_begin(struct file *file, struct address_space *mapping, goto have_folio_no_wait; } - ret = -ENOMEM; rreq = netfs_alloc_request(mapping, file, ops, netfs_priv, folio_file_pos(folio), folio_size(folio), NETFS_READ_FOR_WRITE); - if (!rreq) + if (IS_ERR(rreq)) { + ret = PTR_ERR(rreq); goto error; + } rreq->no_unlock_folio = folio_index(folio); __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); netfs_priv = NULL; diff --git a/include/linux/netfs.h b/include/linux/netfs.h index 7dc741d9b21b..4b99e38f73d9 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -193,7 +193,7 @@ struct netfs_io_request { */ struct netfs_request_ops { bool (*is_cache_enabled)(struct inode *inode); - 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);
Change the 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@redhat.com> cc: linux-cachefs@redhat.com --- fs/9p/vfs_addr.c | 3 ++- fs/afs/file.c | 3 ++- fs/netfs/objects.c | 41 ++++++++++++++++++++++++----------------- fs/netfs/read_helper.c | 20 ++++++++++++-------- include/linux/netfs.h | 2 +- 5 files changed, 41 insertions(+), 28 deletions(-)