Linux NFS development
 help / color / mirror / Atom feed
From: Chuck Lever <cel@kernel.org>
To: Chuck Lever <cel@kernel.org>, Jeff Layton <jlayton@kernel.org>,
	 NeilBrown <neil@brown.name>,
	Olga Kornievskaia <okorniev@redhat.com>,
	 Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: linux-nfs@vger.kernel.org
Subject: [PATCH 5/5] NFSD: Honor OPEN4_SHARE_ACCESS_WANT_READ_DELEG on a read-write OPEN
Date: Thu, 08 Oct 2026 14:18:31 -0400	[thread overview]
Message-ID: <20261008-want-read-v1-5-e372262857c8@kernel.org> (raw)
In-Reply-To: <20261008-want-read-v1-0-e372262857c8@kernel.org>

RFC 8881 Section 18.16.3 defines OPEN4_SHARE_ACCESS_WANT_READ_DELEG
as a request for an OPEN_DELEGATE_READ delegation regardless of the
access bits in the OPEN. NFSD chooses the delegation type from the
access bits alone, so an OPEN for both read and write that sets
WANT_READ_DELEG gets a write delegation.

Any other client's open recalls that write delegation, and another
client's GETATTR triggers a CB_GETATTR. The read delegation the
client asked for survives both. Granting no delegation would also
respect the request, but it withholds a delegation NFSD is able to
grant.

Try for a read delegation when the OPEN sets WANT_READ_DELEG and
includes read access. After this change, a write-only OPEN that
sets WANT_READ_DELEG gets no delegation, with ond_why set to
WND4_RESOURCE. When the OPEN also sets
OPEN4_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION, return the open
stateid along with the read delegation.

Signed-off-by: Chuck Lever <cel@kernel.org>
---
 fs/nfsd/nfs4state.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6bb70d50e9d9..920967dd6f84 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -6984,6 +6984,12 @@ static bool nfsd4_want_deleg_timestamps(const struct nfsd4_open *open)
 	return open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS;
 }
 
+static bool nfsd4_want_read_deleg(const struct nfsd4_open *open)
+{
+	return (open->op_deleg_want & NFS4_SHARE_WANT_TYPE_MASK) ==
+		OPEN4_SHARE_ACCESS_WANT_READ_DELEG;
+}
+
 static void
 nfs4_delegation_record_grant_slot(struct nfs4_delegation *dp,
 				 const struct nfsd4_compound_state *cstate)
@@ -7041,14 +7047,16 @@ nfs4_set_delegation(struct nfsd4_open *open,
 	 *  We choose to offer a write delegation for OPEN with the
 	 *  OPEN4_SHARE_ACCESS_WRITE access mode to accommodate such clients.
 	 */
-	if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) {
+	if ((open->op_share_access & NFS4_SHARE_ACCESS_WRITE) &&
+	    !nfsd4_want_read_deleg(open)) {
 		nf = find_writeable_file(fp);
 		dl_type = deleg_ts ? OPEN_DELEGATE_WRITE_ATTRS_DELEG : OPEN_DELEGATE_WRITE;
 	}
 
 	/*
-	 * If the file is being opened O_RDONLY or we couldn't get a O_RDWR
-	 * file for some reason, then try for a read delegation instead.
+	 * A read delegation can go to a client that holds a write open
+	 * of the file: nfsd_breaker_owns_lease() keeps the holder's own
+	 * opens from breaking it.
 	 */
 	if (!nf && (open->op_share_access & NFS4_SHARE_ACCESS_READ)) {
 		nf = find_readable_file(fp);
@@ -7325,7 +7333,7 @@ nfs4_open_delegation(struct svc_rqst *rqstp, struct nfsd4_open *open,
 
 	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
 
-	if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) {
+	if (deleg_is_write(dp->dl_type)) {
 		struct file *f;
 
 		f = rcu_dereference_protected(dp->dl_stid.sc_file->fi_deleg_file, 1)->nf_file;
@@ -7371,6 +7379,10 @@ static bool open_xor_delegation(struct nfsd4_open *open)
 	/* Did we actually get a delegation? */
 	if (!deleg_is_read(open->op_delegate_type) && !deleg_is_write(open->op_delegate_type))
 		return false;
+	/* A read delegation stateid does not permit WRITE. */
+	if (deleg_is_read(open->op_delegate_type) &&
+	    (open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
+		return false;
 	return true;
 }
 

-- 
2.55.0


      parent reply	other threads:[~2026-10-08 18:18 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-08 18:18 [PATCH 0/5] NFSD: Fixes for OPEN4_SHARE_ACCESS_WANT handling Chuck Lever
2026-10-08 18:18 ` [PATCH 1/5] NFSD: Report WND4_CANCELLED for an OPEN with WANT_CANCEL Chuck Lever
2026-10-08 18:18 ` [PATCH 2/5] NFSD: Report the correct value in an OPEN response's ond_why field Chuck Lever
2026-10-08 18:18 ` [PATCH 3/5] NFSD: Report WND4_CONTENTION for a recently recalled file Chuck Lever
2026-10-08 18:18 ` [PATCH 4/5] NFSD: Report unsupported delegation upgrade and downgrade Chuck Lever
2026-10-08 18:18 ` Chuck Lever [this message]

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=20261008-want-read-v1-5-e372262857c8@kernel.org \
    --to=cel@kernel.org \
    --cc=Dai.Ngo@oracle.com \
    --cc=jlayton@kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neil@brown.name \
    --cc=okorniev@redhat.com \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

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

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