All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jeff Layton <jlayton@kernel.org>
To: Donald Hunter <donald.hunter@gmail.com>,
	 Jakub Kicinski <kuba@kernel.org>,
	"David S. Miller" <davem@davemloft.net>,
	 Eric Dumazet <edumazet@kernel.org>,
	Paolo Abeni <pabeni@redhat.com>,  Simon Horman <horms@kernel.org>,
	Chuck Lever <cel@kernel.org>,  NeilBrown <neil@brown.name>,
	Olga Kornievskaia <okorniev@redhat.com>,
	 Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>,
	 Trond Myklebust <trondmy@kernel.org>,
	Anna Schumaker <anna@kernel.org>,
	 Jonathan Corbet <corbet@lwn.net>,
	Shuah Khan <skhan@linuxfoundation.org>,
	 Randy Dunlap <rdunlap@infradead.org>
Cc: Steve Dickson <steved@redhat.com>,
	netdev@vger.kernel.org,  linux-kernel@vger.kernel.org,
	linux-nfs@vger.kernel.org,  linux-doc@vger.kernel.org,
	Jeff Layton <jlayton@kernel.org>
Subject: [PATCH v2 2/6] NFSD: Apply per-export I/O modes to READ and WRITE
Date: Thu, 29 Oct 2026 08:05:15 -0400	[thread overview]
Message-ID: <20261029-export-iomode-v2-2-fe8ec6251a36@kernel.org> (raw)
In-Reply-To: <20261029-export-iomode-v2-0-fe8ec6251a36@kernel.org>

Resolve each export's effective I/O mode (explicit setting, else the
global io_cache_read/write knob) in nfsd_iter_read and nfsd_vfs_write,
and skip splice for reads on exports whose effective read mode is not
buffered. Update the debugfs knob comments to match.

That per-export check makes the coupling between the debugfs knobs
unnecessary, and it defeats per-export settings, so drop it:

- io_cache_read=dontcache/direct no longer sets disable-splice-read,
  which kept read_io=buffered exports from ever using splice.
- disable-splice-read=0 no longer resets io_cache_read to buffered.

disable-splice-read is now only a global "never splice" override.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/nfsd/debugfs.c | 23 ++++++++---------------
 fs/nfsd/nfs4xdr.c |  6 ++++--
 fs/nfsd/vfs.c     | 39 ++++++++++++++++++++++++++++++++++++---
 fs/nfsd/vfs.h     |  2 ++
 4 files changed, 50 insertions(+), 20 deletions(-)

diff --git a/fs/nfsd/debugfs.c b/fs/nfsd/debugfs.c
index 4af1e6b8b212..d48297e45d7d 100644
--- a/fs/nfsd/debugfs.c
+++ b/fs/nfsd/debugfs.c
@@ -16,6 +16,10 @@ static struct dentry *nfsd_top_dir __read_mostly;
  * The default value of this setting is zero (page splicing is
  * allowed). This setting takes immediate effect for all NFS
  * versions, all exports, and in all NFSD net namespaces.
+ *
+ * Splice is used only on exports whose effective read I/O mode is
+ * buffered, so this setting is independent of io_cache_read and
+ * read_io=.
  */
 
 static int nfsd_dsr_get(void *data, u64 *val)
@@ -27,12 +31,6 @@ static int nfsd_dsr_get(void *data, u64 *val)
 static int nfsd_dsr_set(void *data, u64 val)
 {
 	nfsd_disable_splice_read = (val > 0);
-	if (!nfsd_disable_splice_read) {
-		/*
-		 * Must use buffered I/O if splice_read is enabled.
-		 */
-		nfsd_io_cache_read = NFSD_IO_BUFFERED;
-	}
 	return 0;
 }
 
@@ -47,7 +45,8 @@ DEFINE_DEBUGFS_ATTRIBUTE(nfsd_dsr_fops, nfsd_dsr_get, nfsd_dsr_set, "%llu\n");
  *   %2: NFS READ will use direct IO
  *
  * This setting takes immediate effect for all NFS versions,
- * all exports, and in all NFSD net namespaces.
+ * all exports without an explicit read_io= setting, and in all
+ * NFSD net namespaces.
  */
 
 static int nfsd_io_cache_read_get(void *data, u64 *val)
