[PATCH v4 5/6] nfs4.2: request UNCACHEABLE_DIRENT_METADATA only for directories

Mike Snitzer <[email protected]> Mon, 27 Jul 2026 17:09:42 -0400
Newsgroups org.kernel.vger.linux-nfs
Message-ID <0949ae8eb880fe0fbe702fc1c3e5fbd70ec356da.1785140181.git.snitzer@kernel.org>
The UNCACHEABLE_DIRENT_METADATA attribute (attr 88) applies only to
directory objects (NF4DIR); per draft-ietf-nfsv4-uncacheable-directories
a server must reject a query of it on any other object type with
NFS4ERR_INVAL.

Request it by object type at the single choke point
nfs4_bitmap_copy_adjust(): add FATTR4_WORD2_UNCACHEABLE_DIRENT_METADATA
for a directory target (gated on server->attr_bitmask, i.e. only when the
server supports it) and strip it for any non-directory or unknown target
(callers with an unknown object type, e.g. LOOKUP/LOOKUPP/CREATE, pass a
NULL inode and are already routed through this helper).

Crucially, attr 88 is NOT carried in the shared request bitmaps
(nfs4_fattr_bitmap, nfs4_pnfs_open_bitmap).  Those are used verbatim as
the OPEN "open_bitmap" -- the GETATTR embedded in OPEN, which is masked
only by the server's supported set and is not type-gated -- so a
directory-only attribute placed there would be requested on every
regular-file OPEN and draw NFS4ERR_INVAL.  Adding it in copy_adjust
instead keeps it off OPEN while still requesting it on directory GETATTRs.

This differs from the companion NF4REG-only UNCACHEABLE_FILE_DATA
attribute, which does ride the shared bitmaps: it is legal on the OPEN of
a regular file (where it is wanted, to drive O_DIRECT), so copy_adjust
merely strips it for non-regular targets.  Net: a regular file requests
file_data and never dirent_metadata, a directory requests dirent_metadata
and never file_data, and an unknown/other object requests neither.

The type gate runs before the helper's read/write (file) delegation
handling and is the only adjustment the directory attribute needs: a
directory cannot hold a file delegation, so the delegation-based
suppression below it never applies.

Link: https://datatracker.ietf.org/doc/draft-ietf-nfsv4-uncacheable-directories/

Signed-off-by: Mike Snitzer <[email protected]>
Assisted-by: Claude:claude-opus-4-8
---
 fs/nfs/nfs4proc.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 35156c54dac3..e4b4012d1f49 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -310,13 +310,26 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
 	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).
+	 * (NF4REG) and the uncacheable_dirent_metadata attribute only to
+	 * directories (NF4DIR); a server must reject a query of either on any
+	 * other object type with NFS4ERR_INVAL.  Never request either unless
+	 * the target is known to be of the matching type (callers with an
+	 * unknown object type, e.g. LOOKUP, pass a NULL inode).
+	 *
+	 * uncacheable_file_data rides the shared request bitmaps (it is legal
+	 * on the OPEN of a regular file, where it is wanted); strip it here for
+	 * any non-regular target.  uncacheable_dirent_metadata must NOT ride
+	 * those bitmaps -- they are used verbatim by OPEN on regular files,
+	 * where a directory-only attribute would draw NFS4ERR_INVAL -- so it is
+	 * added here for directories only, gated on server support.
 	 */
 	if (!inode || !S_ISREG(inode->i_mode))
 		dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA;
+	if (inode && S_ISDIR(inode->i_mode))
+		dst[2] |= NFS_SERVER(inode)->attr_bitmask[2] &
+			  FATTR4_WORD2_UNCACHEABLE_DIRENT_METADATA;
+	else
+		dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_DIRENT_METADATA;
 	if (!inode || !nfs_have_read_or_write_delegation(inode))
 		return;
 
-- 
2.47.3