nfsd: apply the notify mask to the delegation when requested

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@kernel.org>
Link: https://patch.msgid.link/20260616-dir-deleg-v7-11-6cbc7eac0ade@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
This commit is contained in:
Jeff Layton 2026-06-16 07:58:54 -04:00 committed by Chuck Lever
parent cb7444b27c
commit 53ba6518a6
3 changed files with 26 additions and 1 deletions

View File

@ -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:
*

View File

@ -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;

View File

@ -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)