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.  A filesystem like Ceph can use this to limit writes to object
boundaries.

This is part of the replacement for ->prepare_write() and will be made use
of in a later patch.

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 086869bd0db1..061d41284deb 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 c3f5c010ed52..2cd8f6a9c440 100644
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -144,6 +144,16 @@ struct netfs_writeback {
        size_t                  len;            /* Total size (can increase) */
 };
 
+/*
+ * 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
@@ -152,10 +162,14 @@ struct netfs_writeback {
 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 */
@@ -340,6 +354,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);
@@ -376,6 +393,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);
 


Reply via email to