@@ -62,15 +61,8 @@ static int nfsd_io_cache_read_set(void *data, u64 val)
 
 	switch (val) {
 	case NFSD_IO_BUFFERED:
-		nfsd_io_cache_read = NFSD_IO_BUFFERED;
-		break;
 	case NFSD_IO_DONTCACHE:
 	case NFSD_IO_DIRECT:
-		/*
-		 * Must disable splice_read when enabling
-		 * NFSD_IO_DONTCACHE.
-		 */
-		nfsd_disable_splice_read = true;
 		nfsd_io_cache_read = val;
 		break;
 	default:
@@ -92,7 +84,8 @@ DEFINE_DEBUGFS_ATTRIBUTE(nfsd_io_cache_read_fops, nfsd_io_cache_read_get,
  *   %1: NFS WRITE will use dontcache (buffered IO w/ dropbehind)
  *
  * This setting takes immediate effect for all NFS versions,
- * all exports, and in all NFSD net namespaces.
+ * all exports without an explicit write_io= setting, and in all
+ * NFSD net namespaces.
  */
 
 static int nfsd_io_cache_write_get(void *data, u64 *val)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 4d983444604a..d4a88bef8444 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -5366,7 +5366,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
 	maxcount = min_t(unsigned long, read->rd_length,
 			 (xdr->buf->buflen - xdr->buf->len));
 
-	if (file->f_op->splice_read && splice_ok)
+	if (file->f_op->splice_read && splice_ok &&
+	    nfsd_read_io_mode(read->rd_fhp->fh_export) == NFSD_IO_BUFFERED)
 		nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
 	else
 		nfserr = nfsd4_encode_readv(resp, read, maxcount);
@@ -6264,7 +6265,8 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
 	maxcount = min_t(unsigned long, read->rd_length,
 			 (xdr->buf->buflen - xdr->buf->len));
 
-	if (file->f_op->splice_read && splice_ok)
+	if (file->f_op->splice_read && splice_ok &&
+	    nfsd_read_io_mode(read->rd_fhp->fh_export) == NFSD_IO_BUFFERED)
 		nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
 	else
 		nfserr = nfsd4_encode_readv(resp, read, maxcount);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index f59a55f89c88..779ad3a61172 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1266,6 +1266,38 @@ static bool nfsd_direct_read_ok(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	return true;
 }
 
+/**
+ * nfsd_read_io_mode - effective NFS READ I/O mode for an export
+ * @exp: export being accessed
+ *
+ * An export without an explicit read_io= setting follows the global
+ * nfsd_io_cache_read knob.
+ *
+ * Returns one of NFSD_IO_BUFFERED, NFSD_IO_DONTCACHE, or NFSD_IO_DIRECT.
+ */
+int nfsd_read_io_mode(struct svc_export *exp)
+{
+	if (exp->ex_read_io == NFSD_IO_DEFAULT)
+		return nfsd_io_cache_read;
+	return exp->ex_read_io;
+}
+
+/**
+ * nfsd_write_io_mode - effective NFS WRITE I/O mode for an export
+ * @exp: export being accessed
+ *
+ * An export without an explicit write_io= setting follows the global
+ * nfsd_io_cache_write knob.
+ *
+ * Returns one of NFSD_IO_BUFFERED, NFSD_IO_DONTCACHE, or NFSD_IO_DIRECT.
+ */
+int nfsd_write_io_mode(struct svc_export *exp)
+{
+	if (exp->ex_write_io == NFSD_IO_DEFAULT)
+		return nfsd_io_cache_write;
+	return exp->ex_write_io;
+}
+
 /**
  * nfsd_iter_read - Perform a VFS read using an iterator
  * @rqstp: RPC transaction context
@@ -1300,7 +1332,7 @@ __be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
 	init_sync_kiocb(&kiocb, file);
 
-	switch (nfsd_io_cache_read) {
+	switch (nfsd_read_io_mode(fhp->fh_export)) {
 	case NFSD_IO_BUFFERED:
 		break;
 	case NFSD_IO_DIRECT:
@@ -1654,7 +1686,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	if (verf)
 		nfsd_copy_write_verifier(verf, nn);
 
-	switch (nfsd_io_cache_write) {
+	switch (nfsd_write_io_mode(exp)) {
 	case NFSD_IO_DIRECT:
 		host_err = nfsd_direct_write(rqstp, fhp, nf, nvecs,
 					     cnt, &kiocb);
@@ -1761,7 +1793,8 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		return err;
 
 	file = nf->nf_file;
-	if (file->f_op->splice_read && nfsd_read_splice_ok(rqstp))
+	if (file->f_op->splice_read && nfsd_read_splice_ok(rqstp) &&
+	    nfsd_read_io_mode(fhp->fh_export) == NFSD_IO_BUFFERED)
 		err = nfsd_splice_read(rqstp, fhp, file, offset, count, eof);
 	else
 		err = nfsd_iter_read(rqstp, fhp, nf, offset, count, eof);
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 1f05c83a3ea6..3cac25adf16b 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -184,6 +184,8 @@ __be32		nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 				struct nfsd_file *nf, loff_t offset,
 				unsigned long *count, u32 *eof);
 bool		nfsd_read_splice_ok(struct svc_rqst *rqstp);
+int		nfsd_read_io_mode(struct svc_export *exp);
+int		nfsd_write_io_mode(struct svc_export *exp);
 __be32		nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 				loff_t offset, unsigned long *count,
 				u32 *eof);

-- 
2.56.0


  parent reply	other threads:[~2026-10-29 12:05 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-29 12:05 [PATCH v2 0/6] nfsd: add new export options for controlling read/write iomode Jeff Layton
2026-10-29 12:05 ` [PATCH v2 1/6] NFSD: Add per-export read/write I/O mode settings Jeff Layton
2026-10-29 12:05 ` Jeff Layton [this message]
2026-10-29 12:05 ` [PATCH v2 3/6] NFSD: Document per-export read_io= and write_io= options Jeff Layton
2026-10-29 12:05 ` [PATCH v2 4/6] NFSD: Keep per-export statistics across export cache updates Jeff Layton
2026-10-29 12:05 ` [PATCH v2 5/6] NFSD: Count the storage reads of each export's READs Jeff Layton
2026-10-29 12:05 ` [PATCH v2 6/6] NFSD: Document how to choose an IO mode Jeff Layton

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=20261029-export-iomode-v2-2-fe8ec6251a36@kernel.org \
    --to=jlayton@kernel.org \
    --cc=Dai.Ngo@oracle.com \
    --cc=anna@kernel.org \
    --cc=cel@kernel.org \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=donald.hunter@gmail.com \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neil@brown.name \
    --cc=netdev@vger.kernel.org \
    --cc=okorniev@redhat.com \
    --cc=pabeni@redhat.com \
    --cc=rdunlap@infradead.org \
    --cc=skhan@linuxfoundation.org \
    --cc=steved@redhat.com \
    --cc=tom@talpey.com \
    --cc=trondmy@kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.