[PATCH v10 32/35] netfs: Add a method to get an estimate of the amount that can be written
David Howells <[email protected]>
| Newsgroups | dev.linux.lists.netfs,dev.linux.lists.v9fs,org.kernel.vger.ceph-devel,org.kernel.vger.linux-cifs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs,org.ozlabs.lists.linux-erofs |
|---|---|
| Message-ID | <[email protected]> |
Add a method, both to the netfs cache API and the netfs filesystem API, that allows netfslib to query how much can be written to a stream in one go. Signed-off-by: David Howells <[email protected]> cc: Paulo Alcantara <[email protected]> cc: Matthew Wilcox <[email protected]> cc: Christoph Hellwig <[email protected]> cc: [email protected] cc: [email protected] --- fs/9p/vfs_addr.c | 17 +++++++++++++++++ fs/afs/file.c | 2 +- fs/afs/internal.h | 3 +++ fs/afs/write.c | 17 +++++++++++++++++ fs/cachefiles/io.c | 15 ++++++++++++++- fs/netfs/write_issue.c | 2 ++ fs/smb/client/file.c | 14 ++++++++++++++ include/linux/netfs.h | 22 ++++++++++++++++++++++ 8 files changed, 90 insertions(+), 2 deletions(-) diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 2129fcb0f65c..9b163a13ec3f 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -48,6 +48,22 @@ static void v9fs_begin_writeback(struct netfs_io_request *wreq) wreq->io_streams[0].avail = true; } +/* + * Estimate how much data should be accumulated before we start issuing + * write subrequests. + */ +static int v9fs_estimate_write(struct netfs_io_request *wreq, + struct netfs_io_stream *stream, + struct netfs_write_estimate *estimate) +{ + struct p9_fid *fid = wreq->netfs_priv; + unsigned long long limit = ULLONG_MAX - stream->issue_from; + unsigned long long max_len = fid->clnt->msize - P9_IOHDRSZ; + + estimate->issue_at = stream->issue_from + umin(max_len, limit); + return 0; +} + /* * Issue a subrequest to write to the server. */ @@ -185,6 +201,7 @@ const struct netfs_request_ops v9fs_req_ops = { .free_request = v9fs_free_request, .issue_read = v9fs_issue_read, .begin_writeback = v9fs_begin_writeback, + .estimate_write = v9fs_estimate_write, .issue_write = v9fs_issue_write, }; diff --git a/fs/afs/file.c b/fs/afs/file.c index 11695be8c4a5..4a412e0472ec 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -469,7 +469,7 @@ const struct netfs_request_ops afs_req_ops = { .update_i_size = afs_update_i_size, .invalidate_cache = afs_netfs_invalidate_cache, .begin_writeback = afs_begin_writeback, - .prepare_write = afs_prepare_write, + .estimate_write = afs_estimate_write, .issue_write = afs_issue_write, .retry_request = afs_retry_request, }; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 556e7e7777f2..ae2bc699bfde 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -1698,6 +1698,9 @@ extern int afs_check_volume_status(struct afs_volume *, struct afs_operation *); /* * write.c */ +int afs_estimate_write(struct netfs_io_request *wreq, + struct netfs_io_stream *stream, + struct netfs_write_estimate *estimate); void afs_prepare_write(struct netfs_io_subrequest *subreq); void afs_issue_write(struct netfs_io_subrequest *subreq); void afs_begin_writeback(struct netfs_io_request *wreq); diff --git a/fs/afs/write.c b/fs/afs/write.c index 7f34b939706a..a0c9916f594b 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -82,6 +82,23 @@ static const struct afs_operation_ops afs_store_data_operation = { .success = afs_store_data_success, }; +/* + * Estimate the maximum size of a write we can send to the server. + */ +int afs_estimate_write(struct netfs_io_request *wreq, + struct netfs_io_stream *stream, + struct netfs_write_estimate *estimate) +{ + unsigned long long limit = ULLONG_MAX - stream->issue_from; + unsigned long long max_len = 256 * 1024 * 1024; + + //if (test_bit(NETFS_SREQ_RETRYING, &subreq->flags)) + // max_len = 512 * 1024; + + estimate->issue_at = stream->issue_from + umin(max_len, limit); + return 0; +} + /* * Prepare a subrequest to write to the server. This sets the max_len * parameter. diff --git a/fs/cachefiles/io.c b/fs/cachefiles/io.c index 23007f450ef4..91b69be78c6b 100644 --- a/fs/cachefiles/io.c +++ b/fs/cachefiles/io.c @@ -26,7 +26,10 @@ struct cachefiles_kiocb { }; struct cachefiles_object *object; netfs_io_terminated_t term_func; - void *term_func_priv; + union { + struct netfs_io_subrequest *subreq; + void *term_func_priv; + }; bool was_async; unsigned int inval_counter; /* Copy of cookie->inval_counter */ u64 b_writing; @@ -611,6 +614,15 @@ static int cachefiles_prepare_write(struct netfs_cache_resources *cres, return ret; } +static int cachefiles_estimate_write(struct netfs_io_request *wreq, + struct netfs_io_stream *stream, + struct netfs_write_estimate *estimate) +{ + estimate->issue_at = stream->issue_from + MAX_RW_COUNT; + estimate->max_segs = BIO_MAX_VECS; + return 0; +} + static void cachefiles_prepare_write_subreq(struct netfs_io_subrequest *subreq) { struct netfs_io_request *wreq = subreq->rreq; @@ -898,6 +910,7 @@ static const struct netfs_cache_ops cachefiles_netfs_cache_ops = { .issue_write = cachefiles_issue_write, .prepare_write = cachefiles_prepare_write, .prepare_write_subreq = cachefiles_prepare_write_subreq, + .estimate_write = cachefiles_estimate_write, .query_occupancy = cachefiles_query_occupancy, .collect_write = cachefiles_collect_write, }; diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c index a5c5ba5deb43..025ea5763fda 100644 --- a/fs/netfs/write_issue.c +++ b/fs/netfs/write_issue.c @@ -114,6 +114,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping, wreq->io_streams[0].stream_nr = 0; wreq->io_streams[0].source = NETFS_UPLOAD_TO_SERVER; + wreq->io_streams[0].estimate_write = ictx->ops->estimate_write; wreq->io_streams[0].prepare_write = ictx->ops->prepare_write; wreq->io_streams[0].issue_write = ictx->ops->issue_write; wreq->io_streams[0].collected_to = start; @@ -126,6 +127,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping, if (fscache_resources_valid(&wreq->cache_resources)) { wreq->io_streams[1].avail = true; wreq->io_streams[1].active = true; + wreq->io_streams[1].estimate_write = wreq->cache_resources.ops->estimate_write; wreq->io_streams[1].prepare_write = wreq->cache_resources.ops->prepare_write_subreq; wreq->io_streams[1].issue_write = wreq->cache_resources.ops->issue_write; } diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index ac89c1ba56b1..7ad464782439 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -39,6 +39,19 @@ static int cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush); +/* + * Estimate the amount of data that can be written in one RPC op. + */ +static int cifs_estimate_write(struct netfs_io_request *wreq, + struct netfs_io_stream *stream, + struct netfs_write_estimate *estimate) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(wreq->inode->i_sb); + + estimate->issue_at = stream->issue_from + cifs_sb->ctx->wsize; + return 0; +} + /* * Prepare a subrequest to upload to the server. We need to allocate credits * so that we know the maximum amount of data that we can include in it. @@ -362,6 +375,7 @@ const struct netfs_request_ops cifs_req_ops = { .issue_read = cifs_issue_read, .done = cifs_rreq_done, .begin_writeback = cifs_begin_writeback, + .estimate_write = cifs_estimate_write, .prepare_write = cifs_prepare_write, .issue_write = cifs_issue_write, .invalidate_cache = cifs_netfs_invalidate_cache, diff --git a/include/linux/netfs.h b/include/linux/netfs.h index 6ee3891845e9..656f4f3f80b6 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -134,6 +134,16 @@ enum netfs_cache_collect { NETFS_CACHE_COLLECT_WRITE_CANCEL, /* Currently collecting cancelled writes */ }; +/* + * Estimate of maximum write subrequest for writeback. The filesystem is + * responsible for filling this in when called from ->estimate_write(), though + * netfslib will preset infinite defaults. + */ +struct netfs_write_estimate { + uoff_t issue_at; /* Point at which we must submit */ + int max_segs; /* Max number of segments in a single RPC */ +}; + /* * Stream of I/O subrequests going to a particular destination, such as the * server or the local cache. This is mainly intended for writing where we may @@ -142,10 +152,14 @@ enum netfs_cache_collect { struct netfs_io_stream { /* Submission tracking */ struct netfs_io_subrequest *construct; /* Op being constructed */ + uoff_t issue_from; /* Current issue point */ size_t sreq_max_len; /* Maximum size of a subrequest */ unsigned int sreq_max_segs; /* 0 or max number of segments in an iterator */ unsigned int submit_off; /* Folio offset we're submitting from */ unsigned int submit_len; /* Amount of data left to submit */ + int (*estimate_write)(struct netfs_io_request *wreq, + struct netfs_io_stream *stream, + struct netfs_write_estimate *estimate); void (*prepare_write)(struct netfs_io_subrequest *subreq); void (*issue_write)(struct netfs_io_subrequest *subreq); /* Collection tracking */ @@ -328,6 +342,9 @@ struct netfs_request_ops { /* Write request handling */ void (*begin_writeback)(struct netfs_io_request *wreq); + int (*estimate_write)(struct netfs_io_request *wreq, + struct netfs_io_stream *stream, + struct netfs_write_estimate *estimate); void (*prepare_write)(struct netfs_io_subrequest *subreq); void (*issue_write)(struct netfs_io_subrequest *subreq); void (*retry_request)(struct netfs_io_request *wreq, struct netfs_io_stream *stream); @@ -364,6 +381,11 @@ struct netfs_cache_ops { netfs_io_terminated_t term_func, void *term_func_priv); + /* Estimate the amount of data that can be written in an op. */ + int (*estimate_write)(struct netfs_io_request *wreq, + struct netfs_io_stream *stream, + struct netfs_write_estimate *estimate); + /* Write data to the cache from a netfs subrequest. */ void (*issue_write)(struct netfs_io_subrequest *subreq);