The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: Paulo Alcantara <pc@manguebit.org>
Cc: David Howells <dhowells@redhat.com>,
	Christian Brauner <christian@brauner.io>,
	Matthew Wilcox <willy@infradead.org>,
	Christoph Hellwig <hch@infradead.org>,
	Jens Axboe <axboe@kernel.dk>, Leon Romanovsky <leon@kernel.org>,
	Namjae Jeon <linkinjeon@kernel.org>,
	ChenXiaoSong <chenxiaosong@chenxiaosong.com>,
	Marc Dionne <marc.dionne@auristor.com>,
	Stefan Metzmacher <metze@samba.org>,
	Eric Van Hensbergen <ericvh@kernel.org>,
	Dominique Martinet <asmadeus@codewreck.org>,
	Ilya Dryomov <idryomov@gmail.com>,
	netfs@lists.linux.dev, linux-afs@lists.infradead.org,
	linux-cifs@vger.kernel.org, linux-nfs@vger.kernel.org,
	ceph-devel@vger.kernel.org, v9fs@lists.linux.dev,
	linux-erofs@lists.ozlabs.org, linux-fsdevel@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH v10 32/35] netfs: Add a method to get an estimate of the amount that can be written
Date: Mon, 24 Aug 2026 15:41:25 +0100	[thread overview]
Message-ID: <20260824144130.759997-33-dhowells@redhat.com> (raw)
In-Reply-To: <20260824144130.759997-1-dhowells@redhat.com>

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 <dhowells@redhat.com>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Matthew Wilcox <willy@infradead.org>
cc: Christoph Hellwig <hch@infradead.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 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);
 


  parent reply	other threads:[~2026-08-24 14:46 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-24 14:40 [PATCH v10 00/35] netfs: Keep track of folios in a segmented bio_vec[] chain David Howells
2026-08-24 14:40 ` [PATCH v10 01/35] netfs: Fix uninitialized return value in netfs_unbuffered_write() David Howells
2026-08-24 14:40 ` [PATCH v10 02/35] netfs: Fix read progress reporting David Howells
2026-08-24 14:40 ` [PATCH v10 03/35] cachefiles,netfs: sunset ondemand mode David Howells
2026-08-24 14:40 ` [PATCH v10 04/35] cachefiles: Fix potential UAF/KASAN warning David Howells
2026-08-24 14:40 ` [PATCH v10 05/35] netfs: Use uoff_t instead of unsigned long long and loff_t David Howells
2026-08-24 14:40 ` [PATCH v10 06/35] mm: Make readahead store folio count in readahead_control David Howells
2026-08-24 14:41 ` [PATCH v10 07/35] netfs: Bulk load the readahead-provided folios up front David Howells
2026-08-24 14:41 ` [PATCH v10 08/35] Add a function to kmap one page of a multipage bio_vec David Howells
2026-08-24 14:41 ` [PATCH v10 09/35] iov_iter: Make iov_iter_get_pages*() wrap iov_iter_extract_pages() David Howells
2026-08-24 14:41 ` [PATCH v10 10/35] iov_iter: Add a segmented queue of bio_vec[] David Howells
2026-08-24 14:41 ` [PATCH v10 11/35] netfs: Add some tools for managing bvecq chains David Howells
2026-08-24 14:41 ` [PATCH v10 12/35] netfs: Make mempool available for bvecq David Howells
2026-08-24 14:41 ` [PATCH v10 13/35] netfs: Add a function to extract from an iter into a bvecq David Howells
2026-08-24 14:41 ` [PATCH v10 14/35] afs: Use a bvecq to hold dir content rather than folioq David Howells
2026-08-24 14:41 ` [PATCH v10 15/35] cifs: Use a bvecq for buffering instead of a folioq David Howells
2026-08-24 14:41 ` [PATCH v10 16/35] smbdirect: Support ITER_BVECQ in smbdirect_map_sges_from_iter() David Howells
2026-08-24 14:41 ` [PATCH v10 17/35] netfs: Remove the writethrough code David Howells
2026-08-24 14:41 ` [PATCH v10 18/35] netfs: trace: Change the "clear" folio traces to "endwb" David Howells
2026-08-24 14:41 ` [PATCH v10 19/35] netfs: trace: Rejig a couple of the tracepoints David Howells
2026-08-24 14:41 ` [PATCH v10 20/35] netfs: Add some functions to wrap the all-queued handling David Howells
2026-08-24 14:41 ` [PATCH v10 21/35] netfs: Make deprecated PG_private_2 support optional David Howells
2026-08-24 14:41 ` [PATCH v10 22/35] cachefiles: Don't rely on backing fs storage map for most use cases David Howells
2026-08-24 14:41 ` [PATCH v10 23/35] netfs: Add the cache object ID to netfs_read/write tracepoints David Howells
2026-08-24 14:41 ` [PATCH v10 24/35] netfs: Switch to using bvecq rather than folio_queue and rolling_buffer David Howells
2026-08-24 14:41 ` [PATCH v10 25/35] smbdirect: Remove support for ITER_FOLIOQ from smbdirect_map_sges_from_iter() David Howells
2026-08-24 14:41 ` [PATCH v10 26/35] netfs: Remove netfs_alloc/free_folioq_buffer() David Howells
2026-08-24 14:41 ` [PATCH v10 27/35] netfs: Remove netfs_extract_user_iter() David Howells
2026-08-24 14:41 ` [PATCH v10 28/35] iov_iter: Remove ITER_FOLIOQ David Howells
2026-08-24 14:41 ` [PATCH v10 29/35] netfs: Remove folio_queue and rolling_buffer David Howells
2026-08-24 14:41 ` [PATCH v10 30/35] netfs: Simplify read abandonment David Howells
2026-08-24 15:39   ` READ_PLUS in NetFS? " Aurélien Couderc
2026-08-24 19:47     ` David Howells
2026-08-24 14:41 ` [PATCH v10 31/35] netfs: Check for too much data being read David Howells
2026-08-24 14:41 ` David Howells [this message]
2026-08-24 14:41 ` [PATCH v10 33/35] netfs: Rework writeback to use a separate list of regions to be unlocked David Howells
2026-08-24 14:41 ` [PATCH v10 34/35] netfs: Combine prepare and issue ops and grab the buffers on request David Howells
2026-08-24 14:41 ` [PATCH v10 35/35] netfs: Clean up now-unused code David Howells
2026-08-24 15:01 ` [PATCH v10 36/35] cachefiles: Preset the state xattr when creating a new file David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260824144130.759997-33-dhowells@redhat.com \
    --to=dhowells@redhat.com \
    --cc=asmadeus@codewreck.org \
    --cc=axboe@kernel.dk \
    --cc=ceph-devel@vger.kernel.org \
    --cc=chenxiaosong@chenxiaosong.com \
    --cc=christian@brauner.io \
    --cc=ericvh@kernel.org \
    --cc=hch@infradead.org \
    --cc=idryomov@gmail.com \
    --cc=leon@kernel.org \
    --cc=linkinjeon@kernel.org \
    --cc=linux-afs@lists.infradead.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-erofs@lists.ozlabs.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=marc.dionne@auristor.com \
    --cc=metze@samba.org \
    --cc=netfs@lists.linux.dev \
    --cc=pc@manguebit.org \
    --cc=v9fs@lists.linux.dev \
    --cc=willy@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox