* [PATCH 0/4] nfs: NFSv4.2 client support for UNCACHEABLE_FILE_DATA
@ 2026-06-24 19:17 Mike Snitzer
2026-06-24 19:17 ` [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute Mike Snitzer
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Mike Snitzer @ 2026-06-24 19:17 UTC (permalink / raw)
To: Trond Myklebust, Anna Schumaker; +Cc: Tom Haynes, Chuck Lever, linux-nfs
Hi,
This series adds Linux NFSv4.2 client support for the uncacheable file
data attribute defined by draft-ietf-nfsv4-uncacheable-files [1].
The attribute is an OPTIONAL, per-file, read-write boolean (FATTR4
number 87) that a server may set on a regular file to advise the client
to suppress client-side caching of that file's data -- both write-behind
and read caching. It is conceptually similar to O_DIRECT but operates at
the protocol level and requires no application changes. The motivating
use case is HPC-style concurrent writers modifying disjoint byte ranges
of a shared file, where cached/delayed writes cause read-modify-write
hazards ("write holes").
This client honors a server-set attribute; it does not set it (that is
left to server/administrator policy). When a regular file is marked
uncacheable, the client opens it O_DIRECT, which suppresses read and
write-behind caching and satisfies the spec's durability invariant via
the existing direct-I/O path. The attribute applies only to regular
files (NF4REG), so the client requests it only for regular files.
The series is organized as:
1/4 add Documentation/sunrpc/xdr/nfs4_2.x and generate the
FATTR4_UNCACHEABLE_FILE_DATA definition via xdrgen, mirroring how
the sibling NFSv4.2 attributes are defined and consumed.
2/4 decode the attribute via GETATTR, track per-exported-filesystem
support, and record it on the inode.
3/4 request the attribute only for regular files, since a server must
reject a query of it on any other object type with NFS4ERR_INVAL.
4/4 open uncacheable regular files O_DIRECT.
[1] https://datatracker.ietf.org/doc/draft-ietf-nfsv4-uncacheable-files/
All review appreciated, thanks.
Mike
Mike Snitzer (3):
nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute
nfs4.2: request UNCACHEABLE_FILE_DATA only for regular files
nfs4.2: open UNCACHEABLE_FILE_DATA files with O_DIRECT
Tom Haynes (1):
nfs4.2: add UNCACHEABLE_FILE_DATA attribute support
Documentation/sunrpc/xdr/nfs4_2.x | 52 ++++++++++++++++++++++++
fs/nfs/dir.c | 4 ++
fs/nfs/inode.c | 24 +++++++++--
fs/nfs/nfs4file.c | 2 +
fs/nfs/nfs4proc.c | 60 +++++++++++++++++++++++++---
fs/nfs/nfs4trace.h | 4 +-
fs/nfs/nfs4xdr.c | 35 +++++++++++++++-
fs/nfs/nfstrace.h | 3 +-
fs/nfsd/Makefile | 5 ++-
include/linux/nfs4.h | 2 +
include/linux/nfs_fs.h | 4 ++
include/linux/nfs_xdr.h | 8 +++-
include/linux/sunrpc/xdrgen/nfs4_2.h | 19 +++++++++
13 files changed, 209 insertions(+), 13 deletions(-)
create mode 100644 Documentation/sunrpc/xdr/nfs4_2.x
create mode 100644 include/linux/sunrpc/xdrgen/nfs4_2.h
--
2.47.3
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute
2026-06-24 19:17 [PATCH 0/4] nfs: NFSv4.2 client support for UNCACHEABLE_FILE_DATA Mike Snitzer
@ 2026-06-24 19:17 ` Mike Snitzer
2026-06-25 14:26 ` Anna Schumaker
2026-06-24 19:17 ` [PATCH 2/4] nfs4.2: add UNCACHEABLE_FILE_DATA attribute support Mike Snitzer
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Mike Snitzer @ 2026-06-24 19:17 UTC (permalink / raw)
To: Trond Myklebust, Anna Schumaker; +Cc: Tom Haynes, Chuck Lever, linux-nfs
Introduce Documentation/sunrpc/xdr/nfs4_2.x for NFSv4.2 protocol
extensions and define the UNCACHEABLE_FILE_DATA attribute (attr 87)
there, verbatim from draft-ietf-nfsv4-uncacheable-files Section 7:
typedef bool fattr4_uncacheable_file_data;
const FATTR4_UNCACHEABLE_FILE_DATA = 87;
This mirrors how the sibling NFSv4.2 attributes (FATTR4_OFFLINE=83,
FATTR4_TIME_DELEG_*=84/85, FATTR4_OPEN_ARGUMENTS=86) are defined in
Documentation/sunrpc/xdr/nfs4_1.x and generated by
tools/net/sunrpc/xdrgen into <linux/sunrpc/xdrgen/nfs4_1.h>, which
nfs4.h already includes.
Wire the fs/nfsd "make xdrgen" target to generate the definitions header
<linux/sunrpc/xdrgen/nfs4_2.h> and include it from <linux/nfs4.h>, so the
generated FATTR4_UNCACHEABLE_FILE_DATA constant and the
NFS4_fattr4_uncacheable_file_data_sz size macro are available to the
NFSv4.2 client support that follows.
No functional change.
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Assisted-by: Claude:claude-opus-4-8
---
Documentation/sunrpc/xdr/nfs4_2.x | 52 ++++++++++++++++++++++++++++
fs/nfsd/Makefile | 5 ++-
include/linux/nfs4.h | 1 +
include/linux/sunrpc/xdrgen/nfs4_2.h | 19 ++++++++++
4 files changed, 76 insertions(+), 1 deletion(-)
create mode 100644 Documentation/sunrpc/xdr/nfs4_2.x
create mode 100644 include/linux/sunrpc/xdrgen/nfs4_2.h
diff --git a/Documentation/sunrpc/xdr/nfs4_2.x b/Documentation/sunrpc/xdr/nfs4_2.x
new file mode 100644
index 000000000000..d10a91d657b0
--- /dev/null
+++ b/Documentation/sunrpc/xdr/nfs4_2.x
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2026 IETF Trust and the persons identified
+ * as the document authors. All rights reserved.
+ *
+ * The document authors are identified in RFC 7862 and
+ * draft-ietf-nfsv4-uncacheable-files.
+ *
+ * Redistribution and use in source and binary forms, with
+ * or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * - Neither the name of Internet Society, IETF or IETF
+ * Trust, nor the names of specific contributors, may be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+pragma header nfs4;
+
+/*
+ * The following content was extracted from
+ * draft-ietf-nfsv4-uncacheable-files
+ */
+
+typedef bool fattr4_uncacheable_file_data;
+
+const FATTR4_UNCACHEABLE_FILE_DATA = 87;
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index f0da4d69dc74..0ff198e102a3 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -37,11 +37,14 @@ nfsd-$(CONFIG_DEBUG_FS) += debugfs.o
#
.PHONY: xdrgen
-xdrgen: ../../include/linux/sunrpc/xdrgen/nfs4_1.h nfs4xdr_gen.h nfs4xdr_gen.c
+xdrgen: ../../include/linux/sunrpc/xdrgen/nfs4_1.h ../../include/linux/sunrpc/xdrgen/nfs4_2.h nfs4xdr_gen.h nfs4xdr_gen.c
../../include/linux/sunrpc/xdrgen/nfs4_1.h: ../../Documentation/sunrpc/xdr/nfs4_1.x
../../tools/net/sunrpc/xdrgen/xdrgen definitions $< > $@
+../../include/linux/sunrpc/xdrgen/nfs4_2.h: ../../Documentation/sunrpc/xdr/nfs4_2.x
+ ../../tools/net/sunrpc/xdrgen/xdrgen definitions $< > $@
+
nfs4xdr_gen.h: ../../Documentation/sunrpc/xdr/nfs4_1.x
../../tools/net/sunrpc/xdrgen/xdrgen declarations $< > $@
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 44e5e9fa12e1..34aa303354bc 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -18,6 +18,7 @@
#include <uapi/linux/nfs4.h>
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/xdrgen/nfs4_1.h>
+#include <linux/sunrpc/xdrgen/nfs4_2.h>
enum nfs4_acl_whotype {
NFS4_ACL_WHO_NAMED = 0,
diff --git a/include/linux/sunrpc/xdrgen/nfs4_2.h b/include/linux/sunrpc/xdrgen/nfs4_2.h
new file mode 100644
index 000000000000..9441f6cefbff
--- /dev/null
+++ b/include/linux/sunrpc/xdrgen/nfs4_2.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Generated by xdrgen. Manual edits will be lost. */
+/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_2.x */
+/* XDR specification modification time: Fri Jun 12 10:44:36 2026 */
+
+#ifndef _LINUX_XDRGEN_NFS4_2_DEF_H
+#define _LINUX_XDRGEN_NFS4_2_DEF_H
+
+#include <linux/types.h>
+#include <linux/sunrpc/xdrgen/_defs.h>
+
+typedef bool fattr4_uncacheable_file_data;
+
+enum { FATTR4_UNCACHEABLE_FILE_DATA = 87 };
+
+#define NFS4_fattr4_uncacheable_file_data_sz \
+ (XDR_bool)
+
+#endif /* _LINUX_XDRGEN_NFS4_2_DEF_H */
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/4] nfs4.2: add UNCACHEABLE_FILE_DATA attribute support
2026-06-24 19:17 [PATCH 0/4] nfs: NFSv4.2 client support for UNCACHEABLE_FILE_DATA Mike Snitzer
2026-06-24 19:17 ` [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute Mike Snitzer
@ 2026-06-24 19:17 ` Mike Snitzer
2026-06-25 14:56 ` Anna Schumaker
2026-06-24 19:17 ` [PATCH 3/4] nfs4.2: request UNCACHEABLE_FILE_DATA only for regular files Mike Snitzer
2026-06-24 19:17 ` [PATCH 4/4] nfs4.2: open UNCACHEABLE_FILE_DATA files with O_DIRECT Mike Snitzer
3 siblings, 1 reply; 10+ messages in thread
From: Mike Snitzer @ 2026-06-24 19:17 UTC (permalink / raw)
To: Trond Myklebust, Anna Schumaker; +Cc: Tom Haynes, Chuck Lever, linux-nfs
From: Tom Haynes <loghyr@hammerspace.com>
Recognize the NFSv4.2 per-file UNCACHEABLE_FILE_DATA attribute (attr 87,
draft-ietf-nfsv4-uncacheable-files): decode it via GETATTR, track per-
exported-filesystem support, and record on the inode whether a regular
file's data must not be cached. Acting on the attribute (opening such
files O_DIRECT) is done by a subsequent change.
If the NFSv4 server reports a regular file's UNCACHEABLE_FILE_DATA as
true, it indicates the file's data must not be cached; the client records
this in NFS_I(inode)->uncacheable_file_data for use by the I/O paths.
The UNCACHEABLE_FILE_DATA attribute applies only to regular files
(NF4REG); per the draft a server MUST reject a query of it on any other
object type with NFS4ERR_INVAL. A subsequent commit gates the client
accordingly.
See: https://datatracker.ietf.org/doc/draft-ietf-nfsv4-uncacheable-files/
Signed-off-by: Tom Haynes <loghyr@hammerspace.com>
[snitzer: adapt Tom's original code focused on metadata for ABE]
Co-developed-by: Mike Snitzer <snitzer@hammerspace.com>
Signed-off-by: Mike Snitzer <snitzer@hammerspace.com>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Assisted-by: Claude:claude-opus-4-8
---
fs/nfs/inode.c | 22 +++++++++++++++++++---
fs/nfs/nfs4proc.c | 14 ++++++++++++--
fs/nfs/nfs4trace.h | 4 +++-
fs/nfs/nfs4xdr.c | 35 ++++++++++++++++++++++++++++++++++-
fs/nfs/nfstrace.h | 3 ++-
include/linux/nfs4.h | 1 +
include/linux/nfs_fs.h | 3 +++
include/linux/nfs_xdr.h | 8 +++++++-
8 files changed, 81 insertions(+), 9 deletions(-)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5bcd4027d203..c1227b7c5545 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -507,6 +507,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
inode->i_blocks = 0;
nfsi->write_io = 0;
nfsi->read_io = 0;
+ nfsi->uncacheable_file_data = 0;
nfsi->read_cache_jiffies = fattr->time_start;
nfsi->attr_gencount = fattr->gencount;
@@ -561,6 +562,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
} else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED &&
fattr->size != 0)
nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
+ if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
+ nfsi->uncacheable_file_data =
+ !!(fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA);
+ else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
+ nfs_set_cache_invalid(inode, NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
nfs_setsecurity(inode, fattr);
@@ -1975,7 +1981,8 @@ static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
- NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME;
+ NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME |
+ NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
unsigned long cache_validity = NFS_I(inode)->cache_validity;
enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
@@ -2297,7 +2304,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ATIME
| NFS_INO_REVAL_FORCED
- | NFS_INO_INVALID_BLOCKS);
+ | NFS_INO_INVALID_BLOCKS
+ | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
/* Do atomic weak cache consistency updates */
nfs_wcc_update_inode(inode, fattr);
@@ -2337,7 +2345,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
| NFS_INO_INVALID_NLINK
| NFS_INO_INVALID_MODE
| NFS_INO_INVALID_OTHER
- | NFS_INO_INVALID_BTIME;
+ | NFS_INO_INVALID_BTIME
+ | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
if (S_ISDIR(inode->i_mode))
nfs_force_lookup_revalidate(inode);
attr_changed = true;
@@ -2461,6 +2470,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfsi->cache_validity |=
save_cache_validity & NFS_INO_INVALID_BLOCKS;
+ if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
+ nfsi->uncacheable_file_data =
+ !!(fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA);
+ else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
+ nfsi->cache_validity |=
+ save_cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
+
/* Update attrtimeo value if we're out of the unstable period */
if (attr_changed) {
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1360409d8de9..d237abca4793 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -228,6 +228,7 @@ const u32 nfs4_fattr_bitmap[3] = {
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
FATTR4_WORD2_SECURITY_LABEL
#endif
+ | FATTR4_WORD2_UNCACHEABLE_FILE_DATA
};
static const u32 nfs4_pnfs_open_bitmap[3] = {
@@ -250,6 +251,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
| FATTR4_WORD2_SECURITY_LABEL
#endif
+ | FATTR4_WORD2_UNCACHEABLE_FILE_DATA
};
static const u32 nfs4_open_noattr_bitmap[3] = {
@@ -327,6 +329,9 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
if (!(cache_validity & NFS_INO_INVALID_BTIME))
dst[1] &= ~FATTR4_WORD1_TIME_CREATE;
+ if (!(cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA))
+ dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
+
if (nfs_have_delegated_mtime(inode)) {
if (!(cache_validity & NFS_INO_INVALID_ATIME))
dst[1] &= ~(FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET);
@@ -1238,7 +1243,7 @@ nfs4_update_changeattr_locked(struct inode *inode,
NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
NFS_INO_INVALID_MODE | NFS_INO_INVALID_BTIME |
- NFS_INO_INVALID_XATTR;
+ NFS_INO_INVALID_XATTR | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
}
nfsi->attrtimeo_timestamp = jiffies;
@@ -3839,6 +3844,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
if (IS_ERR(state))
return ERR_CAST(state);
+
return state->inode;
}
@@ -3857,7 +3863,7 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
#define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
#define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
-#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_OPEN_ARGUMENTS - 1UL)
+#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_UNCACHEABLE_FILE_DATA - 1UL)
#define FATTR4_WORD2_NFS42_TIME_DELEG_MASK \
(FATTR4_WORD2_TIME_DELEG_MODIFY|FATTR4_WORD2_TIME_DELEG_ACCESS)
@@ -3981,6 +3987,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
memcpy(server->attr_bitmask_nl, res.attr_bitmask,
sizeof(server->attr_bitmask));
server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+ if (!(res.attr_bitmask[2] & FATTR4_WORD2_UNCACHEABLE_FILE_DATA))
+ server->fattr_valid &= ~NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA;
if (res.open_caps.oa_share_access_want[0] &
NFS4_SHARE_WANT_OPEN_XOR_DELEGATION)
@@ -5809,6 +5817,8 @@ void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
bitmask[1] |= FATTR4_WORD1_SPACE_USED;
if (cache_validity & NFS_INO_INVALID_BTIME)
bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
+ if (cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA)
+ bitmask[2] |= FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
if (cache_validity & NFS_INO_INVALID_SIZE)
bitmask[0] |= FATTR4_WORD0_SIZE;
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
index 1ed677810d9d..27748a979e12 100644
--- a/fs/nfs/nfs4trace.h
+++ b/fs/nfs/nfs4trace.h
@@ -33,7 +33,9 @@
{ NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
{ NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
{ NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" }, \
- { NFS_ATTR_FATTR_BTIME, "BTIME" })
+ { NFS_ATTR_FATTR_BTIME, "BTIME" }, \
+ { NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA, "UNCACHEABLE_FILE_DATA" })
+
DECLARE_EVENT_CLASS(nfs4_clientid_event,
TP_PROTO(
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index c23c2eee1b5c..5020ac86b977 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -120,7 +120,8 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
3*nfstime4_maxsz + \
nfs4_owner_maxsz + \
nfs4_group_maxsz + nfs4_label_maxsz + \
- decode_mdsthreshold_maxsz))
+ decode_mdsthreshold_maxsz) + \
+ NFS4_fattr4_uncacheable_file_data_sz)
#define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \
nfs4_fattr_value_maxsz)
#define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
@@ -4380,6 +4381,30 @@ static int decode_attr_open_arguments(struct xdr_stream *xdr, uint32_t *bitmap,
return 0;
}
+static int decode_attr_uncacheable_file_data(struct xdr_stream *xdr, uint32_t *bitmap,
+ uint32_t *res, uint64_t *flags)
+{
+ int status = 0;
+ __be32 *p;
+
+ if (unlikely(bitmap[2] & (FATTR4_WORD2_UNCACHEABLE_FILE_DATA - 1U)))
+ return -EIO;
+ if (likely(bitmap[2] & FATTR4_WORD2_UNCACHEABLE_FILE_DATA)) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ return -EIO;
+ if (be32_to_cpup(p))
+ *res |= NFS_AUX_UNCACHEABLE_FILE_DATA;
+ else
+ *res &= ~NFS_AUX_UNCACHEABLE_FILE_DATA;
+ bitmap[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
+ *flags |= NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA;
+ }
+ dprintk("%s: uncacheable_file_data: =%s\n", __func__,
+ (*res & NFS_AUX_UNCACHEABLE_FILE_DATA) == 0 ? "false" : "true");
+ return status;
+}
+
static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
{
unsigned int attrwords = XDR_QUADLEN(attrlen);
@@ -4725,6 +4750,8 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
uint32_t type;
int32_t err;
+ fattr->aux_flags = 0;
+
status = decode_attr_type(xdr, bitmap, &type);
if (status < 0)
goto xdr_error;
@@ -4843,6 +4870,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
goto xdr_error;
fattr->valid |= status;
+ status = decode_attr_uncacheable_file_data(xdr, bitmap, &fattr->aux_flags,
+ &fattr->valid);
+ if (status < 0)
+ goto xdr_error;
+
+ status = 0;
xdr_error:
dprintk("%s: xdr returned %d\n", __func__, -status);
return status;
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
index 4ada21f4eebd..b15c1732c869 100644
--- a/fs/nfs/nfstrace.h
+++ b/fs/nfs/nfstrace.h
@@ -33,7 +33,8 @@
{ NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
{ NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
{ NFS_INO_INVALID_MODE, "INVALID_MODE" }, \
- { NFS_INO_INVALID_BTIME, "INVALID_BTIME" })
+ { NFS_INO_INVALID_BTIME, "INVALID_BTIME" }, \
+ { NFS_INO_INVALID_UNCACHEABLE_FILE_DATA, "INVALID_UNCACHEABLE_FILE_DATA" })
#define nfs_show_nfsi_flags(v) \
__print_flags(v, "|", \
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 34aa303354bc..af402373d0e7 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -476,6 +476,7 @@ enum {
#define FATTR4_WORD2_ACL_TRUEFORM_SCOPE BIT(FATTR4_ACL_TRUEFORM_SCOPE - 64)
#define FATTR4_WORD2_POSIX_DEFAULT_ACL BIT(FATTR4_POSIX_DEFAULT_ACL - 64)
#define FATTR4_WORD2_POSIX_ACCESS_ACL BIT(FATTR4_POSIX_ACCESS_ACL - 64)
+#define FATTR4_WORD2_UNCACHEABLE_FILE_DATA BIT(FATTR4_UNCACHEABLE_FILE_DATA - 64)
/* MDS threshold bitmap bits */
#define THRESHOLD_RD (1UL << 0)
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index ec17e602c979..b9228086a1df 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -162,6 +162,8 @@ struct nfs_inode {
struct timespec64 btime;
+ unsigned char uncacheable_file_data : 1;
+
/*
* read_cache_jiffies is when we started read-caching this inode.
* attrtimeo is for how long the cached information is assumed
@@ -319,6 +321,7 @@ struct nfs4_copy_state {
#define NFS_INO_INVALID_NLINK BIT(16) /* cached nlinks is invalid */
#define NFS_INO_INVALID_MODE BIT(17) /* cached mode is invalid */
#define NFS_INO_INVALID_BTIME BIT(18) /* cached btime is invalid */
+#define NFS_INO_INVALID_UNCACHEABLE_FILE_DATA BIT(19) /* cached uncacheable_file_data is invalid */
#define NFS_INO_INVALID_ATTR (NFS_INO_INVALID_CHANGE \
| NFS_INO_INVALID_CTIME \
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 11c5b31cfc7d..2e1987ac403d 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -17,6 +17,9 @@
#define NFS_BITMASK_SZ 3
+/* aux_flags in nfs_fattr */
+#define NFS_AUX_UNCACHEABLE_FILE_DATA BIT(0)
+
struct nfs4_string {
unsigned int len;
char *data;
@@ -68,6 +71,7 @@ struct nfs_fattr {
struct timespec64 mtime;
struct timespec64 ctime;
struct timespec64 btime;
+ __u32 aux_flags; /* NFSv4 auxiliary flags bitfield */
__u64 change_attr; /* NFSv4 change attribute */
__u64 pre_change_attr;/* pre-op NFSv4 change attribute */
__u64 pre_size; /* pre_op_attr.size */
@@ -108,6 +112,7 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR_GROUP_NAME BIT_ULL(24)
#define NFS_ATTR_FATTR_V4_SECURITY_LABEL BIT_ULL(25)
#define NFS_ATTR_FATTR_BTIME BIT_ULL(26)
+#define NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA BIT_ULL(27)
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
| NFS_ATTR_FATTR_MODE \
@@ -129,7 +134,8 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
| NFS_ATTR_FATTR_SPACE_USED \
| NFS_ATTR_FATTR_BTIME \
- | NFS_ATTR_FATTR_V4_SECURITY_LABEL)
+ | NFS_ATTR_FATTR_V4_SECURITY_LABEL \
+ | NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
/*
* Maximal number of supported layout drivers.
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/4] nfs4.2: request UNCACHEABLE_FILE_DATA only for regular files
2026-06-24 19:17 [PATCH 0/4] nfs: NFSv4.2 client support for UNCACHEABLE_FILE_DATA Mike Snitzer
2026-06-24 19:17 ` [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute Mike Snitzer
2026-06-24 19:17 ` [PATCH 2/4] nfs4.2: add UNCACHEABLE_FILE_DATA attribute support Mike Snitzer
@ 2026-06-24 19:17 ` Mike Snitzer
2026-06-24 19:17 ` [PATCH 4/4] nfs4.2: open UNCACHEABLE_FILE_DATA files with O_DIRECT Mike Snitzer
3 siblings, 0 replies; 10+ messages in thread
From: Mike Snitzer @ 2026-06-24 19:17 UTC (permalink / raw)
To: Trond Myklebust, Anna Schumaker; +Cc: Tom Haynes, Chuck Lever, linux-nfs
The UNCACHEABLE_FILE_DATA attribute applies only to regular files
(NF4REG); per draft-ietf-nfsv4-uncacheable-files a server MUST reject a
query of it on any other object type with NFS4ERR_INVAL. The previous
commit decodes and tracks the attribute but does not gate it: the bit
rides in the per-server attribute bitmask (server->attr_bitmask) and in
the generic getattr request bitmap (nfs4_fattr_bitmap), so it would be
requested for non-regular objects too -- e.g. a plain directory GETATTR,
a LOOKUP that resolves to a directory, or a CREATE (which only ever makes
non-regular objects). A strict server would fail those compounds.
Gate the client accordingly:
- Only set NFS_INO_INVALID_UNCACHEABLE_FILE_DATA on regular-file inodes,
so the attribute is never (re)requested for directories or other
non-regular objects via the delegation GETATTR or nfs4_bitmask_set()
refresh paths.
- Gate the request by object type at the single choke point
nfs4_bitmap_copy_adjust(), which clears
FATTR4_WORD2_UNCACHEABLE_FILE_DATA unless the target inode is a
regular file (a NULL inode -- unknown object type -- clears it too).
This already covers GETATTR, SETATTR and LINK; route LOOKUP, LOOKUPP
and CREATE through it as well.
The bit is kept in server->attr_bitmask (it is server-supported, and OPEN
still requests it via its regular-file-only open_bitmap), so no bespoke
per-data-file bitmask plumbing is needed. The remaining getattr-bearing
compounds are already safe: ACCESS, DELEGRETURN, WRITE, CLOSE and
LAYOUTCOMMIT use server->cache_consistency_bitmask (no word2 attributes)
or operate on regular files; READDIR does not encode the bit; and
LOOKUP_ROOT, FSINFO, STATFS and PATHCONF use fixed bitmaps without it.
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Assisted-by: Claude:claude-opus-4-8
---
fs/nfs/inode.c | 6 ++++--
fs/nfs/nfs4proc.c | 37 ++++++++++++++++++++++++++++++++++---
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index c1227b7c5545..edadc3142592 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -565,7 +565,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
nfsi->uncacheable_file_data =
!!(fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA);
- else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
+ else if (S_ISREG(inode->i_mode) &&
+ (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA))
nfs_set_cache_invalid(inode, NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
nfs_setsecurity(inode, fattr);
@@ -2473,7 +2474,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
nfsi->uncacheable_file_data =
!!(fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA);
- else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
+ else if (S_ISREG(inode->i_mode) &&
+ (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA))
nfsi->cache_validity |=
save_cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d237abca4793..72d809463de7 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -308,6 +308,15 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
unsigned long cache_validity;
memcpy(dst, src, NFS4_BITMASK_SZ*sizeof(*dst));
+ /*
+ * The uncacheable_file_data attribute applies only to regular files
+ * (NF4REG); a server must reject a query of it on any other object
+ * type with NFS4ERR_INVAL. Never request it unless the target is
+ * known to be a regular file (callers with an unknown object type,
+ * e.g. LOOKUP, pass a NULL inode).
+ */
+ if (!inode || !S_ISREG(inode->i_mode))
+ dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
if (!inode || !nfs_have_read_or_write_delegation(inode))
return;
@@ -4599,6 +4608,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
.rpc_resp = &res,
};
unsigned short task_flags = 0;
+ __u32 bitmask[NFS4_BITMASK_SZ];
if (nfs_server_capable(dir, NFS_CAP_MOVEABLE))
task_flags = RPC_TASK_MOVEABLE;
@@ -4607,7 +4617,13 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
if (nfs_lookup_is_soft_revalidate(dentry))
task_flags |= RPC_TASK_TIMEOUT;
- args.bitmask = nfs4_bitmask(server, fattr->label);
+ /*
+ * The looked-up object's type is unknown here, so gate out the
+ * regular-file-only uncacheable_file_data attribute (NULL inode).
+ */
+ nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label),
+ NULL, 0);
+ args.bitmask = bitmask;
nfs_fattr_init(fattr);
@@ -4721,13 +4737,20 @@ static int _nfs4_proc_lookupp(struct inode *inode,
.rpc_resp = &res,
};
unsigned short task_flags = 0;
+ __u32 bitmask[NFS4_BITMASK_SZ];
if (server->flags & NFS_MOUNT_SOFTREVAL)
task_flags |= RPC_TASK_TIMEOUT;
if (server->caps & NFS_CAP_MOVEABLE)
task_flags |= RPC_TASK_MOVEABLE;
- args.bitmask = nfs4_bitmask(server, fattr->label);
+ /*
+ * The looked-up object's type is unknown here, so gate out the
+ * regular-file-only uncacheable_file_data attribute (NULL inode).
+ */
+ nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label),
+ NULL, 0);
+ args.bitmask = bitmask;
nfs_fattr_init(fattr);
nfs4_init_sequence(server->nfs_client, &args.seq_args, &res.seq_res, 0, 0);
@@ -5142,6 +5165,7 @@ struct nfs4_createdata {
struct nfs4_create_res res;
struct nfs_fh fh;
struct nfs_fattr fattr;
+ u32 bitmask[NFS4_BITMASK_SZ];
};
static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
@@ -5165,7 +5189,14 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
data->arg.name = name;
data->arg.attrs = sattr;
data->arg.ftype = ftype;
- data->arg.bitmask = nfs4_bitmask(server, data->fattr.label);
+ /*
+ * CREATE only makes non-regular objects, so gate out the
+ * regular-file-only uncacheable_file_data attribute (NULL inode).
+ */
+ nfs4_bitmap_copy_adjust(data->bitmask,
+ nfs4_bitmask(server, data->fattr.label),
+ NULL, 0);
+ data->arg.bitmask = data->bitmask;
data->arg.umask = current_umask();
data->res.server = server;
data->res.fh = &data->fh;
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/4] nfs4.2: open UNCACHEABLE_FILE_DATA files with O_DIRECT
2026-06-24 19:17 [PATCH 0/4] nfs: NFSv4.2 client support for UNCACHEABLE_FILE_DATA Mike Snitzer
` (2 preceding siblings ...)
2026-06-24 19:17 ` [PATCH 3/4] nfs4.2: request UNCACHEABLE_FILE_DATA only for regular files Mike Snitzer
@ 2026-06-24 19:17 ` Mike Snitzer
3 siblings, 0 replies; 10+ messages in thread
From: Mike Snitzer @ 2026-06-24 19:17 UTC (permalink / raw)
To: Trond Myklebust, Anna Schumaker; +Cc: Tom Haynes, Chuck Lever, linux-nfs
Honor the per-file UNCACHEABLE_FILE_DATA attribute by transparently
opening such regular files with O_DIRECT, so reads and writes bypass the
page cache as the attribute requires, without the application having to
request O_DIRECT itself.
This follows the model the specification describes: the attribute is
"similar in intent to O_DIRECT" and clients "retain flexibility in how
they satisfy the requirements" (draft-ietf-nfsv4-uncacheable-files
Section 4.4, "Relationship to Direct I/O"), and its Implementation
Status (Section 6) describes a prototype Linux client that "treats the
attribute as an indication to use O_DIRECT-like behavior for file
access".
Introduce an NFS_CONTEXT_O_DIRECT open-context flag: nfs4_atomic_open()
sets it when the resolved inode has uncacheable_file_data set (and the
open is not O_APPEND), and the open paths nfs_atomic_open() and
nfs4_file_open() apply O_DIRECT to the file when the flag is set.
The I/O mode is thus selected at open time and is not changed for an
already-open file: a later change to the attribute takes effect on the
next open. The specification permits this -- a client that has already
opened a file MAY continue with its existing caching behavior and apply
the updated attribute to subsequent operations (Section 5).
The delegation interaction in Section 4.3 was considered: it permits read
caching to remain when another NFSv4.2 mechanism, such as a delegation,
already ensures a consistent view of the file. That relaxation is
optional ("may remain appropriate") and read-only -- it does not relax
write-behind suppression (Section 4.1) or the WRITE durability invariant
(Section 4.2). This implementation deliberately does not take it: an
uncacheable file is opened O_DIRECT regardless of any delegation held,
which is compliant (read caching is simply suppressed more aggressively
than the Section 4.3 minimum) and avoids decoupling read vs write caching
behind a single open flag. Relaxing reads under a delegation is left as
a possible future optimization.
Section 6 observes the benefit holds "for applications that issue
well-formed I/O requests". That alignment caveat does not constrain the
Linux NFS client's over-the-wire path: the client readily issues
misaligned I/O using O_DIRECT over SunRPC to the remote NFS server. The
only place a fallback from O_DIRECT to buffered I/O for misaligned I/O
applies is NFS LOCALIO (fs/nfs/localio.c), which detects non-DIO-aligned
I/O and falls back internally; that path is unaffected by this change.
See: https://datatracker.ietf.org/doc/draft-ietf-nfsv4-uncacheable-files/
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Assisted-by: Claude:claude-opus-4-8
---
fs/nfs/dir.c | 4 ++++
fs/nfs/nfs4file.c | 2 ++
fs/nfs/nfs4proc.c | 9 +++++++++
include/linux/nfs_fs.h | 1 +
4 files changed, 16 insertions(+)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index c7b723c18620..6b07abf272b1 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2208,6 +2208,10 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
goto out;
}
file->f_mode |= FMODE_CAN_ODIRECT;
+ if (test_bit(NFS_CONTEXT_O_DIRECT, &ctx->flags)) {
+ file->f_flags |= O_DIRECT;
+ open_flags |= O_DIRECT;
+ }
err = nfs_finish_open(ctx, ctx->dentry, file, open_flags);
trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index be40e126c539..6401f6363f75 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -91,6 +91,8 @@ nfs4_file_open(struct inode *inode, struct file *filp)
nfs_fscache_open_file(inode, filp);
err = 0;
filp->f_mode |= FMODE_CAN_ODIRECT;
+ if (test_bit(NFS_CONTEXT_O_DIRECT, &ctx->flags))
+ filp->f_flags |= O_DIRECT;
out_put_ctx:
put_nfs_open_context(ctx);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 72d809463de7..5bec57a2027c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3854,6 +3854,15 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
if (IS_ERR(state))
return ERR_CAST(state);
+ /*
+ * Use O_DIRECT if file was marked as Uncacheable, see:
+ * https://datatracker.ietf.org/doc/draft-ietf-nfsv4-uncacheable-files/
+ */
+ if (!(open_flags & O_DIRECT) && NFS_I(state->inode)->uncacheable_file_data) {
+ if (!(open_flags & O_APPEND))
+ set_bit(NFS_CONTEXT_O_DIRECT, &ctx->flags);
+ }
+
return state->inode;
}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index b9228086a1df..0df1d70eee90 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -110,6 +110,7 @@ struct nfs_open_context {
#define NFS_CONTEXT_UNLOCK (3)
#define NFS_CONTEXT_FILE_OPEN (4)
#define NFS_CONTEXT_WRITE_SYNC (5)
+#define NFS_CONTEXT_O_DIRECT (6)
struct nfs4_threshold *mdsthreshold;
struct list_head list;
--
2.47.3
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute
2026-06-24 19:17 ` [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute Mike Snitzer
@ 2026-06-25 14:26 ` Anna Schumaker
2026-06-25 17:31 ` Mike Snitzer
0 siblings, 1 reply; 10+ messages in thread
From: Anna Schumaker @ 2026-06-25 14:26 UTC (permalink / raw)
To: Mike Snitzer, Trond Myklebust; +Cc: Tom Haynes, Chuck Lever, linux-nfs
Hi Mike,
On Wed, Jun 24, 2026, at 3:17 PM, Mike Snitzer wrote:
> Introduce Documentation/sunrpc/xdr/nfs4_2.x for NFSv4.2 protocol
> extensions and define the UNCACHEABLE_FILE_DATA attribute (attr 87)
> there, verbatim from draft-ietf-nfsv4-uncacheable-files Section 7:
>
> typedef bool fattr4_uncacheable_file_data;
> const FATTR4_UNCACHEABLE_FILE_DATA = 87;
>
> This mirrors how the sibling NFSv4.2 attributes (FATTR4_OFFLINE=83,
> FATTR4_TIME_DELEG_*=84/85, FATTR4_OPEN_ARGUMENTS=86) are defined in
> Documentation/sunrpc/xdr/nfs4_1.x and generated by
> tools/net/sunrpc/xdrgen into <linux/sunrpc/xdrgen/nfs4_1.h>, which
> nfs4.h already includes.
>
> Wire the fs/nfsd "make xdrgen" target to generate the definitions header
> <linux/sunrpc/xdrgen/nfs4_2.h> and include it from <linux/nfs4.h>, so the
> generated FATTR4_UNCACHEABLE_FILE_DATA constant and the
> NFS4_fattr4_uncacheable_file_data_sz size macro are available to the
> NFSv4.2 client support that follows.
Aren't these client side changes? The xdrgen stuff is used on the
server-side. I wouldn't expect any of these values to be available
if nfsd is kconfig-ed off.
Thanks,
Anna
>
> No functional change.
>
> Signed-off-by: Mike Snitzer <snitzer@kernel.org>
> Assisted-by: Claude:claude-opus-4-8
> ---
> Documentation/sunrpc/xdr/nfs4_2.x | 52 ++++++++++++++++++++++++++++
> fs/nfsd/Makefile | 5 ++-
> include/linux/nfs4.h | 1 +
> include/linux/sunrpc/xdrgen/nfs4_2.h | 19 ++++++++++
> 4 files changed, 76 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/sunrpc/xdr/nfs4_2.x
> create mode 100644 include/linux/sunrpc/xdrgen/nfs4_2.h
>
> diff --git a/Documentation/sunrpc/xdr/nfs4_2.x
> b/Documentation/sunrpc/xdr/nfs4_2.x
> new file mode 100644
> index 000000000000..d10a91d657b0
> --- /dev/null
> +++ b/Documentation/sunrpc/xdr/nfs4_2.x
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright (c) 2026 IETF Trust and the persons identified
> + * as the document authors. All rights reserved.
> + *
> + * The document authors are identified in RFC 7862 and
> + * draft-ietf-nfsv4-uncacheable-files.
> + *
> + * Redistribution and use in source and binary forms, with
> + * or without modification, are permitted provided that the
> + * following conditions are met:
> + *
> + * - Redistributions of source code must retain the above
> + * copyright notice, this list of conditions and the
> + * following disclaimer.
> + *
> + * - Redistributions in binary form must reproduce the above
> + * copyright notice, this list of conditions and the
> + * following disclaimer in the documentation and/or other
> + * materials provided with the distribution.
> + *
> + * - Neither the name of Internet Society, IETF or IETF
> + * Trust, nor the names of specific contributors, may be
> + * used to endorse or promote products derived from this
> + * software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
> + * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
> + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
> + * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
> + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
> + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +pragma header nfs4;
> +
> +/*
> + * The following content was extracted from
> + * draft-ietf-nfsv4-uncacheable-files
> + */
> +
> +typedef bool fattr4_uncacheable_file_data;
> +
> +const FATTR4_UNCACHEABLE_FILE_DATA = 87;
> diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
> index f0da4d69dc74..0ff198e102a3 100644
> --- a/fs/nfsd/Makefile
> +++ b/fs/nfsd/Makefile
> @@ -37,11 +37,14 @@ nfsd-$(CONFIG_DEBUG_FS) += debugfs.o
> #
> .PHONY: xdrgen
>
> -xdrgen: ../../include/linux/sunrpc/xdrgen/nfs4_1.h nfs4xdr_gen.h
> nfs4xdr_gen.c
> +xdrgen: ../../include/linux/sunrpc/xdrgen/nfs4_1.h
> ../../include/linux/sunrpc/xdrgen/nfs4_2.h nfs4xdr_gen.h nfs4xdr_gen.c
>
> ../../include/linux/sunrpc/xdrgen/nfs4_1.h:
> ../../Documentation/sunrpc/xdr/nfs4_1.x
> ../../tools/net/sunrpc/xdrgen/xdrgen definitions $< > $@
>
> +../../include/linux/sunrpc/xdrgen/nfs4_2.h:
> ../../Documentation/sunrpc/xdr/nfs4_2.x
> + ../../tools/net/sunrpc/xdrgen/xdrgen definitions $< > $@
> +
> nfs4xdr_gen.h: ../../Documentation/sunrpc/xdr/nfs4_1.x
> ../../tools/net/sunrpc/xdrgen/xdrgen declarations $< > $@
>
> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> index 44e5e9fa12e1..34aa303354bc 100644
> --- a/include/linux/nfs4.h
> +++ b/include/linux/nfs4.h
> @@ -18,6 +18,7 @@
> #include <uapi/linux/nfs4.h>
> #include <linux/sunrpc/msg_prot.h>
> #include <linux/sunrpc/xdrgen/nfs4_1.h>
> +#include <linux/sunrpc/xdrgen/nfs4_2.h>
>
> enum nfs4_acl_whotype {
> NFS4_ACL_WHO_NAMED = 0,
> diff --git a/include/linux/sunrpc/xdrgen/nfs4_2.h
> b/include/linux/sunrpc/xdrgen/nfs4_2.h
> new file mode 100644
> index 000000000000..9441f6cefbff
> --- /dev/null
> +++ b/include/linux/sunrpc/xdrgen/nfs4_2.h
> @@ -0,0 +1,19 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Generated by xdrgen. Manual edits will be lost. */
> +/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_2.x */
> +/* XDR specification modification time: Fri Jun 12 10:44:36 2026 */
> +
> +#ifndef _LINUX_XDRGEN_NFS4_2_DEF_H
> +#define _LINUX_XDRGEN_NFS4_2_DEF_H
> +
> +#include <linux/types.h>
> +#include <linux/sunrpc/xdrgen/_defs.h>
> +
> +typedef bool fattr4_uncacheable_file_data;
> +
> +enum { FATTR4_UNCACHEABLE_FILE_DATA = 87 };
> +
> +#define NFS4_fattr4_uncacheable_file_data_sz \
> + (XDR_bool)
> +
> +#endif /* _LINUX_XDRGEN_NFS4_2_DEF_H */
> --
> 2.47.3
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/4] nfs4.2: add UNCACHEABLE_FILE_DATA attribute support
2026-06-24 19:17 ` [PATCH 2/4] nfs4.2: add UNCACHEABLE_FILE_DATA attribute support Mike Snitzer
@ 2026-06-25 14:56 ` Anna Schumaker
2026-06-25 17:51 ` Mike Snitzer
0 siblings, 1 reply; 10+ messages in thread
From: Anna Schumaker @ 2026-06-25 14:56 UTC (permalink / raw)
To: Mike Snitzer, Trond Myklebust; +Cc: Tom Haynes, Chuck Lever, linux-nfs
Hi Mike,
On Wed, Jun 24, 2026, at 3:17 PM, Mike Snitzer wrote:
> From: Tom Haynes <loghyr@hammerspace.com>
>
> Recognize the NFSv4.2 per-file UNCACHEABLE_FILE_DATA attribute (attr 87,
> draft-ietf-nfsv4-uncacheable-files): decode it via GETATTR, track per-
> exported-filesystem support, and record on the inode whether a regular
> file's data must not be cached. Acting on the attribute (opening such
> files O_DIRECT) is done by a subsequent change.
>
> If the NFSv4 server reports a regular file's UNCACHEABLE_FILE_DATA as
> true, it indicates the file's data must not be cached; the client records
> this in NFS_I(inode)->uncacheable_file_data for use by the I/O paths.
>
> The UNCACHEABLE_FILE_DATA attribute applies only to regular files
> (NF4REG); per the draft a server MUST reject a query of it on any other
> object type with NFS4ERR_INVAL. A subsequent commit gates the client
> accordingly.
>
> See: https://datatracker.ietf.org/doc/draft-ietf-nfsv4-uncacheable-files/
>
> Signed-off-by: Tom Haynes <loghyr@hammerspace.com>
> [snitzer: adapt Tom's original code focused on metadata for ABE]
> Co-developed-by: Mike Snitzer <snitzer@hammerspace.com>
> Signed-off-by: Mike Snitzer <snitzer@hammerspace.com>
> Signed-off-by: Mike Snitzer <snitzer@kernel.org>
> Assisted-by: Claude:claude-opus-4-8
> ---
> fs/nfs/inode.c | 22 +++++++++++++++++++---
> fs/nfs/nfs4proc.c | 14 ++++++++++++--
> fs/nfs/nfs4trace.h | 4 +++-
> fs/nfs/nfs4xdr.c | 35 ++++++++++++++++++++++++++++++++++-
> fs/nfs/nfstrace.h | 3 ++-
> include/linux/nfs4.h | 1 +
> include/linux/nfs_fs.h | 3 +++
> include/linux/nfs_xdr.h | 8 +++++++-
> 8 files changed, 81 insertions(+), 9 deletions(-)
>
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 5bcd4027d203..c1227b7c5545 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -507,6 +507,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh
> *fh, struct nfs_fattr *fattr)
> inode->i_blocks = 0;
> nfsi->write_io = 0;
> nfsi->read_io = 0;
> + nfsi->uncacheable_file_data = 0;
>
> nfsi->read_cache_jiffies = fattr->time_start;
> nfsi->attr_gencount = fattr->gencount;
> @@ -561,6 +562,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh
> *fh, struct nfs_fattr *fattr)
> } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED &&
> fattr->size != 0)
> nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
> + if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
> + nfsi->uncacheable_file_data =
> + !!(fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA);
> + else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
> + nfs_set_cache_invalid(inode, NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
>
> nfs_setsecurity(inode, fattr);
>
> @@ -1975,7 +1981,8 @@ static int
> nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
> NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
> NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
> NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
> - NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME;
> + NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME |
> + NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
> unsigned long cache_validity = NFS_I(inode)->cache_validity;
> enum nfs4_change_attr_type ctype =
> NFS_SERVER(inode)->change_attr_type;
>
> @@ -2297,7 +2304,8 @@ static int nfs_update_inode(struct inode *inode,
> struct nfs_fattr *fattr)
> nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
> | NFS_INO_INVALID_ATIME
> | NFS_INO_REVAL_FORCED
> - | NFS_INO_INVALID_BLOCKS);
> + | NFS_INO_INVALID_BLOCKS
> + | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
>
> /* Do atomic weak cache consistency updates */
> nfs_wcc_update_inode(inode, fattr);
> @@ -2337,7 +2345,8 @@ static int nfs_update_inode(struct inode *inode,
> struct nfs_fattr *fattr)
> | NFS_INO_INVALID_NLINK
> | NFS_INO_INVALID_MODE
> | NFS_INO_INVALID_OTHER
> - | NFS_INO_INVALID_BTIME;
> + | NFS_INO_INVALID_BTIME
> + | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
> if (S_ISDIR(inode->i_mode))
> nfs_force_lookup_revalidate(inode);
> attr_changed = true;
> @@ -2461,6 +2470,13 @@ static int nfs_update_inode(struct inode *inode,
> struct nfs_fattr *fattr)
> nfsi->cache_validity |=
> save_cache_validity & NFS_INO_INVALID_BLOCKS;
>
> + if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
> + nfsi->uncacheable_file_data =
> + !!(fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA);
> + else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
> + nfsi->cache_validity |=
> + save_cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
> +
> /* Update attrtimeo value if we're out of the unstable period */
> if (attr_changed) {
> nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 1360409d8de9..d237abca4793 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -228,6 +228,7 @@ const u32 nfs4_fattr_bitmap[3] = {
> #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> FATTR4_WORD2_SECURITY_LABEL
> #endif
> + | FATTR4_WORD2_UNCACHEABLE_FILE_DATA
> };
>
> static const u32 nfs4_pnfs_open_bitmap[3] = {
> @@ -250,6 +251,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
> #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> | FATTR4_WORD2_SECURITY_LABEL
> #endif
> + | FATTR4_WORD2_UNCACHEABLE_FILE_DATA
> };
>
> static const u32 nfs4_open_noattr_bitmap[3] = {
> @@ -327,6 +329,9 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst,
> const __u32 *src,
> if (!(cache_validity & NFS_INO_INVALID_BTIME))
> dst[1] &= ~FATTR4_WORD1_TIME_CREATE;
>
> + if (!(cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA))
> + dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
> +
> if (nfs_have_delegated_mtime(inode)) {
> if (!(cache_validity & NFS_INO_INVALID_ATIME))
> dst[1] &= ~(FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET);
> @@ -1238,7 +1243,7 @@ nfs4_update_changeattr_locked(struct inode *inode,
> NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
> NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
> NFS_INO_INVALID_MODE | NFS_INO_INVALID_BTIME |
> - NFS_INO_INVALID_XATTR;
> + NFS_INO_INVALID_XATTR | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
> nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
> }
> nfsi->attrtimeo_timestamp = jiffies;
> @@ -3839,6 +3844,7 @@ nfs4_atomic_open(struct inode *dir, struct
> nfs_open_context *ctx,
>
> if (IS_ERR(state))
> return ERR_CAST(state);
> +
I think this unrelated whitespace change accidentally snuck in
> return state->inode;
> }
>
> @@ -3857,7 +3863,7 @@ static void nfs4_close_context(struct
> nfs_open_context *ctx, int is_sync)
>
> #define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
> #define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
> -#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_OPEN_ARGUMENTS - 1UL)
> +#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_UNCACHEABLE_FILE_DATA - 1UL)
>
> #define FATTR4_WORD2_NFS42_TIME_DELEG_MASK \
> (FATTR4_WORD2_TIME_DELEG_MODIFY|FATTR4_WORD2_TIME_DELEG_ACCESS)
> @@ -3981,6 +3987,8 @@ static int _nfs4_server_capabilities(struct
> nfs_server *server, struct nfs_fh *f
> memcpy(server->attr_bitmask_nl, res.attr_bitmask,
> sizeof(server->attr_bitmask));
> server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
> + if (!(res.attr_bitmask[2] & FATTR4_WORD2_UNCACHEABLE_FILE_DATA))
> + server->fattr_valid &= ~NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA;
>
> if (res.open_caps.oa_share_access_want[0] &
> NFS4_SHARE_WANT_OPEN_XOR_DELEGATION)
> @@ -5809,6 +5817,8 @@ void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
> bitmask[1] |= FATTR4_WORD1_SPACE_USED;
> if (cache_validity & NFS_INO_INVALID_BTIME)
> bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
> + if (cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA)
> + bitmask[2] |= FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
>
> if (cache_validity & NFS_INO_INVALID_SIZE)
> bitmask[0] |= FATTR4_WORD0_SIZE;
> diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
> index 1ed677810d9d..27748a979e12 100644
> --- a/fs/nfs/nfs4trace.h
> +++ b/fs/nfs/nfs4trace.h
> @@ -33,7 +33,9 @@
> { NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
> { NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
> { NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" }, \
> - { NFS_ATTR_FATTR_BTIME, "BTIME" })
> + { NFS_ATTR_FATTR_BTIME, "BTIME" }, \
> + { NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA, "UNCACHEABLE_FILE_DATA" })
> +
>
> DECLARE_EVENT_CLASS(nfs4_clientid_event,
> TP_PROTO(
> diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> index c23c2eee1b5c..5020ac86b977 100644
> --- a/fs/nfs/nfs4xdr.c
> +++ b/fs/nfs/nfs4xdr.c
> @@ -120,7 +120,8 @@ static int decode_layoutget(struct xdr_stream *xdr,
> struct rpc_rqst *req,
> 3*nfstime4_maxsz + \
> nfs4_owner_maxsz + \
> nfs4_group_maxsz + nfs4_label_maxsz + \
> - decode_mdsthreshold_maxsz))
> + decode_mdsthreshold_maxsz) + \
> + NFS4_fattr4_uncacheable_file_data_sz)
Can this simply be a '1' like many of the other values here? I haven't
looked into why the double-parentheses are here yet, but it might be
styilisticly better to put the new value inside them right after
decode_mdsthreshold_maxsz.
> #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \
> nfs4_fattr_value_maxsz)
> #define decode_getattr_maxsz (op_decode_hdr_maxsz +
> nfs4_fattr_maxsz)
> @@ -4380,6 +4381,30 @@ static int decode_attr_open_arguments(struct
> xdr_stream *xdr, uint32_t *bitmap,
> return 0;
> }
>
> +static int decode_attr_uncacheable_file_data(struct xdr_stream *xdr,
> uint32_t *bitmap,
> + uint32_t *res, uint64_t *flags)
> +{
> + int status = 0;
> + __be32 *p;
> +
> + if (unlikely(bitmap[2] & (FATTR4_WORD2_UNCACHEABLE_FILE_DATA - 1U)))
> + return -EIO;
> + if (likely(bitmap[2] & FATTR4_WORD2_UNCACHEABLE_FILE_DATA)) {
> + p = xdr_inline_decode(xdr, 4);
> + if (unlikely(!p))
> + return -EIO;
> + if (be32_to_cpup(p))
> + *res |= NFS_AUX_UNCACHEABLE_FILE_DATA;
> + else
> + *res &= ~NFS_AUX_UNCACHEABLE_FILE_DATA;
> + bitmap[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
> + *flags |= NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA;
> + }
> + dprintk("%s: uncacheable_file_data: =%s\n", __func__,
> + (*res & NFS_AUX_UNCACHEABLE_FILE_DATA) == 0 ? "false" : "true");
> + return status;
> +}
> +
> static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep,
> uint32_t attrlen)
> {
> unsigned int attrwords = XDR_QUADLEN(attrlen);
> @@ -4725,6 +4750,8 @@ static int decode_getfattr_attrs(struct
> xdr_stream *xdr, uint32_t *bitmap,
> uint32_t type;
> int32_t err;
>
> + fattr->aux_flags = 0;
> +
> status = decode_attr_type(xdr, bitmap, &type);
> if (status < 0)
> goto xdr_error;
> @@ -4843,6 +4870,12 @@ static int decode_getfattr_attrs(struct
> xdr_stream *xdr, uint32_t *bitmap,
> goto xdr_error;
> fattr->valid |= status;
>
> + status = decode_attr_uncacheable_file_data(xdr, bitmap, &fattr->aux_flags,
> + &fattr->valid);
> + if (status < 0)
> + goto xdr_error;
> +
> + status = 0;
> xdr_error:
> dprintk("%s: xdr returned %d\n", __func__, -status);
> return status;
> diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
> index 4ada21f4eebd..b15c1732c869 100644
> --- a/fs/nfs/nfstrace.h
> +++ b/fs/nfs/nfstrace.h
> @@ -33,7 +33,8 @@
> { NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
> { NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
> { NFS_INO_INVALID_MODE, "INVALID_MODE" }, \
> - { NFS_INO_INVALID_BTIME, "INVALID_BTIME" })
> + { NFS_INO_INVALID_BTIME, "INVALID_BTIME" }, \
> + { NFS_INO_INVALID_UNCACHEABLE_FILE_DATA, "INVALID_UNCACHEABLE_FILE_DATA" })
>
> #define nfs_show_nfsi_flags(v) \
> __print_flags(v, "|", \
> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> index 34aa303354bc..af402373d0e7 100644
> --- a/include/linux/nfs4.h
> +++ b/include/linux/nfs4.h
> @@ -476,6 +476,7 @@ enum {
> #define FATTR4_WORD2_ACL_TRUEFORM_SCOPE BIT(FATTR4_ACL_TRUEFORM_SCOPE
> - 64)
> #define FATTR4_WORD2_POSIX_DEFAULT_ACL BIT(FATTR4_POSIX_DEFAULT_ACL -
> 64)
> #define FATTR4_WORD2_POSIX_ACCESS_ACL BIT(FATTR4_POSIX_ACCESS_ACL - 64)
> +#define
> FATTR4_WORD2_UNCACHEABLE_FILE_DATA BIT(FATTR4_UNCACHEABLE_FILE_DATA -
> 64)
>
> /* MDS threshold bitmap bits */
> #define THRESHOLD_RD (1UL << 0)
> diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> index ec17e602c979..b9228086a1df 100644
> --- a/include/linux/nfs_fs.h
> +++ b/include/linux/nfs_fs.h
> @@ -162,6 +162,8 @@ struct nfs_inode {
>
> struct timespec64 btime;
>
> + unsigned char uncacheable_file_data : 1;
> +
Since this is a boolean value, could we store it in a bool?
Thanks,
Anna
> /*
> * read_cache_jiffies is when we started read-caching this inode.
> * attrtimeo is for how long the cached information is assumed
> @@ -319,6 +321,7 @@ struct nfs4_copy_state {
> #define NFS_INO_INVALID_NLINK BIT(16) /* cached nlinks is invalid */
> #define NFS_INO_INVALID_MODE BIT(17) /* cached mode is invalid */
> #define NFS_INO_INVALID_BTIME BIT(18) /* cached btime is invalid */
> +#define NFS_INO_INVALID_UNCACHEABLE_FILE_DATA BIT(19) /* cached
> uncacheable_file_data is invalid */
>
> #define NFS_INO_INVALID_ATTR (NFS_INO_INVALID_CHANGE \
> | NFS_INO_INVALID_CTIME \
> diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> index 11c5b31cfc7d..2e1987ac403d 100644
> --- a/include/linux/nfs_xdr.h
> +++ b/include/linux/nfs_xdr.h
> @@ -17,6 +17,9 @@
>
> #define NFS_BITMASK_SZ 3
>
> +/* aux_flags in nfs_fattr */
> +#define NFS_AUX_UNCACHEABLE_FILE_DATA BIT(0)
> +
> struct nfs4_string {
> unsigned int len;
> char *data;
> @@ -68,6 +71,7 @@ struct nfs_fattr {
> struct timespec64 mtime;
> struct timespec64 ctime;
> struct timespec64 btime;
> + __u32 aux_flags; /* NFSv4 auxiliary flags bitfield */
> __u64 change_attr; /* NFSv4 change attribute */
> __u64 pre_change_attr;/* pre-op NFSv4 change attribute */
> __u64 pre_size; /* pre_op_attr.size */
> @@ -108,6 +112,7 @@ struct nfs_fattr {
> #define NFS_ATTR_FATTR_GROUP_NAME BIT_ULL(24)
> #define NFS_ATTR_FATTR_V4_SECURITY_LABEL BIT_ULL(25)
> #define NFS_ATTR_FATTR_BTIME BIT_ULL(26)
> +#define NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA BIT_ULL(27)
>
> #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
> | NFS_ATTR_FATTR_MODE \
> @@ -129,7 +134,8 @@ struct nfs_fattr {
> #define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
> | NFS_ATTR_FATTR_SPACE_USED \
> | NFS_ATTR_FATTR_BTIME \
> - | NFS_ATTR_FATTR_V4_SECURITY_LABEL)
> + | NFS_ATTR_FATTR_V4_SECURITY_LABEL \
> + | NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
>
> /*
> * Maximal number of supported layout drivers.
> --
> 2.47.3
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute
2026-06-25 14:26 ` Anna Schumaker
@ 2026-06-25 17:31 ` Mike Snitzer
2026-06-25 18:08 ` Chuck Lever
0 siblings, 1 reply; 10+ messages in thread
From: Mike Snitzer @ 2026-06-25 17:31 UTC (permalink / raw)
To: Anna Schumaker; +Cc: Trond Myklebust, Tom Haynes, Chuck Lever, linux-nfs
On Thu, Jun 25, 2026 at 10:26:22AM -0400, Anna Schumaker wrote:
> Hi Mike,
>
> On Wed, Jun 24, 2026, at 3:17 PM, Mike Snitzer wrote:
> > Introduce Documentation/sunrpc/xdr/nfs4_2.x for NFSv4.2 protocol
> > extensions and define the UNCACHEABLE_FILE_DATA attribute (attr 87)
> > there, verbatim from draft-ietf-nfsv4-uncacheable-files Section 7:
> >
> > typedef bool fattr4_uncacheable_file_data;
> > const FATTR4_UNCACHEABLE_FILE_DATA = 87;
> >
> > This mirrors how the sibling NFSv4.2 attributes (FATTR4_OFFLINE=83,
> > FATTR4_TIME_DELEG_*=84/85, FATTR4_OPEN_ARGUMENTS=86) are defined in
> > Documentation/sunrpc/xdr/nfs4_1.x and generated by
> > tools/net/sunrpc/xdrgen into <linux/sunrpc/xdrgen/nfs4_1.h>, which
> > nfs4.h already includes.
> >
> > Wire the fs/nfsd "make xdrgen" target to generate the definitions header
> > <linux/sunrpc/xdrgen/nfs4_2.h> and include it from <linux/nfs4.h>, so the
> > generated FATTR4_UNCACHEABLE_FILE_DATA constant and the
> > NFS4_fattr4_uncacheable_file_data_sz size macro are available to the
> > NFSv4.2 client support that follows.
>
> Aren't these client side changes? The xdrgen stuff is used on the
> server-side. I wouldn't expect any of these values to be available
> if nfsd is kconfig-ed off.
The NFS4.x client code needs and has access to NFS spec definitions
also, via <linux/nfs4.h>.
Its only that the server side's xdrgen framework is needed to generate
updates to the headers. So you'll note that I have also included in
this commit the gnerated output of <linux/sunrpc/xdrgen/nfs4_2.h>.
Even if NFSD weren't Kconfig'd on, the NFS client code still has the
benefit of these NFS spec definitions via <linux/nfs4.h> (and its
inclusion of previously generated <linux/sunrpc/xdrgen/nfs4_1.h> and
now <linux/sunrpc/xdrgen/nfs4_2.h>).
Getting xdrgen to build and verify it to work took effort (Chuck uses
recent Fedora AFAIK, I happen to be using EL9.6 in this container, but
Claude code helped me cut through the missing deps pretty quickly).
So to be clear: the Linux kernel build (and NFS client build) isn't
dependent on xdrgen running at build time.
Tangential but related: maybe the xdrgen stuff should get lifted to
fs/nfs_common/ ? Or we're fine with it living with NFS server?
Thanks,
Mike
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/4] nfs4.2: add UNCACHEABLE_FILE_DATA attribute support
2026-06-25 14:56 ` Anna Schumaker
@ 2026-06-25 17:51 ` Mike Snitzer
0 siblings, 0 replies; 10+ messages in thread
From: Mike Snitzer @ 2026-06-25 17:51 UTC (permalink / raw)
To: Anna Schumaker; +Cc: Trond Myklebust, Tom Haynes, Chuck Lever, linux-nfs
On Thu, Jun 25, 2026 at 10:56:02AM -0400, Anna Schumaker wrote:
> Hi Mike,
>
> On Wed, Jun 24, 2026, at 3:17 PM, Mike Snitzer wrote:
> > From: Tom Haynes <loghyr@hammerspace.com>
> >
> > Recognize the NFSv4.2 per-file UNCACHEABLE_FILE_DATA attribute (attr 87,
> > draft-ietf-nfsv4-uncacheable-files): decode it via GETATTR, track per-
> > exported-filesystem support, and record on the inode whether a regular
> > file's data must not be cached. Acting on the attribute (opening such
> > files O_DIRECT) is done by a subsequent change.
> >
> > If the NFSv4 server reports a regular file's UNCACHEABLE_FILE_DATA as
> > true, it indicates the file's data must not be cached; the client records
> > this in NFS_I(inode)->uncacheable_file_data for use by the I/O paths.
> >
> > The UNCACHEABLE_FILE_DATA attribute applies only to regular files
> > (NF4REG); per the draft a server MUST reject a query of it on any other
> > object type with NFS4ERR_INVAL. A subsequent commit gates the client
> > accordingly.
> >
> > See: https://datatracker.ietf.org/doc/draft-ietf-nfsv4-uncacheable-files/
> >
> > Signed-off-by: Tom Haynes <loghyr@hammerspace.com>
> > [snitzer: adapt Tom's original code focused on metadata for ABE]
> > Co-developed-by: Mike Snitzer <snitzer@hammerspace.com>
> > Signed-off-by: Mike Snitzer <snitzer@hammerspace.com>
> > Signed-off-by: Mike Snitzer <snitzer@kernel.org>
> > Assisted-by: Claude:claude-opus-4-8
> > ---
> > fs/nfs/inode.c | 22 +++++++++++++++++++---
> > fs/nfs/nfs4proc.c | 14 ++++++++++++--
> > fs/nfs/nfs4trace.h | 4 +++-
> > fs/nfs/nfs4xdr.c | 35 ++++++++++++++++++++++++++++++++++-
> > fs/nfs/nfstrace.h | 3 ++-
> > include/linux/nfs4.h | 1 +
> > include/linux/nfs_fs.h | 3 +++
> > include/linux/nfs_xdr.h | 8 +++++++-
> > 8 files changed, 81 insertions(+), 9 deletions(-)
> >
> > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> > index 5bcd4027d203..c1227b7c5545 100644
> > --- a/fs/nfs/inode.c
> > +++ b/fs/nfs/inode.c
> > @@ -507,6 +507,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh
> > *fh, struct nfs_fattr *fattr)
> > inode->i_blocks = 0;
> > nfsi->write_io = 0;
> > nfsi->read_io = 0;
> > + nfsi->uncacheable_file_data = 0;
> >
> > nfsi->read_cache_jiffies = fattr->time_start;
> > nfsi->attr_gencount = fattr->gencount;
> > @@ -561,6 +562,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh
> > *fh, struct nfs_fattr *fattr)
> > } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED &&
> > fattr->size != 0)
> > nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
> > + if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
> > + nfsi->uncacheable_file_data =
> > + !!(fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA);
> > + else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
> > + nfs_set_cache_invalid(inode, NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
> >
> > nfs_setsecurity(inode, fattr);
> >
> > @@ -1975,7 +1981,8 @@ static int
> > nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
> > NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
> > NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
> > NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
> > - NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME;
> > + NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME |
> > + NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
> > unsigned long cache_validity = NFS_I(inode)->cache_validity;
> > enum nfs4_change_attr_type ctype =
> > NFS_SERVER(inode)->change_attr_type;
> >
> > @@ -2297,7 +2304,8 @@ static int nfs_update_inode(struct inode *inode,
> > struct nfs_fattr *fattr)
> > nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
> > | NFS_INO_INVALID_ATIME
> > | NFS_INO_REVAL_FORCED
> > - | NFS_INO_INVALID_BLOCKS);
> > + | NFS_INO_INVALID_BLOCKS
> > + | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA);
> >
> > /* Do atomic weak cache consistency updates */
> > nfs_wcc_update_inode(inode, fattr);
> > @@ -2337,7 +2345,8 @@ static int nfs_update_inode(struct inode *inode,
> > struct nfs_fattr *fattr)
> > | NFS_INO_INVALID_NLINK
> > | NFS_INO_INVALID_MODE
> > | NFS_INO_INVALID_OTHER
> > - | NFS_INO_INVALID_BTIME;
> > + | NFS_INO_INVALID_BTIME
> > + | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
> > if (S_ISDIR(inode->i_mode))
> > nfs_force_lookup_revalidate(inode);
> > attr_changed = true;
> > @@ -2461,6 +2470,13 @@ static int nfs_update_inode(struct inode *inode,
> > struct nfs_fattr *fattr)
> > nfsi->cache_validity |=
> > save_cache_validity & NFS_INO_INVALID_BLOCKS;
> >
> > + if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
> > + nfsi->uncacheable_file_data =
> > + !!(fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA);
> > + else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)
> > + nfsi->cache_validity |=
> > + save_cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
> > +
> > /* Update attrtimeo value if we're out of the unstable period */
> > if (attr_changed) {
> > nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 1360409d8de9..d237abca4793 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -228,6 +228,7 @@ const u32 nfs4_fattr_bitmap[3] = {
> > #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > FATTR4_WORD2_SECURITY_LABEL
> > #endif
> > + | FATTR4_WORD2_UNCACHEABLE_FILE_DATA
> > };
> >
> > static const u32 nfs4_pnfs_open_bitmap[3] = {
> > @@ -250,6 +251,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
> > #ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > | FATTR4_WORD2_SECURITY_LABEL
> > #endif
> > + | FATTR4_WORD2_UNCACHEABLE_FILE_DATA
> > };
> >
> > static const u32 nfs4_open_noattr_bitmap[3] = {
> > @@ -327,6 +329,9 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst,
> > const __u32 *src,
> > if (!(cache_validity & NFS_INO_INVALID_BTIME))
> > dst[1] &= ~FATTR4_WORD1_TIME_CREATE;
> >
> > + if (!(cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA))
> > + dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
> > +
> > if (nfs_have_delegated_mtime(inode)) {
> > if (!(cache_validity & NFS_INO_INVALID_ATIME))
> > dst[1] &= ~(FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET);
> > @@ -1238,7 +1243,7 @@ nfs4_update_changeattr_locked(struct inode *inode,
> > NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
> > NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
> > NFS_INO_INVALID_MODE | NFS_INO_INVALID_BTIME |
> > - NFS_INO_INVALID_XATTR;
> > + NFS_INO_INVALID_XATTR | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA;
> > nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
> > }
> > nfsi->attrtimeo_timestamp = jiffies;
> > @@ -3839,6 +3844,7 @@ nfs4_atomic_open(struct inode *dir, struct
> > nfs_open_context *ctx,
> >
> > if (IS_ERR(state))
> > return ERR_CAST(state);
> > +
>
> I think this unrelated whitespace change accidentally snuck in
Yeap, will clean up if v2 needed.
> > return state->inode;
> > }
> >
> > @@ -3857,7 +3863,7 @@ static void nfs4_close_context(struct
> > nfs_open_context *ctx, int is_sync)
> >
> > #define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
> > #define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
> > -#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_OPEN_ARGUMENTS - 1UL)
> > +#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_UNCACHEABLE_FILE_DATA - 1UL)
> >
> > #define FATTR4_WORD2_NFS42_TIME_DELEG_MASK \
> > (FATTR4_WORD2_TIME_DELEG_MODIFY|FATTR4_WORD2_TIME_DELEG_ACCESS)
> > @@ -3981,6 +3987,8 @@ static int _nfs4_server_capabilities(struct
> > nfs_server *server, struct nfs_fh *f
> > memcpy(server->attr_bitmask_nl, res.attr_bitmask,
> > sizeof(server->attr_bitmask));
> > server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
> > + if (!(res.attr_bitmask[2] & FATTR4_WORD2_UNCACHEABLE_FILE_DATA))
> > + server->fattr_valid &= ~NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA;
> >
> > if (res.open_caps.oa_share_access_want[0] &
> > NFS4_SHARE_WANT_OPEN_XOR_DELEGATION)
> > @@ -5809,6 +5817,8 @@ void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
> > bitmask[1] |= FATTR4_WORD1_SPACE_USED;
> > if (cache_validity & NFS_INO_INVALID_BTIME)
> > bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
> > + if (cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA)
> > + bitmask[2] |= FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
> >
> > if (cache_validity & NFS_INO_INVALID_SIZE)
> > bitmask[0] |= FATTR4_WORD0_SIZE;
> > diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
> > index 1ed677810d9d..27748a979e12 100644
> > --- a/fs/nfs/nfs4trace.h
> > +++ b/fs/nfs/nfs4trace.h
> > @@ -33,7 +33,9 @@
> > { NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
> > { NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
> > { NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" }, \
> > - { NFS_ATTR_FATTR_BTIME, "BTIME" })
> > + { NFS_ATTR_FATTR_BTIME, "BTIME" }, \
> > + { NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA, "UNCACHEABLE_FILE_DATA" })
> > +
> >
> > DECLARE_EVENT_CLASS(nfs4_clientid_event,
> > TP_PROTO(
> > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> > index c23c2eee1b5c..5020ac86b977 100644
> > --- a/fs/nfs/nfs4xdr.c
> > +++ b/fs/nfs/nfs4xdr.c
> > @@ -120,7 +120,8 @@ static int decode_layoutget(struct xdr_stream *xdr,
> > struct rpc_rqst *req,
> > 3*nfstime4_maxsz + \
> > nfs4_owner_maxsz + \
> > nfs4_group_maxsz + nfs4_label_maxsz + \
> > - decode_mdsthreshold_maxsz))
> > + decode_mdsthreshold_maxsz) + \
> > + NFS4_fattr4_uncacheable_file_data_sz)
>
> Can this simply be a '1' like many of the other values here? I haven't
> looked into why the double-parentheses are here yet, but it might be
> styilisticly better to put the new value inside them right after
> decode_mdsthreshold_maxsz.
I used the xdrgen generated variable because over time the reason for
each unnamed +1 gets lost. So no, I purposely made a point to put a
reason to the additional space usage.
As for the parens, I think maybe just looking at the diff isn't
adequate, if you look at the change applied to the code it will make
sense (I think).
> > #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \
> > nfs4_fattr_value_maxsz)
> > #define decode_getattr_maxsz (op_decode_hdr_maxsz +
> > nfs4_fattr_maxsz)
> > @@ -4380,6 +4381,30 @@ static int decode_attr_open_arguments(struct
> > xdr_stream *xdr, uint32_t *bitmap,
> > return 0;
> > }
> >
> > +static int decode_attr_uncacheable_file_data(struct xdr_stream *xdr,
> > uint32_t *bitmap,
> > + uint32_t *res, uint64_t *flags)
> > +{
> > + int status = 0;
> > + __be32 *p;
> > +
> > + if (unlikely(bitmap[2] & (FATTR4_WORD2_UNCACHEABLE_FILE_DATA - 1U)))
> > + return -EIO;
> > + if (likely(bitmap[2] & FATTR4_WORD2_UNCACHEABLE_FILE_DATA)) {
> > + p = xdr_inline_decode(xdr, 4);
> > + if (unlikely(!p))
> > + return -EIO;
> > + if (be32_to_cpup(p))
> > + *res |= NFS_AUX_UNCACHEABLE_FILE_DATA;
> > + else
> > + *res &= ~NFS_AUX_UNCACHEABLE_FILE_DATA;
> > + bitmap[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
> > + *flags |= NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA;
> > + }
> > + dprintk("%s: uncacheable_file_data: =%s\n", __func__,
> > + (*res & NFS_AUX_UNCACHEABLE_FILE_DATA) == 0 ? "false" : "true");
> > + return status;
> > +}
> > +
> > static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep,
> > uint32_t attrlen)
> > {
> > unsigned int attrwords = XDR_QUADLEN(attrlen);
> > @@ -4725,6 +4750,8 @@ static int decode_getfattr_attrs(struct
> > xdr_stream *xdr, uint32_t *bitmap,
> > uint32_t type;
> > int32_t err;
> >
> > + fattr->aux_flags = 0;
> > +
> > status = decode_attr_type(xdr, bitmap, &type);
> > if (status < 0)
> > goto xdr_error;
> > @@ -4843,6 +4870,12 @@ static int decode_getfattr_attrs(struct
> > xdr_stream *xdr, uint32_t *bitmap,
> > goto xdr_error;
> > fattr->valid |= status;
> >
> > + status = decode_attr_uncacheable_file_data(xdr, bitmap, &fattr->aux_flags,
> > + &fattr->valid);
> > + if (status < 0)
> > + goto xdr_error;
> > +
> > + status = 0;
> > xdr_error:
> > dprintk("%s: xdr returned %d\n", __func__, -status);
> > return status;
> > diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
> > index 4ada21f4eebd..b15c1732c869 100644
> > --- a/fs/nfs/nfstrace.h
> > +++ b/fs/nfs/nfstrace.h
> > @@ -33,7 +33,8 @@
> > { NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
> > { NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
> > { NFS_INO_INVALID_MODE, "INVALID_MODE" }, \
> > - { NFS_INO_INVALID_BTIME, "INVALID_BTIME" })
> > + { NFS_INO_INVALID_BTIME, "INVALID_BTIME" }, \
> > + { NFS_INO_INVALID_UNCACHEABLE_FILE_DATA, "INVALID_UNCACHEABLE_FILE_DATA" })
> >
> > #define nfs_show_nfsi_flags(v) \
> > __print_flags(v, "|", \
> > diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> > index 34aa303354bc..af402373d0e7 100644
> > --- a/include/linux/nfs4.h
> > +++ b/include/linux/nfs4.h
> > @@ -476,6 +476,7 @@ enum {
> > #define FATTR4_WORD2_ACL_TRUEFORM_SCOPE BIT(FATTR4_ACL_TRUEFORM_SCOPE
> > - 64)
> > #define FATTR4_WORD2_POSIX_DEFAULT_ACL BIT(FATTR4_POSIX_DEFAULT_ACL -
> > 64)
> > #define FATTR4_WORD2_POSIX_ACCESS_ACL BIT(FATTR4_POSIX_ACCESS_ACL - 64)
> > +#define
> > FATTR4_WORD2_UNCACHEABLE_FILE_DATA BIT(FATTR4_UNCACHEABLE_FILE_DATA -
> > 64)
> >
> > /* MDS threshold bitmap bits */
> > #define THRESHOLD_RD (1UL << 0)
> > diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> > index ec17e602c979..b9228086a1df 100644
> > --- a/include/linux/nfs_fs.h
> > +++ b/include/linux/nfs_fs.h
> > @@ -162,6 +162,8 @@ struct nfs_inode {
> >
> > struct timespec64 btime;
> >
> > + unsigned char uncacheable_file_data : 1;
> > +
>
> Since this is a boolean value, could we store it in a bool?
Sure, we can use a bitfield with bool as well. I don't have a
preference, but seeing "bool" would express the boolean flag nature of
this struct member (and any other flags that might follow).
Mike
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute
2026-06-25 17:31 ` Mike Snitzer
@ 2026-06-25 18:08 ` Chuck Lever
0 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2026-06-25 18:08 UTC (permalink / raw)
To: Mike Snitzer, Anna Schumaker; +Cc: Trond Myklebust, Thomas Haynes, linux-nfs
On Thu, Jun 25, 2026, at 1:31 PM, Mike Snitzer wrote:
> On Thu, Jun 25, 2026 at 10:26:22AM -0400, Anna Schumaker wrote:
>> Hi Mike,
>>
>> On Wed, Jun 24, 2026, at 3:17 PM, Mike Snitzer wrote:
>> > Introduce Documentation/sunrpc/xdr/nfs4_2.x for NFSv4.2 protocol
>> > extensions and define the UNCACHEABLE_FILE_DATA attribute (attr 87)
>> > there, verbatim from draft-ietf-nfsv4-uncacheable-files Section 7:
>> >
>> > typedef bool fattr4_uncacheable_file_data;
>> > const FATTR4_UNCACHEABLE_FILE_DATA = 87;
>> >
>> > This mirrors how the sibling NFSv4.2 attributes (FATTR4_OFFLINE=83,
>> > FATTR4_TIME_DELEG_*=84/85, FATTR4_OPEN_ARGUMENTS=86) are defined in
>> > Documentation/sunrpc/xdr/nfs4_1.x and generated by
>> > tools/net/sunrpc/xdrgen into <linux/sunrpc/xdrgen/nfs4_1.h>, which
>> > nfs4.h already includes.
>> >
>> > Wire the fs/nfsd "make xdrgen" target to generate the definitions header
>> > <linux/sunrpc/xdrgen/nfs4_2.h> and include it from <linux/nfs4.h>, so the
>> > generated FATTR4_UNCACHEABLE_FILE_DATA constant and the
>> > NFS4_fattr4_uncacheable_file_data_sz size macro are available to the
>> > NFSv4.2 client support that follows.
>>
>> Aren't these client side changes? The xdrgen stuff is used on the
>> server-side. I wouldn't expect any of these values to be available
>> if nfsd is kconfig-ed off.
>
> The NFS4.x client code needs and has access to NFS spec definitions
> also, via <linux/nfs4.h>.
>
> Its only that the server side's xdrgen framework is needed to generate
> updates to the headers. So you'll note that I have also included in
> this commit the gnerated output of <linux/sunrpc/xdrgen/nfs4_2.h>.
> Even if NFSD weren't Kconfig'd on, the NFS client code still has the
> benefit of these NFS spec definitions via <linux/nfs4.h> (and its
> inclusion of previously generated <linux/sunrpc/xdrgen/nfs4_1.h> and
> now <linux/sunrpc/xdrgen/nfs4_2.h>).
>
> Getting xdrgen to build and verify it to work took effort (Chuck uses
> recent Fedora AFAIK, I happen to be using EL9.6 in this container, but
> Claude code helped me cut through the missing deps pretty quickly).
>
> So to be clear: the Linux kernel build (and NFS client build) isn't
> dependent on xdrgen running at build time.
Correct: The Makefile changes are for a target that is used only
when the .x file changes, not for rebuilding the kernel.
However, as far as I am aware the client does not use the xdrgen
headers for anything, currently. Changing the server-side should
be done in a separate patch and only if the server-side code also
needs the new protocol definitions. Otherwise I think we continue
with the duplicated infrastructure -- or only hand-rolled, if
there are no server-side needs yet.
> Tangential but related: maybe the xdrgen stuff should get lifted to
> fs/nfs_common/ ? Or we're fine with it living with NFS server?
We're not that far along with xdrgen. I haven't heard any interest
in the client-side maintainers adopting the tool-generated approach.
--
Chuck Lever
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-06-25 18:09 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-24 19:17 [PATCH 0/4] nfs: NFSv4.2 client support for UNCACHEABLE_FILE_DATA Mike Snitzer
2026-06-24 19:17 ` [PATCH 1/4] nfs4.2: add nfs4_2.x to generate the UNCACHEABLE_FILE_DATA attribute Mike Snitzer
2026-06-25 14:26 ` Anna Schumaker
2026-06-25 17:31 ` Mike Snitzer
2026-06-25 18:08 ` Chuck Lever
2026-06-24 19:17 ` [PATCH 2/4] nfs4.2: add UNCACHEABLE_FILE_DATA attribute support Mike Snitzer
2026-06-25 14:56 ` Anna Schumaker
2026-06-25 17:51 ` Mike Snitzer
2026-06-24 19:17 ` [PATCH 3/4] nfs4.2: request UNCACHEABLE_FILE_DATA only for regular files Mike Snitzer
2026-06-24 19:17 ` [PATCH 4/4] nfs4.2: open UNCACHEABLE_FILE_DATA files with O_DIRECT Mike Snitzer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox