[PATCH v7 11/20] nfsd: apply the notify mask to the delegation when requested

From: Jeff Layton

Date: Tue Jun 16 2026 - 08:05:56 EST


If the client requests a directory delegation with notifications
enabled, set the appropriate return mask in gddr_notification[0]. This
will ensure the lease acquisition sets the appropriate ignore mask.

Also store the granted mask in the delegation's dl_notify_mask field, so
that the CB_NOTIFY encoder can later tell which notifications the client
was granted.

If the client doesn't set NOTIFY4_GFLAG_EXTEND, then don't offer any
notifications, as nfsd won't provide directory offset information, and
"classic" notifications require them.

Similarly, if the client sets GFLAG_EXTEND | CFLAG_ORDER, then zero out
the notification mask. The Linux server can't provide the necessary
ordering info to those clients.

Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
---
fs/nfsd/nfs4proc.c | 21 +++++++++++++++++++++
fs/nfsd/nfs4state.c | 3 ++-
fs/nfsd/state.h | 3 +++
3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 3e4de45aa360..565bf76c08ed 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -2552,12 +2552,18 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return status == nfserr_same ? nfs_ok : status;
}

+#define SUPPORTED_NOTIFY_MASK (BIT(NOTIFY4_REMOVE_ENTRY) | \
+ BIT(NOTIFY4_ADD_ENTRY) | \
+ BIT(NOTIFY4_RENAME_ENTRY) | \
+ BIT(NOTIFY4_GFLAG_EXTEND))
+
static __be32
nfsd4_get_dir_delegation(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
union nfsd4_op_u *u)
{
struct nfsd4_get_dir_delegation *gdd = &u->get_dir_delegation;
+ u32 requested = gdd->gdda_notification_types[0];
struct nfs4_delegation *dd;
struct nfsd_file *nf;
__be32 status;
@@ -2566,6 +2572,21 @@ nfsd4_get_dir_delegation(struct svc_rqst *rqstp,
if (status != nfs_ok)
return status;

+ /*
+ * Offer no notifications to an order-aware client. RFC8881bis section
+ * 16.2.13 defines order-aware as NOTIFY4_CFLAG_ORDER being set or
+ * NOTIFY4_GFLAG_EXTEND being reset. Such a client expects cookie and
+ * previous-entry information with its notifications (e.g. 27.4.5), and
+ * nfsd does not track or emit directory offset information. Per
+ * 16.2.11.3 the alternative would be to recall the delegation, so it's
+ * simpler to just decline the notifications here.
+ */
+ if (!(requested & BIT(NOTIFY4_GFLAG_EXTEND)) ||
+ (requested & BIT(NOTIFY4_CFLAG_ORDER)))
+ requested = 0;
+
+ gdd->gddr_notification[0] = requested & SUPPORTED_NOTIFY_MASK;
+
/*
* RFC 8881, section 18.39.3 says:
*
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 5a4f0843c2fe..682c00fbd2fb 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -10031,7 +10031,8 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstate,
* NB: gddr_notification[0] represents the notifications that
* will be granted to the client
*/
- fl = nfs4_alloc_init_lease(dp, gdd->gddr_notification[0]);
+ dp->dl_notify_mask = gdd->gddr_notification[0];
+ fl = nfs4_alloc_init_lease(dp, dp->dl_notify_mask);
if (!fl)
goto out_put_stid;

diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index f8457e0f2b57..7a66048a130c 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -297,6 +297,9 @@ struct nfs4_delegation {
struct timespec64 dl_atime;
struct timespec64 dl_mtime;
struct timespec64 dl_ctime;
+
+ /* For dir delegations */
+ u32 dl_notify_mask;
};

static inline bool deleg_is_read(u32 dl_type)

--
2.54.0