[PATCH v7 11/20] nfsd: apply the notify mask to the delegation when requested
Jeff Layton <[email protected]>
| Newsgroups | gmane.linux.nfs,gmane.linux.kernel,gmane.linux.documentation |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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