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 1/6] NFSD: Add per-export read/write I/O mode settings
Date: Thu, 29 Oct 2026 08:05:14 -0400 [thread overview]
Message-ID: <20261029-export-iomode-v2-1-fe8ec6251a36@kernel.org> (raw)
In-Reply-To: <20261029-export-iomode-v2-0-fe8ec6251a36@kernel.org>
Add ex_read_io/ex_write_io to struct svc_export along with a
kernel-internal NFSD_IO_DEFAULT value meaning "follow the global debugfs
knob".
Add an io-mode enum to the nfsd netlink spec so the mode values are
uAPI (NFSD_IO_MODE_*), and define NFSD_IO_BUFFERED/DONTCACHE/DIRECT in
terms of it. The generated NLA_POLICY_MAX policy range-checks the new
read-io/write-io attributes.
Parse those attributes, copy the settings on cache update, and report
them in nfsd.export/content. The new options are netlink-only.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
Documentation/netlink/specs/nfsd.yaml | 24 ++++++++++++++++++++++++
fs/nfsd/export.c | 28 ++++++++++++++++++++++++++--
fs/nfsd/export.h | 2 ++
fs/nfsd/netlink.c | 4 +++-
fs/nfsd/netlink.h | 2 +-
fs/nfsd/nfsd.h | 17 +++++++++++++----
include/uapi/linux/nfsd_netlink.h | 12 ++++++++++++
7 files changed, 81 insertions(+), 8 deletions(-)
diff --git a/Documentation/netlink/specs/nfsd.yaml b/Documentation/netlink/specs/nfsd.yaml
index a4991206b45e..8b11bda24f89 100644
--- a/Documentation/netlink/specs/nfsd.yaml
+++ b/Documentation/netlink/specs/nfsd.yaml
@@ -56,6 +56,16 @@ definitions:
name: nfsclnt-idmax
value: 1024
header: linux/nfsd/export.h
+ -
+ type: enum
+ name: io-mode
+ doc: >-
+ NFS READ/WRITE I/O mode. These values match the global io_cache_read
+ and io_cache_write debugfs settings.
+ entries:
+ - buffered
+ - dontcache
+ - direct
attribute-sets:
-
@@ -302,6 +312,20 @@ attribute-sets:
-
name: fsid
type: s32
+ -
+ name: read-io
+ type: u32
+ enum: io-mode
+ doc: >-
+ Per-export NFS READ I/O mode. When absent, the export follows
+ the global io_cache_read setting.
+ -
+ name: write-io
+ type: u32
+ enum: io-mode
+ doc: >-
+ Per-export NFS WRITE I/O mode. When absent, the export follows
+ the global io_cache_write setting.
-
name: svc-export-reqs
attributes:
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 265ea8fd31c6..a85aedc0c4c8 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -838,14 +838,14 @@ static int check_export(const struct path *path, int *flags,
static int nfsd_nl_parse_one_export(struct cache_detail *cd,
struct nlattr *attr)
{
- struct nlattr *tb[NFSD_A_SVC_EXPORT_FSID + 1];
+ struct nlattr *tb[NFSD_A_SVC_EXPORT_WRITE_IO + 1];
struct auth_domain *dom = NULL;
struct svc_export exp = {}, *expp;
struct nlattr *secinfo_attr;
struct timespec64 boot;
int err, rem;
- err = nla_parse_nested(tb, NFSD_A_SVC_EXPORT_FSID, attr,
+ err = nla_parse_nested(tb, NFSD_A_SVC_EXPORT_WRITE_IO, attr,
nfsd_svc_export_nl_policy, NULL);
if (err)
return err;
@@ -873,6 +873,8 @@ static int nfsd_nl_parse_one_export(struct cache_detail *cd,
exp.cd = cd;
exp.ex_devid_map = NULL;
exp.ex_xprtsec_modes = NFSEXP_XPRTSEC_ALL;
+ exp.ex_read_io = NFSD_IO_DEFAULT;
+ exp.ex_write_io = NFSD_IO_DEFAULT;
/* expiry (required, wallclock seconds) */
if (!tb[NFSD_A_SVC_EXPORT_EXPIRY]) {
@@ -986,6 +988,12 @@ static int nfsd_nl_parse_one_export(struct cache_detail *cd,
}
}
+ /* read-io / write-io (optional u32) */
+ if (tb[NFSD_A_SVC_EXPORT_READ_IO])
+ exp.ex_read_io = nla_get_u32(tb[NFSD_A_SVC_EXPORT_READ_IO]);
+ if (tb[NFSD_A_SVC_EXPORT_WRITE_IO])
+ exp.ex_write_io = nla_get_u32(tb[NFSD_A_SVC_EXPORT_WRITE_IO]);
+
err = check_export(&exp.ex_path, &exp.ex_flags,
exp.ex_uuid);
if (err)
@@ -1342,6 +1350,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
exp.cd = cd;
exp.ex_devid_map = NULL;
exp.ex_xprtsec_modes = NFSEXP_XPRTSEC_ALL;
+ exp.ex_read_io = NFSD_IO_DEFAULT;
+ exp.ex_write_io = NFSD_IO_DEFAULT;
/* expiry */
err = get_expiry(&mesg, &exp.h.expiry_time);
@@ -1462,6 +1472,12 @@ static int is_export_stats_file(struct seq_file *m)
return !strcmp(m->file->f_path.dentry->d_name.name, "export_stats");
}
+static const char * const nfsd_io_mode_names[] = {
+ [NFSD_IO_BUFFERED] = "buffered",
+ [NFSD_IO_DONTCACHE] = "dontcache",
+ [NFSD_IO_DIRECT] = "direct",
+};
+
static int svc_export_show(struct seq_file *m,
struct cache_detail *cd,
struct cache_head *h)
@@ -1498,6 +1514,12 @@ static int svc_export_show(struct seq_file *m,
!test_bit(CACHE_NEGATIVE, &h->flags)) {
exp_flags(m, exp->ex_flags, exp->ex_fsid,
exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
+ if (exp->ex_read_io != NFSD_IO_DEFAULT)
+ seq_printf(m, ",read_io=%s",
+ nfsd_io_mode_names[exp->ex_read_io]);
+ if (exp->ex_write_io != NFSD_IO_DEFAULT)
+ seq_printf(m, ",write_io=%s",
+ nfsd_io_mode_names[exp->ex_write_io]);
if (exp->ex_uuid) {
int i;
seq_puts(m, ",uuid=");
@@ -1564,6 +1586,8 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
new->ex_flavors[i] = item->ex_flavors[i];
}
new->ex_xprtsec_modes = item->ex_xprtsec_modes;
+ new->ex_read_io = item->ex_read_io;
+ new->ex_write_io = item->ex_write_io;
}
static struct cache_head *svc_export_alloc(void)
diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
index 117fb28db1e0..1c020b53fd74 100644
--- a/fs/nfsd/export.h
+++ b/fs/nfsd/export.h
@@ -77,6 +77,8 @@ struct svc_export {
struct cache_detail *cd;
struct rcu_head ex_rcu;
unsigned long ex_xprtsec_modes;
+ s8 ex_read_io;
+ s8 ex_write_io;
struct export_stats *ex_stats;
};
diff --git a/fs/nfsd/netlink.c b/fs/nfsd/netlink.c
index 4ea6a7c1ce7f..0e60cab823eb 100644
--- a/fs/nfsd/netlink.c
+++ b/fs/nfsd/netlink.c
@@ -42,7 +42,7 @@ const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1] = {
[NFSD_A_SOCK_TRANSPORT_NAME] = { .type = NLA_NUL_STRING, },
};
-const struct nla_policy nfsd_svc_export_nl_policy[NFSD_A_SVC_EXPORT_FSID + 1] = {
+const struct nla_policy nfsd_svc_export_nl_policy[NFSD_A_SVC_EXPORT_WRITE_IO + 1] = {
[NFSD_A_SVC_EXPORT_SEQNO] = { .type = NLA_U64, },
[NFSD_A_SVC_EXPORT_CLIENT] = { .type = NLA_NUL_STRING, },
[NFSD_A_SVC_EXPORT_PATH] = { .type = NLA_NUL_STRING, },
@@ -56,6 +56,8 @@ const struct nla_policy nfsd_svc_export_nl_policy[NFSD_A_SVC_EXPORT_FSID + 1] =
[NFSD_A_SVC_EXPORT_XPRTSEC] = NLA_POLICY_MASK(NLA_U32, 0x7),
[NFSD_A_SVC_EXPORT_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x3ffff),
[NFSD_A_SVC_EXPORT_FSID] = { .type = NLA_S32, },
+ [NFSD_A_SVC_EXPORT_READ_IO] = NLA_POLICY_MAX(NLA_U32, 2),
+ [NFSD_A_SVC_EXPORT_WRITE_IO] = NLA_POLICY_MAX(NLA_U32, 2),
};
const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
diff --git a/fs/nfsd/netlink.h b/fs/nfsd/netlink.h
index 57fc86c63b1d..b4b04f7777a9 100644
--- a/fs/nfsd/netlink.h
+++ b/fs/nfsd/netlink.h
@@ -19,7 +19,7 @@ extern const struct nla_policy nfsd_expkey_nl_policy[NFSD_A_EXPKEY_PATH + 1];
extern const struct nla_policy nfsd_fslocation_nl_policy[NFSD_A_FSLOCATION_PATH + 1];
extern const struct nla_policy nfsd_fslocations_nl_policy[NFSD_A_FSLOCATIONS_LOCATION + 1];
extern const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1];
-extern const struct nla_policy nfsd_svc_export_nl_policy[NFSD_A_SVC_EXPORT_FSID + 1];
+extern const struct nla_policy nfsd_svc_export_nl_policy[NFSD_A_SVC_EXPORT_WRITE_IO + 1];
extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1];
int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index b520b51692b0..8b4bed37b46b 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -16,6 +16,7 @@
#include <linux/sunrpc/svc_xprt.h>
#include <uapi/linux/nfsd/debug.h>
+#include <uapi/linux/nfsd_netlink.h>
#undef ifdebug
#ifdef CONFIG_SUNRPC_DEBUG
@@ -134,10 +135,18 @@ extern bool nfsd_disable_splice_read __read_mostly;
extern bool nfsd_delegts_enabled __read_mostly;
enum {
- /* Any new NFSD_IO enum value must be added at the end */
- NFSD_IO_BUFFERED,
- NFSD_IO_DONTCACHE,
- NFSD_IO_DIRECT,
+ /* Values are uAPI: per-export modes are sent over netlink */
+ NFSD_IO_BUFFERED = NFSD_IO_MODE_BUFFERED,
+ NFSD_IO_DONTCACHE = NFSD_IO_MODE_DONTCACHE,
+ NFSD_IO_DIRECT = NFSD_IO_MODE_DIRECT,
+ /*
+ * Kernel-internal only: a per-export mode of NFSD_IO_DEFAULT
+ * means "follow the global nfsd_io_cache_read/write knob".
+ * It is never sent across the kernel-userspace interface.
+ * It is -1 so that it stays distinct from all present and
+ * future mode values.
+ */
+ NFSD_IO_DEFAULT = -1,
};
extern u64 nfsd_io_cache_read __read_mostly;
diff --git a/include/uapi/linux/nfsd_netlink.h b/include/uapi/linux/nfsd_netlink.h
index dcd2126d848b..f67efa23997f 100644
--- a/include/uapi/linux/nfsd_netlink.h
+++ b/include/uapi/linux/nfsd_netlink.h
@@ -59,6 +59,16 @@ enum nfsd_rpcbind_flags {
NFSD_RPCBIND_FLAGS_NO_UDP = 1,
};
+/*
+ * NFS READ/WRITE I/O mode. These values match the global io_cache_read and
+ * io_cache_write debugfs settings.
+ */
+enum nfsd_io_mode {
+ NFSD_IO_MODE_BUFFERED,
+ NFSD_IO_MODE_DONTCACHE,
+ NFSD_IO_MODE_DIRECT,
+};
+
enum {
NFSD_A_CACHE_NOTIFY_CACHE_TYPE = 1,
@@ -185,6 +195,8 @@ enum {
NFSD_A_SVC_EXPORT_XPRTSEC,
NFSD_A_SVC_EXPORT_FLAGS,
NFSD_A_SVC_EXPORT_FSID,
+ NFSD_A_SVC_EXPORT_READ_IO,
+ NFSD_A_SVC_EXPORT_WRITE_IO,
__NFSD_A_SVC_EXPORT_MAX,
NFSD_A_SVC_EXPORT_MAX = (__NFSD_A_SVC_EXPORT_MAX - 1)
--
2.56.0
next prev 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 ` Jeff Layton [this message]
2026-10-29 12:05 ` [PATCH v2 2/6] NFSD: Apply per-export I/O modes to READ and WRITE Jeff Layton
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-1-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.