From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F0DBA481259; Thu, 11 Jun 2026 17:50:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200235; cv=none; b=p4+R6at/oiufHp51BL6u18EVhIMeOQwWKPxzqdCyVjLAmmYEH2RTiJ9pXxRXCORQGp9praj4nBcWROm9/2zcUPSooq0fVsX+nxca2uh9i9eDjq7JPeYiJ2tcaOzvhne7LbghWt3i9QPBmC46ZeT1GZJci1G7kjBHGue7Bb3cqro= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200235; c=relaxed/simple; bh=grNZpmtqtDrOl1PmFZLq1MU0od9JE2hW7Jg3j0BFn9Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IdnHPxZ10GqXp8hzcgMPQoG9YpZCOgx3hbYtbrM5MZHGxu6i99Y9G90O6qwr/Gr84dLryyShmbS75H9PKNEHxcetMquau2NKIWqLg4Nry8hqLusKaOVqbfwiybP2JM23YB7WNSTmxy9r1O0c2qWWHlO1cyYc87V+dbXYWIzfrsA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KBxH4/DW; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="KBxH4/DW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 313CE1F00899; Thu, 11 Jun 2026 17:50:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200233; bh=Da+Ni315UI6dQ7ZRwAdfmDwUEFlmAVsmtvo5KbaH9So=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=KBxH4/DWNDaCg1Oyrc01RI/w80L192702Iy7injNz+Rk9KRvElRXzA/ANmLeBxodo mFJYVZm6Kvq3cG3r9iL48t+Py4c3Koz3pA0aiH3wqqSWq59FtzbB2blRpejYvAyjSk qJ1v4Qf27vhMu+EcIf5BULLqfH8cHlL6Qupe5nowfIH40VW61Lni7WpVwxog14r8/U X2MmJWQpCPYT3ZycAp6ZFNFf66PJ2jnqDEamrQc2y2jJjHuQs5oXEuyOHB22+Fbt2g pFXXT0sJs6lA4J/kmUWWXen5UPfByfzOcAB1ycBsOh7W0/vCayPIlfPYDG8L3T1N4p /l7unjU6Il+Og== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:07 -0400 Subject: [PATCH v6 01/20] nfsd: check fl_lmops in nfsd_breaker_owns_lease() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-1-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1106; i=jlayton@kernel.org; h=from:subject:message-id; bh=grNZpmtqtDrOl1PmFZLq1MU0od9JE2hW7Jg3j0BFn9Q=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVdYGu7Jdkc6xx3QwrXf6l8NohT7L2yuv+/a ij60//2s9SJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1XQAKCRAADmhBGVaC FfFbD/9RtUHEy5xl74cWNpiAO7z9Ehwib7RvM2PECsj/ehgy8XvAxRs4lGcmIXodwcbNv8Q5c67 MBf5u8uZDxICfrYPEyl0YyxSss7wWPL1Rge1klQQFq9Q5CH0nui8ZFFZCvSBr+6ATy3gnjLKNo9 3JeLOxHU6vbisWPfSVhcgCpOnVyWGJMB2G0QV+8x0tMqun0SUz4hYz+tlnGCKsMFKBuKxwZPxwB fFhHqcIjjaEKKSDTWa5MDbQVKZ675LPnFlQWMMQXdlH1MP4/f85EtK0l6hKx5PJjhWGmCWhJr03 kR/HVYKG+RzFHYHMsE5h87Zpv3BRmkVkqcoBls4e8abTOz3YA5u0u8vJpu99rVwU0kjI+bEcrMG 6Mq2rL9v4QhkyEBDdnMENqNshZaToKFZ2R+IYI4qi8cAlkDJB37RiUQHPkCUk1QmzBBdk/YanTa 69qKVrGo6suzcDU/HMZ6PfBatAVkjtwmucR3dHbHUSo+znLtR3bVRgtUlTn50BbEjM+MDAoIMQ+ 5JH6hzH14cqLmRJvPXbNBqHhwVKdmEOQ0Xmi+rqo/MmmmHMTKGbiQrypBhMUMyPZSHg7eiT8mRi OHLfEWQg1Fhefizw+hHD9yCNp7R9ovuop6z6XRPTuutUOPrkAa6hl72zX4J7DJA4/C8ercVecwh 36JYqobWYsxrvHA== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Any lease created by nfsd will have its fl_lmops set to nfsd_lease_mng_ops. Do a quick check for that first when testing whether the lease breaker owns the lease. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4state.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e59aec57e9e8..489558bf124c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -91,6 +91,8 @@ static void _free_cpntf_state_locked(struct nfsd_net *nn,= struct nfs4_cpntf_stat static void nfsd4_file_hash_remove(struct nfs4_file *fi); static void deleg_reaper(struct nfsd_net *nn); =20 +static const struct lease_manager_operations nfsd_lease_mng_ops; + /* Locking: */ =20 enum nfsd4_st_mutex_lock_subclass { @@ -5734,6 +5736,10 @@ static bool nfsd_breaker_owns_lease(struct file_leas= e *fl) struct svc_rqst *rqst; struct nfs4_client *clp; =20 + /* Only nfsd leases */ + if (fl->fl_lmops !=3D &nfsd_lease_mng_ops) + return false; + rqst =3D nfsd_current_rqst(); if (!nfsd_v4client(rqst)) return false; --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2DDE749553C; Thu, 11 Jun 2026 17:50:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200238; cv=none; b=IRcRzpl+w3yGH8CGFqX/el9admScj0KLRzKnxCPkYdpvNHMh59Q5UqKBgHWf8xgWaEjPrScCTEfqvjtJUFl0CKsImKO85SyRrm9Jcx0kHcjftV9KcEDpB8TZ4iNNgLbG+Yv7wrYRWS7m8yv8GFGcTgXPEsAjvTV0L3R0Uf+30zY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200238; c=relaxed/simple; bh=NYix9P5qUSyNYOcngF6Z04j/Yxh+wWpRdMLk31xUwm8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=duOUpUx8MTFnjTnLkocZkSIISU+D29K/knzZsN0aFODELKlJf8piJsBPkht28HF9SVSQOUnAH/22tjl6WNhWm80nJ+vKnVOMlhjJgXc2xlV2UjibMcyOMgBif4jABCuUmsptp11Z+yJHLU650Fl6beyEM5r+WSosvyTv90clvkE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=noOiz353; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="noOiz353" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 184F01F00893; Thu, 11 Jun 2026 17:50:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200235; bh=+eybaZPlYTohd+UsE6RghCyPQdmAv3sghXxLizXuygI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=noOiz353CDtPLoYwiqywXTTNM0rVjJnFwt0c2XKsoV7l9Jz3MUxMnrOKI+CuSHHx7 3gWrwQFZ0abcDsCXYh7WQ4SlbSuMfo/XBZwXU/PoVqP61I1UPN6uyfcThVr5Z0D5rP RUI2wxXCHmNFHUdPIX+Eyq6zzfXLwmpemwnMVcLPO0Ew3htMg7a2f7L7YRy96xYizw AjnSRF90V+E5LFVQMjH3tr7tn/qBdKsNxrk3pYNA1EGZgNdB4mfQUSNi6uZ6WPkGbM oO8t4AXIffLmyzY/s/z1vxjvR8+jLs5dBjt+1g85rSsht+gWs9W1lzdiuydDeTA8iW ueivnOV3QWMdQ== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:08 -0400 Subject: [PATCH v6 02/20] nfsd: add protocol support for CB_NOTIFY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-2-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=49615; i=jlayton@kernel.org; h=from:subject:message-id; bh=NYix9P5qUSyNYOcngF6Z04j/Yxh+wWpRdMLk31xUwm8=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVeJUArFs4UYX87/IuKuDo2jxi7TSdCIU7c3 9q/LfmMzoyJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1XgAKCRAADmhBGVaC FUZ/EACUk4J34Ay9VXJHkObIYG4QmHw5dcPV5AmVQh+lNkgZF+lnULc0njOt78neREpk830brbG 7gmzBG9jR0BumQhBHStSUnLjhWIg57CKI/KtVmwZeJSXQxUZwq/RvOnA1N7mlSe6BKMwWZlzVis jrFnCDKHHQXpMBs52uTdV3IW5u5veILxOAPNtc99T5pu4ClnNG4AOMJ3ehWBg9LVnONiJHeZqIk BqM8IuWA8d3KOzXuHRN5hAA0BYG+T907KS8ZcxOZzHZQtBAhSrjOjV2f+sZt44XFjKLgoO0mD6I 0SIbQpA/sZ3Yd9KsMhkd49q/d5SQrc18gxKEcNA99V560AbZMn4DTNwCIY02nCX41F8maYfSwyq uSTJ/I+5PPyN1s/P234EsvsIwTV6fsoHIL5NqzOaG1CRbqlZJKRo+4av7HStHSlSiHat1rkhOwp /2IiEpZsAXlHluAKSytgCd9/MoUzdQ562Sa6lGUj/8zJohrlooCrZ6lqA5VTwJs8ZAol3PJ0hPb nEUmX+4SHHz2DAMPLJO9w6qyLDI8ImjUKw7dCWWLvRPp4fu2Xx0Qv+HZ7Pevx43av3Ib+drkbLx mB3RXRVtTt70ZL+0tkZmXmpksN3VA1NFPjwKdMPTwPFRW9QDYA0PUct0AAhU3fXfsM1T2hHj+UT dQKdtkLS6IFnA6A== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Add the necessary bits to nfs4_1.x and remove the duplicate definitions from nfs4.h and the uapi nfs4 header. Regenerate the xdr files. Note that regenerating these files caused conflicts with the definitions of NFS4_VERIFIER_SIZE and NFS4_FHSIZE in include/uapi/linux/nfs4.h. These constants are defined by the RFC, and are not part of the kernel API. They have been removed. Userspace consumers who require those constants should plan to get them from more authoritative sources. Signed-off-by: Jeff Layton --- Documentation/sunrpc/xdr/nfs4_1.x | 250 ++++++++++++++- fs/nfsd/nfs4xdr_gen.c | 590 +++++++++++++++++++++++++++++++= +++- fs/nfsd/nfs4xdr_gen.h | 20 +- fs/nfsd/trace.h | 1 + include/linux/nfs4.h | 127 -------- include/linux/sunrpc/xdrgen/nfs4_1.h | 280 ++++++++++++++++- include/uapi/linux/nfs4.h | 2 - 7 files changed, 1129 insertions(+), 141 deletions(-) diff --git a/Documentation/sunrpc/xdr/nfs4_1.x b/Documentation/sunrpc/xdr/n= fs4_1.x index 5b45547b2ebc..632f5b579c39 100644 --- a/Documentation/sunrpc/xdr/nfs4_1.x +++ b/Documentation/sunrpc/xdr/nfs4_1.x @@ -45,19 +45,165 @@ pragma header nfs4; /* * Basic typedefs for RFC 1832 data type definitions */ -typedef hyper int64_t; -typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef hyper int64_t; +typedef unsigned hyper uint64_t; + +const NFS4_VERIFIER_SIZE =3D 8; +const NFS4_FHSIZE =3D 128; + +enum nfsstat4 { + NFS4_OK =3D 0, /* everything is okay */ + NFS4ERR_PERM =3D 1, /* caller not privileged */ + NFS4ERR_NOENT =3D 2, /* no such file/directory */ + NFS4ERR_IO =3D 5, /* hard I/O error */ + NFS4ERR_NXIO =3D 6, /* no such device */ + NFS4ERR_ACCESS =3D 13, /* access denied */ + NFS4ERR_EXIST =3D 17, /* file already exists */ + NFS4ERR_XDEV =3D 18, /* different filesystems */ + + /* + * Please do not allocate value 19; it was used in NFSv3 + * and we do not want a value in NFSv3 to have a different + * meaning in NFSv4.x. + */ + + NFS4ERR_NOTDIR =3D 20, /* should be a directory */ + NFS4ERR_ISDIR =3D 21, /* should not be directory */ + NFS4ERR_INVAL =3D 22, /* invalid argument */ + NFS4ERR_FBIG =3D 27, /* file exceeds server max */ + NFS4ERR_NOSPC =3D 28, /* no space on filesystem */ + NFS4ERR_ROFS =3D 30, /* read-only filesystem */ + NFS4ERR_MLINK =3D 31, /* too many hard links */ + NFS4ERR_NAMETOOLONG =3D 63, /* name exceeds server max */ + NFS4ERR_NOTEMPTY =3D 66, /* directory not empty */ + NFS4ERR_DQUOT =3D 69, /* hard quota limit reached*/ + NFS4ERR_STALE =3D 70, /* file no longer exists */ + NFS4ERR_BADHANDLE =3D 10001,/* Illegal filehandle */ + NFS4ERR_BAD_COOKIE =3D 10003,/* READDIR cookie is stale */ + NFS4ERR_NOTSUPP =3D 10004,/* operation not supported */ + NFS4ERR_TOOSMALL =3D 10005,/* response limit exceeded */ + NFS4ERR_SERVERFAULT =3D 10006,/* undefined server error */ + NFS4ERR_BADTYPE =3D 10007,/* type invalid for CREATE */ + NFS4ERR_DELAY =3D 10008,/* file "busy" - retry */ + NFS4ERR_SAME =3D 10009,/* nverify says attrs same */ + NFS4ERR_DENIED =3D 10010,/* lock unavailable */ + NFS4ERR_EXPIRED =3D 10011,/* lock lease expired */ + NFS4ERR_LOCKED =3D 10012,/* I/O failed due to lock */ + NFS4ERR_GRACE =3D 10013,/* in grace period */ + NFS4ERR_FHEXPIRED =3D 10014,/* filehandle expired */ + NFS4ERR_SHARE_DENIED =3D 10015,/* share reserve denied */ + NFS4ERR_WRONGSEC =3D 10016,/* wrong security flavor */ + NFS4ERR_CLID_INUSE =3D 10017,/* clientid in use */ + + /* NFS4ERR_RESOURCE is not a valid error in NFSv4.1 */ + NFS4ERR_RESOURCE =3D 10018,/* resource exhaustion */ + + NFS4ERR_MOVED =3D 10019,/* filesystem relocated */ + NFS4ERR_NOFILEHANDLE =3D 10020,/* current FH is not set */ + NFS4ERR_MINOR_VERS_MISMATCH=3D 10021,/* minor vers not supp */ + NFS4ERR_STALE_CLIENTID =3D 10022,/* server has rebooted */ + NFS4ERR_STALE_STATEID =3D 10023,/* server has rebooted */ + NFS4ERR_OLD_STATEID =3D 10024,/* state is out of sync */ + NFS4ERR_BAD_STATEID =3D 10025,/* incorrect stateid */ + NFS4ERR_BAD_SEQID =3D 10026,/* request is out of seq. */ + NFS4ERR_NOT_SAME =3D 10027,/* verify - attrs not same */ + NFS4ERR_LOCK_RANGE =3D 10028,/* overlapping lock range */ + NFS4ERR_SYMLINK =3D 10029,/* should be file/directory*/ + NFS4ERR_RESTOREFH =3D 10030,/* no saved filehandle */ + NFS4ERR_LEASE_MOVED =3D 10031,/* some filesystem moved */ + NFS4ERR_ATTRNOTSUPP =3D 10032,/* recommended attr not sup*/ + NFS4ERR_NO_GRACE =3D 10033,/* reclaim outside of grace*/ + NFS4ERR_RECLAIM_BAD =3D 10034,/* reclaim error at server */ + NFS4ERR_RECLAIM_CONFLICT=3D 10035,/* conflict on reclaim */ + NFS4ERR_BADXDR =3D 10036,/* XDR decode failed */ + NFS4ERR_LOCKS_HELD =3D 10037,/* file locks held at CLOSE*/ + NFS4ERR_OPENMODE =3D 10038,/* conflict in OPEN and I/O*/ + NFS4ERR_BADOWNER =3D 10039,/* owner translation bad */ + NFS4ERR_BADCHAR =3D 10040,/* utf-8 char not supported*/ + NFS4ERR_BADNAME =3D 10041,/* name not supported */ + NFS4ERR_BAD_RANGE =3D 10042,/* lock range not supported*/ + NFS4ERR_LOCK_NOTSUPP =3D 10043,/* no atomic up/downgrade */ + NFS4ERR_OP_ILLEGAL =3D 10044,/* undefined operation */ + NFS4ERR_DEADLOCK =3D 10045,/* file locking deadlock */ + NFS4ERR_FILE_OPEN =3D 10046,/* open file blocks op. */ + NFS4ERR_ADMIN_REVOKED =3D 10047,/* lockowner state revoked */ + NFS4ERR_CB_PATH_DOWN =3D 10048,/* callback path down */ + + /* NFSv4.1 errors start here. */ + + NFS4ERR_BADIOMODE =3D 10049, + NFS4ERR_BADLAYOUT =3D 10050, + NFS4ERR_BAD_SESSION_DIGEST =3D 10051, + NFS4ERR_BADSESSION =3D 10052, + NFS4ERR_BADSLOT =3D 10053, + NFS4ERR_COMPLETE_ALREADY =3D 10054, + NFS4ERR_CONN_NOT_BOUND_TO_SESSION =3D 10055, + NFS4ERR_DELEG_ALREADY_WANTED =3D 10056, + NFS4ERR_BACK_CHAN_BUSY =3D 10057,/*backchan reqs outstanding*/ + NFS4ERR_LAYOUTTRYLATER =3D 10058, + NFS4ERR_LAYOUTUNAVAILABLE =3D 10059, + NFS4ERR_NOMATCHING_LAYOUT =3D 10060, + NFS4ERR_RECALLCONFLICT =3D 10061, + NFS4ERR_UNKNOWN_LAYOUTTYPE =3D 10062, + NFS4ERR_SEQ_MISORDERED =3D 10063,/* unexpected seq.ID in req*/ + NFS4ERR_SEQUENCE_POS =3D 10064,/* [CB_]SEQ. op not 1st op */ + NFS4ERR_REQ_TOO_BIG =3D 10065,/* request too big */ + NFS4ERR_REP_TOO_BIG =3D 10066,/* reply too big */ + NFS4ERR_REP_TOO_BIG_TO_CACHE =3D10067,/* rep. not all cached*/ + NFS4ERR_RETRY_UNCACHED_REP =3D10068,/* retry & rep. uncached*/ + NFS4ERR_UNSAFE_COMPOUND =3D10069,/* retry/recovery too hard */ + NFS4ERR_TOO_MANY_OPS =3D 10070,/*too many ops in [CB_]COMP*/ + NFS4ERR_OP_NOT_IN_SESSION =3D10071,/* op needs [CB_]SEQ. op */ + NFS4ERR_HASH_ALG_UNSUPP =3D 10072, /* hash alg. not supp. */ + /* Error 10073 is unused. */ + NFS4ERR_CLIENTID_BUSY =3D 10074,/* clientid has state */ + NFS4ERR_PNFS_IO_HOLE =3D 10075,/* IO to _SPARSE file hole */ + NFS4ERR_SEQ_FALSE_RETRY=3D 10076,/* Retry !=3D original req. */ + NFS4ERR_BAD_HIGH_SLOT =3D 10077,/* req has bad highest_slot*/ + NFS4ERR_DEADSESSION =3D 10078,/*new req sent to dead sess*/ + NFS4ERR_ENCR_ALG_UNSUPP=3D 10079,/* encr alg. not supp. */ + NFS4ERR_PNFS_NO_LAYOUT =3D 10080,/* I/O without a layout */ + NFS4ERR_NOT_ONLY_OP =3D 10081,/* addl ops not allowed */ + NFS4ERR_WRONG_CRED =3D 10082,/* op done by wrong cred */ + NFS4ERR_WRONG_TYPE =3D 10083,/* op on wrong type object */ + NFS4ERR_DIRDELEG_UNAVAIL=3D10084,/* delegation not avail. */ + NFS4ERR_REJECT_DELEG =3D 10085,/* cb rejected delegation */ + NFS4ERR_RETURNCONFLICT =3D 10086,/* layout get before return*/ + NFS4ERR_DELEG_REVOKED =3D 10087, /* deleg./layout revoked */ + NFS4ERR_PARTNER_NOTSUPP =3D 10088, + NFS4ERR_PARTNER_NO_AUTH =3D 10089, + NFS4ERR_UNION_NOTSUPP =3D 10090, + NFS4ERR_OFFLOAD_DENIED =3D 10091, + NFS4ERR_WRONG_LFS =3D 10092, + NFS4ERR_BADLABEL =3D 10093, + NFS4ERR_OFFLOAD_NO_REQS =3D 10094, + NFS4ERR_NOXATTR =3D 10095, + NFS4ERR_XATTR2BIG =3D 10096, + + /* always set this to one more than the last one in the enum */ + NFS4ERR_FIRST_FREE =3D 10097 +}; =20 /* * Basic data types */ +typedef opaque attrlist4<>; typedef uint32_t bitmap4<>; +typedef opaque verifier4[NFS4_VERIFIER_SIZE]; +typedef uint64_t nfs_cookie4; +typedef opaque nfs_fh4; =20 typedef opaque utf8string<>; typedef utf8string utf8str_cis; typedef utf8string utf8str_cs; typedef utf8string utf8str_mixed; =20 +typedef utf8str_cs component4; +typedef utf8str_cs linktext4; +typedef component4 pathname4<>; + /* * Timeval */ @@ -66,6 +212,21 @@ struct nfstime4 { uint32_t nseconds; }; =20 +/* + * File attribute container + */ +struct fattr4 { + bitmap4 attrmask; + attrlist4 attr_vals; +}; + +/* + * Stateid + */ +struct stateid4 { + uint32_t seqid; + opaque other[12]; +}; =20 /* * The following content was extracted from draft-ietf-nfsv4-delstid @@ -245,3 +406,88 @@ const FATTR4_ACL_TRUEFORM =3D 89; const FATTR4_ACL_TRUEFORM_SCOPE =3D 90; const FATTR4_POSIX_DEFAULT_ACL =3D 91; const FATTR4_POSIX_ACCESS_ACL =3D 92; + +/* + * Directory notification types. + */ +enum notify_type4 { + NOTIFY4_CHANGE_CHILD_ATTRS =3D 0, + NOTIFY4_CHANGE_DIR_ATTRS =3D 1, + NOTIFY4_REMOVE_ENTRY =3D 2, + NOTIFY4_ADD_ENTRY =3D 3, + NOTIFY4_RENAME_ENTRY =3D 4, + NOTIFY4_CHANGE_COOKIE_VERIFIER =3D 5 +}; + +/* Changed entry information. */ +struct notify_entry4 { + component4 ne_file; + fattr4 ne_attrs; +}; + +/* Previous entry information */ +struct prev_entry4 { + notify_entry4 pe_prev_entry; + /* what READDIR returned for this entry */ + nfs_cookie4 pe_prev_entry_cookie; +}; + +struct notify_remove4 { + notify_entry4 nrm_old_entry; + nfs_cookie4 nrm_old_entry_cookie; +}; +pragma public notify_remove4; + +struct notify_add4 { + /* + * Information on object + * possibly renamed over. + */ + notify_remove4 nad_old_entry<1>; + notify_entry4 nad_new_entry; + /* what READDIR would have returned for this entry */ + nfs_cookie4 nad_new_entry_cookie<1>; + prev_entry4 nad_prev_entry<1>; + bool nad_last_entry; +}; +pragma public notify_add4; + +struct notify_attr4 { + notify_entry4 na_changed_entry; +}; +pragma public notify_attr4; + +struct notify_rename4 { + notify_remove4 nrn_old_entry; + notify_add4 nrn_new_entry; +}; +pragma public notify_rename4; + +struct notify_verifier4 { + verifier4 nv_old_cookieverf; + verifier4 nv_new_cookieverf; +}; + +/* + * Objects of type notify_<>4 and + * notify_device_<>4 are encoded in this. + */ +typedef opaque notifylist4<>; + +struct notify4 { + /* composed from notify_type4 or notify_deviceid_type4 */ + bitmap4 notify_mask; + notifylist4 notify_vals; +}; + +struct CB_NOTIFY4args { + stateid4 cna_stateid; + nfs_fh4 cna_fh; + notify4 cna_changes<>; +}; +pragma public CB_NOTIFY4args; + +struct CB_NOTIFY4res { + nfsstat4 cnr_status; +}; +pragma public CB_NOTIFY4res; diff --git a/fs/nfsd/nfs4xdr_gen.c b/fs/nfsd/nfs4xdr_gen.c index 824497051b87..5e656d6bbb8e 100644 --- a/fs/nfsd/nfs4xdr_gen.c +++ b/fs/nfsd/nfs4xdr_gen.c @@ -1,16 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 // Generated by xdrgen. Manual edits will be lost. // XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x -// XDR specification modification time: Thu Jan 8 23:12:07 2026 +// XDR specification modification time: Wed Mar 25 11:39:22 2026 =20 #include =20 #include "nfs4xdr_gen.h" =20 static bool __maybe_unused -xdrgen_decode_int64_t(struct xdr_stream *xdr, int64_t *ptr) +xdrgen_decode_int32_t(struct xdr_stream *xdr, int32_t *ptr) { - return xdrgen_decode_hyper(xdr, ptr); + return xdrgen_decode_int(xdr, ptr); } =20 static bool __maybe_unused @@ -19,6 +19,155 @@ xdrgen_decode_uint32_t(struct xdr_stream *xdr, uint32_t= *ptr) return xdrgen_decode_unsigned_int(xdr, ptr); } =20 +static bool __maybe_unused +xdrgen_decode_int64_t(struct xdr_stream *xdr, int64_t *ptr) +{ + return xdrgen_decode_hyper(xdr, ptr); +} + +static bool __maybe_unused +xdrgen_decode_uint64_t(struct xdr_stream *xdr, uint64_t *ptr) +{ + return xdrgen_decode_unsigned_hyper(xdr, ptr); +} + +static bool __maybe_unused +xdrgen_decode_nfsstat4(struct xdr_stream *xdr, nfsstat4 *ptr) +{ + u32 val; + + if (xdr_stream_decode_u32(xdr, &val) < 0) + return false; + /* Compiler may optimize to a range check for dense enums */ + switch (val) { + case NFS4_OK: + case NFS4ERR_PERM: + case NFS4ERR_NOENT: + case NFS4ERR_IO: + case NFS4ERR_NXIO: + case NFS4ERR_ACCESS: + case NFS4ERR_EXIST: + case NFS4ERR_XDEV: + case NFS4ERR_NOTDIR: + case NFS4ERR_ISDIR: + case NFS4ERR_INVAL: + case NFS4ERR_FBIG: + case NFS4ERR_NOSPC: + case NFS4ERR_ROFS: + case NFS4ERR_MLINK: + case NFS4ERR_NAMETOOLONG: + case NFS4ERR_NOTEMPTY: + case NFS4ERR_DQUOT: + case NFS4ERR_STALE: + case NFS4ERR_BADHANDLE: + case NFS4ERR_BAD_COOKIE: + case NFS4ERR_NOTSUPP: + case NFS4ERR_TOOSMALL: + case NFS4ERR_SERVERFAULT: + case NFS4ERR_BADTYPE: + case NFS4ERR_DELAY: + case NFS4ERR_SAME: + case NFS4ERR_DENIED: + case NFS4ERR_EXPIRED: + case NFS4ERR_LOCKED: + case NFS4ERR_GRACE: + case NFS4ERR_FHEXPIRED: + case NFS4ERR_SHARE_DENIED: + case NFS4ERR_WRONGSEC: + case NFS4ERR_CLID_INUSE: + case NFS4ERR_RESOURCE: + case NFS4ERR_MOVED: + case NFS4ERR_NOFILEHANDLE: + case NFS4ERR_MINOR_VERS_MISMATCH: + case NFS4ERR_STALE_CLIENTID: + case NFS4ERR_STALE_STATEID: + case NFS4ERR_OLD_STATEID: + case NFS4ERR_BAD_STATEID: + case NFS4ERR_BAD_SEQID: + case NFS4ERR_NOT_SAME: + case NFS4ERR_LOCK_RANGE: + case NFS4ERR_SYMLINK: + case NFS4ERR_RESTOREFH: + case NFS4ERR_LEASE_MOVED: + case NFS4ERR_ATTRNOTSUPP: + case NFS4ERR_NO_GRACE: + case NFS4ERR_RECLAIM_BAD: + case NFS4ERR_RECLAIM_CONFLICT: + case NFS4ERR_BADXDR: + case NFS4ERR_LOCKS_HELD: + case NFS4ERR_OPENMODE: + case NFS4ERR_BADOWNER: + case NFS4ERR_BADCHAR: + case NFS4ERR_BADNAME: + case NFS4ERR_BAD_RANGE: + case NFS4ERR_LOCK_NOTSUPP: + case NFS4ERR_OP_ILLEGAL: + case NFS4ERR_DEADLOCK: + case NFS4ERR_FILE_OPEN: + case NFS4ERR_ADMIN_REVOKED: + case NFS4ERR_CB_PATH_DOWN: + case NFS4ERR_BADIOMODE: + case NFS4ERR_BADLAYOUT: + case NFS4ERR_BAD_SESSION_DIGEST: + case NFS4ERR_BADSESSION: + case NFS4ERR_BADSLOT: + case NFS4ERR_COMPLETE_ALREADY: + case NFS4ERR_CONN_NOT_BOUND_TO_SESSION: + case NFS4ERR_DELEG_ALREADY_WANTED: + case NFS4ERR_BACK_CHAN_BUSY: + case NFS4ERR_LAYOUTTRYLATER: + case NFS4ERR_LAYOUTUNAVAILABLE: + case NFS4ERR_NOMATCHING_LAYOUT: + case NFS4ERR_RECALLCONFLICT: + case NFS4ERR_UNKNOWN_LAYOUTTYPE: + case NFS4ERR_SEQ_MISORDERED: + case NFS4ERR_SEQUENCE_POS: + case NFS4ERR_REQ_TOO_BIG: + case NFS4ERR_REP_TOO_BIG: + case NFS4ERR_REP_TOO_BIG_TO_CACHE: + case NFS4ERR_RETRY_UNCACHED_REP: + case NFS4ERR_UNSAFE_COMPOUND: + case NFS4ERR_TOO_MANY_OPS: + case NFS4ERR_OP_NOT_IN_SESSION: + case NFS4ERR_HASH_ALG_UNSUPP: + case NFS4ERR_CLIENTID_BUSY: + case NFS4ERR_PNFS_IO_HOLE: + case NFS4ERR_SEQ_FALSE_RETRY: + case NFS4ERR_BAD_HIGH_SLOT: + case NFS4ERR_DEADSESSION: + case NFS4ERR_ENCR_ALG_UNSUPP: + case NFS4ERR_PNFS_NO_LAYOUT: + case NFS4ERR_NOT_ONLY_OP: + case NFS4ERR_WRONG_CRED: + case NFS4ERR_WRONG_TYPE: + case NFS4ERR_DIRDELEG_UNAVAIL: + case NFS4ERR_REJECT_DELEG: + case NFS4ERR_RETURNCONFLICT: + case NFS4ERR_DELEG_REVOKED: + case NFS4ERR_PARTNER_NOTSUPP: + case NFS4ERR_PARTNER_NO_AUTH: + case NFS4ERR_UNION_NOTSUPP: + case NFS4ERR_OFFLOAD_DENIED: + case NFS4ERR_WRONG_LFS: + case NFS4ERR_BADLABEL: + case NFS4ERR_OFFLOAD_NO_REQS: + case NFS4ERR_NOXATTR: + case NFS4ERR_XATTR2BIG: + case NFS4ERR_FIRST_FREE: + break; + default: + return false; + } + *ptr =3D val; + return true; +} + +static bool __maybe_unused +xdrgen_decode_attrlist4(struct xdr_stream *xdr, attrlist4 *ptr) +{ + return xdrgen_decode_opaque(xdr, ptr, 0); +} + static bool __maybe_unused xdrgen_decode_bitmap4(struct xdr_stream *xdr, bitmap4 *ptr) { @@ -30,6 +179,24 @@ xdrgen_decode_bitmap4(struct xdr_stream *xdr, bitmap4 *= ptr) return true; } =20 +static bool __maybe_unused +xdrgen_decode_verifier4(struct xdr_stream *xdr, verifier4 *ptr) +{ + return xdr_stream_decode_opaque_fixed(xdr, ptr, NFS4_VERIFIER_SIZE) =3D= =3D 0; +} + +static bool __maybe_unused +xdrgen_decode_nfs_cookie4(struct xdr_stream *xdr, nfs_cookie4 *ptr) +{ + return xdrgen_decode_uint64_t(xdr, ptr); +} + +static bool __maybe_unused +xdrgen_decode_nfs_fh4(struct xdr_stream *xdr, nfs_fh4 *ptr) +{ + return xdrgen_decode_opaque(xdr, ptr, NFS4_FHSIZE); +} + static bool __maybe_unused xdrgen_decode_utf8string(struct xdr_stream *xdr, utf8string *ptr) { @@ -54,6 +221,29 @@ xdrgen_decode_utf8str_mixed(struct xdr_stream *xdr, utf= 8str_mixed *ptr) return xdrgen_decode_utf8string(xdr, ptr); } =20 +static bool __maybe_unused +xdrgen_decode_component4(struct xdr_stream *xdr, component4 *ptr) +{ + return xdrgen_decode_utf8str_cs(xdr, ptr); +} + +static bool __maybe_unused +xdrgen_decode_linktext4(struct xdr_stream *xdr, linktext4 *ptr) +{ + return xdrgen_decode_utf8str_cs(xdr, ptr); +} + +static bool __maybe_unused +xdrgen_decode_pathname4(struct xdr_stream *xdr, pathname4 *ptr) +{ + if (xdr_stream_decode_u32(xdr, &ptr->count) < 0) + return false; + for (u32 i =3D 0; i < ptr->count; i++) + if (!xdrgen_decode_component4(xdr, &ptr->element[i])) + return false; + return true; +} + static bool __maybe_unused xdrgen_decode_nfstime4(struct xdr_stream *xdr, struct nfstime4 *ptr) { @@ -64,6 +254,26 @@ xdrgen_decode_nfstime4(struct xdr_stream *xdr, struct n= fstime4 *ptr) return true; } =20 +static bool __maybe_unused +xdrgen_decode_fattr4(struct xdr_stream *xdr, struct fattr4 *ptr) +{ + if (!xdrgen_decode_bitmap4(xdr, &ptr->attrmask)) + return false; + if (!xdrgen_decode_attrlist4(xdr, &ptr->attr_vals)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_stateid4(struct xdr_stream *xdr, struct stateid4 *ptr) +{ + if (!xdrgen_decode_uint32_t(xdr, &ptr->seqid)) + return false; + if (xdr_stream_decode_opaque_fixed(xdr, ptr->other, 12) < 0) + return false; + return true; +} + static bool __maybe_unused xdrgen_decode_fattr4_offline(struct xdr_stream *xdr, fattr4_offline *ptr) { @@ -366,9 +576,160 @@ xdrgen_decode_fattr4_posix_access_acl(struct xdr_stre= am *xdr, fattr4_posix_acces */ =20 static bool __maybe_unused -xdrgen_encode_int64_t(struct xdr_stream *xdr, const int64_t value) +xdrgen_decode_notify_type4(struct xdr_stream *xdr, notify_type4 *ptr) { - return xdrgen_encode_hyper(xdr, value); + u32 val; + + if (xdr_stream_decode_u32(xdr, &val) < 0) + return false; + /* Compiler may optimize to a range check for dense enums */ + switch (val) { + case NOTIFY4_CHANGE_CHILD_ATTRS: + case NOTIFY4_CHANGE_DIR_ATTRS: + case NOTIFY4_REMOVE_ENTRY: + case NOTIFY4_ADD_ENTRY: + case NOTIFY4_RENAME_ENTRY: + case NOTIFY4_CHANGE_COOKIE_VERIFIER: + break; + default: + return false; + } + *ptr =3D val; + return true; +} + +static bool __maybe_unused +xdrgen_decode_notify_entry4(struct xdr_stream *xdr, struct notify_entry4 *= ptr) +{ + if (!xdrgen_decode_component4(xdr, &ptr->ne_file)) + return false; + if (!xdrgen_decode_fattr4(xdr, &ptr->ne_attrs)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_prev_entry4(struct xdr_stream *xdr, struct prev_entry4 *ptr) +{ + if (!xdrgen_decode_notify_entry4(xdr, &ptr->pe_prev_entry)) + return false; + if (!xdrgen_decode_nfs_cookie4(xdr, &ptr->pe_prev_entry_cookie)) + return false; + return true; +} + +bool +xdrgen_decode_notify_remove4(struct xdr_stream *xdr, struct notify_remove4= *ptr) +{ + if (!xdrgen_decode_notify_entry4(xdr, &ptr->nrm_old_entry)) + return false; + if (!xdrgen_decode_nfs_cookie4(xdr, &ptr->nrm_old_entry_cookie)) + return false; + return true; +} + +bool +xdrgen_decode_notify_add4(struct xdr_stream *xdr, struct notify_add4 *ptr) +{ + if (xdr_stream_decode_u32(xdr, &ptr->nad_old_entry.count) < 0) + return false; + if (ptr->nad_old_entry.count > 1) + return false; + for (u32 i =3D 0; i < ptr->nad_old_entry.count; i++) + if (!xdrgen_decode_notify_remove4(xdr, &ptr->nad_old_entry.element[i])) + return false; + if (!xdrgen_decode_notify_entry4(xdr, &ptr->nad_new_entry)) + return false; + if (xdr_stream_decode_u32(xdr, &ptr->nad_new_entry_cookie.count) < 0) + return false; + if (ptr->nad_new_entry_cookie.count > 1) + return false; + for (u32 i =3D 0; i < ptr->nad_new_entry_cookie.count; i++) + if (!xdrgen_decode_nfs_cookie4(xdr, &ptr->nad_new_entry_cookie.element[i= ])) + return false; + if (xdr_stream_decode_u32(xdr, &ptr->nad_prev_entry.count) < 0) + return false; + if (ptr->nad_prev_entry.count > 1) + return false; + for (u32 i =3D 0; i < ptr->nad_prev_entry.count; i++) + if (!xdrgen_decode_prev_entry4(xdr, &ptr->nad_prev_entry.element[i])) + return false; + if (!xdrgen_decode_bool(xdr, &ptr->nad_last_entry)) + return false; + return true; +} + +bool +xdrgen_decode_notify_attr4(struct xdr_stream *xdr, struct notify_attr4 *pt= r) +{ + if (!xdrgen_decode_notify_entry4(xdr, &ptr->na_changed_entry)) + return false; + return true; +} + +bool +xdrgen_decode_notify_rename4(struct xdr_stream *xdr, struct notify_rename4= *ptr) +{ + if (!xdrgen_decode_notify_remove4(xdr, &ptr->nrn_old_entry)) + return false; + if (!xdrgen_decode_notify_add4(xdr, &ptr->nrn_new_entry)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_notify_verifier4(struct xdr_stream *xdr, struct notify_verif= ier4 *ptr) +{ + if (!xdrgen_decode_verifier4(xdr, &ptr->nv_old_cookieverf)) + return false; + if (!xdrgen_decode_verifier4(xdr, &ptr->nv_new_cookieverf)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_notifylist4(struct xdr_stream *xdr, notifylist4 *ptr) +{ + return xdrgen_decode_opaque(xdr, ptr, 0); +} + +static bool __maybe_unused +xdrgen_decode_notify4(struct xdr_stream *xdr, struct notify4 *ptr) +{ + if (!xdrgen_decode_bitmap4(xdr, &ptr->notify_mask)) + return false; + if (!xdrgen_decode_notifylist4(xdr, &ptr->notify_vals)) + return false; + return true; +} + +bool +xdrgen_decode_CB_NOTIFY4args(struct xdr_stream *xdr, struct CB_NOTIFY4args= *ptr) +{ + if (!xdrgen_decode_stateid4(xdr, &ptr->cna_stateid)) + return false; + if (!xdrgen_decode_nfs_fh4(xdr, &ptr->cna_fh)) + return false; + if (xdr_stream_decode_u32(xdr, &ptr->cna_changes.count) < 0) + return false; + for (u32 i =3D 0; i < ptr->cna_changes.count; i++) + if (!xdrgen_decode_notify4(xdr, &ptr->cna_changes.element[i])) + return false; + return true; +} + +bool +xdrgen_decode_CB_NOTIFY4res(struct xdr_stream *xdr, struct CB_NOTIFY4res *= ptr) +{ + if (!xdrgen_decode_nfsstat4(xdr, &ptr->cnr_status)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_int32_t(struct xdr_stream *xdr, const int32_t value) +{ + return xdrgen_encode_int(xdr, value); } =20 static bool __maybe_unused @@ -377,6 +738,30 @@ xdrgen_encode_uint32_t(struct xdr_stream *xdr, const u= int32_t value) return xdrgen_encode_unsigned_int(xdr, value); } =20 +static bool __maybe_unused +xdrgen_encode_int64_t(struct xdr_stream *xdr, const int64_t value) +{ + return xdrgen_encode_hyper(xdr, value); +} + +static bool __maybe_unused +xdrgen_encode_uint64_t(struct xdr_stream *xdr, const uint64_t value) +{ + return xdrgen_encode_unsigned_hyper(xdr, value); +} + +static bool __maybe_unused +xdrgen_encode_nfsstat4(struct xdr_stream *xdr, nfsstat4 value) +{ + return xdr_stream_encode_u32(xdr, value) =3D=3D XDR_UNIT; +} + +static bool __maybe_unused +xdrgen_encode_attrlist4(struct xdr_stream *xdr, const attrlist4 value) +{ + return xdr_stream_encode_opaque(xdr, value.data, value.len) >=3D 0; +} + static bool __maybe_unused xdrgen_encode_bitmap4(struct xdr_stream *xdr, const bitmap4 value) { @@ -388,6 +773,24 @@ xdrgen_encode_bitmap4(struct xdr_stream *xdr, const bi= tmap4 value) return true; } =20 +static bool __maybe_unused +xdrgen_encode_verifier4(struct xdr_stream *xdr, const verifier4 value) +{ + return xdr_stream_encode_opaque_fixed(xdr, value, NFS4_VERIFIER_SIZE) >= =3D 0; +} + +static bool __maybe_unused +xdrgen_encode_nfs_cookie4(struct xdr_stream *xdr, const nfs_cookie4 value) +{ + return xdrgen_encode_uint64_t(xdr, value); +} + +static bool __maybe_unused +xdrgen_encode_nfs_fh4(struct xdr_stream *xdr, const nfs_fh4 value) +{ + return xdr_stream_encode_opaque(xdr, value.data, value.len) >=3D 0; +} + static bool __maybe_unused xdrgen_encode_utf8string(struct xdr_stream *xdr, const utf8string value) { @@ -412,6 +815,29 @@ xdrgen_encode_utf8str_mixed(struct xdr_stream *xdr, co= nst utf8str_mixed value) return xdrgen_encode_utf8string(xdr, value); } =20 +static bool __maybe_unused +xdrgen_encode_component4(struct xdr_stream *xdr, const component4 value) +{ + return xdrgen_encode_utf8str_cs(xdr, value); +} + +static bool __maybe_unused +xdrgen_encode_linktext4(struct xdr_stream *xdr, const linktext4 value) +{ + return xdrgen_encode_utf8str_cs(xdr, value); +} + +static bool __maybe_unused +xdrgen_encode_pathname4(struct xdr_stream *xdr, const pathname4 value) +{ + if (xdr_stream_encode_u32(xdr, value.count) !=3D XDR_UNIT) + return false; + for (u32 i =3D 0; i < value.count; i++) + if (!xdrgen_encode_component4(xdr, value.element[i])) + return false; + return true; +} + static bool __maybe_unused xdrgen_encode_nfstime4(struct xdr_stream *xdr, const struct nfstime4 *valu= e) { @@ -422,6 +848,26 @@ xdrgen_encode_nfstime4(struct xdr_stream *xdr, const s= truct nfstime4 *value) return true; } =20 +static bool __maybe_unused +xdrgen_encode_fattr4(struct xdr_stream *xdr, const struct fattr4 *value) +{ + if (!xdrgen_encode_bitmap4(xdr, value->attrmask)) + return false; + if (!xdrgen_encode_attrlist4(xdr, value->attr_vals)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_stateid4(struct xdr_stream *xdr, const struct stateid4 *valu= e) +{ + if (!xdrgen_encode_uint32_t(xdr, value->seqid)) + return false; + if (xdr_stream_encode_opaque_fixed(xdr, value->other, 12) < 0) + return false; + return true; +} + static bool __maybe_unused xdrgen_encode_fattr4_offline(struct xdr_stream *xdr, const fattr4_offline = value) { @@ -567,3 +1013,137 @@ xdrgen_encode_fattr4_posix_access_acl(struct xdr_str= eam *xdr, const fattr4_posix return false; return true; } + +static bool __maybe_unused +xdrgen_encode_notify_type4(struct xdr_stream *xdr, notify_type4 value) +{ + return xdr_stream_encode_u32(xdr, value) =3D=3D XDR_UNIT; +} + +static bool __maybe_unused +xdrgen_encode_notify_entry4(struct xdr_stream *xdr, const struct notify_en= try4 *value) +{ + if (!xdrgen_encode_component4(xdr, value->ne_file)) + return false; + if (!xdrgen_encode_fattr4(xdr, &value->ne_attrs)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_prev_entry4(struct xdr_stream *xdr, const struct prev_entry4= *value) +{ + if (!xdrgen_encode_notify_entry4(xdr, &value->pe_prev_entry)) + return false; + if (!xdrgen_encode_nfs_cookie4(xdr, value->pe_prev_entry_cookie)) + return false; + return true; +} + +bool +xdrgen_encode_notify_remove4(struct xdr_stream *xdr, const struct notify_r= emove4 *value) +{ + if (!xdrgen_encode_notify_entry4(xdr, &value->nrm_old_entry)) + return false; + if (!xdrgen_encode_nfs_cookie4(xdr, value->nrm_old_entry_cookie)) + return false; + return true; +} + +bool +xdrgen_encode_notify_add4(struct xdr_stream *xdr, const struct notify_add4= *value) +{ + if (value->nad_old_entry.count > 1) + return false; + if (xdr_stream_encode_u32(xdr, value->nad_old_entry.count) !=3D XDR_UNIT) + return false; + for (u32 i =3D 0; i < value->nad_old_entry.count; i++) + if (!xdrgen_encode_notify_remove4(xdr, &value->nad_old_entry.element[i])) + return false; + if (!xdrgen_encode_notify_entry4(xdr, &value->nad_new_entry)) + return false; + if (value->nad_new_entry_cookie.count > 1) + return false; + if (xdr_stream_encode_u32(xdr, value->nad_new_entry_cookie.count) !=3D XD= R_UNIT) + return false; + for (u32 i =3D 0; i < value->nad_new_entry_cookie.count; i++) + if (!xdrgen_encode_nfs_cookie4(xdr, value->nad_new_entry_cookie.element[= i])) + return false; + if (value->nad_prev_entry.count > 1) + return false; + if (xdr_stream_encode_u32(xdr, value->nad_prev_entry.count) !=3D XDR_UNIT) + return false; + for (u32 i =3D 0; i < value->nad_prev_entry.count; i++) + if (!xdrgen_encode_prev_entry4(xdr, &value->nad_prev_entry.element[i])) + return false; + if (!xdrgen_encode_bool(xdr, value->nad_last_entry)) + return false; + return true; +} + +bool +xdrgen_encode_notify_attr4(struct xdr_stream *xdr, const struct notify_att= r4 *value) +{ + if (!xdrgen_encode_notify_entry4(xdr, &value->na_changed_entry)) + return false; + return true; +} + +bool +xdrgen_encode_notify_rename4(struct xdr_stream *xdr, const struct notify_r= ename4 *value) +{ + if (!xdrgen_encode_notify_remove4(xdr, &value->nrn_old_entry)) + return false; + if (!xdrgen_encode_notify_add4(xdr, &value->nrn_new_entry)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_notify_verifier4(struct xdr_stream *xdr, const struct notify= _verifier4 *value) +{ + if (!xdrgen_encode_verifier4(xdr, value->nv_old_cookieverf)) + return false; + if (!xdrgen_encode_verifier4(xdr, value->nv_new_cookieverf)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_notifylist4(struct xdr_stream *xdr, const notifylist4 value) +{ + return xdr_stream_encode_opaque(xdr, value.data, value.len) >=3D 0; +} + +static bool __maybe_unused +xdrgen_encode_notify4(struct xdr_stream *xdr, const struct notify4 *value) +{ + if (!xdrgen_encode_bitmap4(xdr, value->notify_mask)) + return false; + if (!xdrgen_encode_notifylist4(xdr, value->notify_vals)) + return false; + return true; +} + +bool +xdrgen_encode_CB_NOTIFY4args(struct xdr_stream *xdr, const struct CB_NOTIF= Y4args *value) +{ + if (!xdrgen_encode_stateid4(xdr, &value->cna_stateid)) + return false; + if (!xdrgen_encode_nfs_fh4(xdr, value->cna_fh)) + return false; + if (xdr_stream_encode_u32(xdr, value->cna_changes.count) !=3D XDR_UNIT) + return false; + for (u32 i =3D 0; i < value->cna_changes.count; i++) + if (!xdrgen_encode_notify4(xdr, &value->cna_changes.element[i])) + return false; + return true; +} + +bool +xdrgen_encode_CB_NOTIFY4res(struct xdr_stream *xdr, const struct CB_NOTIFY= 4res *value) +{ + if (!xdrgen_encode_nfsstat4(xdr, value->cnr_status)) + return false; + return true; +} diff --git a/fs/nfsd/nfs4xdr_gen.h b/fs/nfsd/nfs4xdr_gen.h index 1c487f1a11ab..503fe2ccba51 100644 --- a/fs/nfsd/nfs4xdr_gen.h +++ b/fs/nfsd/nfs4xdr_gen.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Generated by xdrgen. Manual edits will be lost. */ /* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x */ -/* XDR specification modification time: Thu Jan 8 23:12:07 2026 */ +/* XDR specification modification time: Wed Mar 25 11:39:22 2026 */ =20 #ifndef _LINUX_XDRGEN_NFS4_1_DECL_H #define _LINUX_XDRGEN_NFS4_1_DECL_H @@ -32,4 +32,22 @@ bool xdrgen_decode_posixaceperm4(struct xdr_stream *xdr,= posixaceperm4 *ptr); bool xdrgen_encode_posixaceperm4(struct xdr_stream *xdr, const posixaceper= m4 value); =20 =20 +bool xdrgen_decode_notify_remove4(struct xdr_stream *xdr, struct notify_re= move4 *ptr); +bool xdrgen_encode_notify_remove4(struct xdr_stream *xdr, const struct not= ify_remove4 *value); + +bool xdrgen_decode_notify_add4(struct xdr_stream *xdr, struct notify_add4 = *ptr); +bool xdrgen_encode_notify_add4(struct xdr_stream *xdr, const struct notify= _add4 *value); + +bool xdrgen_decode_notify_attr4(struct xdr_stream *xdr, struct notify_attr= 4 *ptr); +bool xdrgen_encode_notify_attr4(struct xdr_stream *xdr, const struct notif= y_attr4 *value); + +bool xdrgen_decode_notify_rename4(struct xdr_stream *xdr, struct notify_re= name4 *ptr); +bool xdrgen_encode_notify_rename4(struct xdr_stream *xdr, const struct not= ify_rename4 *value); + +bool xdrgen_decode_CB_NOTIFY4args(struct xdr_stream *xdr, struct CB_NOTIFY= 4args *ptr); +bool xdrgen_encode_CB_NOTIFY4args(struct xdr_stream *xdr, const struct CB_= NOTIFY4args *value); + +bool xdrgen_decode_CB_NOTIFY4res(struct xdr_stream *xdr, struct CB_NOTIFY4= res *ptr); +bool xdrgen_encode_CB_NOTIFY4res(struct xdr_stream *xdr, const struct CB_N= OTIFY4res *value); + #endif /* _LINUX_XDRGEN_NFS4_1_DECL_H */ diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 33953d38314e..171e8fdbafb6 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -1677,6 +1677,7 @@ TRACE_EVENT(nfsd_cb_setup_err, { OP_CB_RECALL, "CB_RECALL" }, \ { OP_CB_LAYOUTRECALL, "CB_LAYOUTRECALL" }, \ { OP_CB_RECALL_ANY, "CB_RECALL_ANY" }, \ + { OP_CB_NOTIFY, "CB_NOTIFY" }, \ { OP_CB_NOTIFY_LOCK, "CB_NOTIFY_LOCK" }, \ { OP_CB_OFFLOAD, "CB_OFFLOAD" }) =20 diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index d87be1f25273..44e5e9fa12e1 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -171,133 +171,6 @@ Needs to be updated if more operations are defined in= future.*/ #define LAST_NFS42_OP OP_REMOVEXATTR #define LAST_NFS4_OP LAST_NFS42_OP =20 -enum nfsstat4 { - NFS4_OK =3D 0, - NFS4ERR_PERM =3D 1, - NFS4ERR_NOENT =3D 2, - NFS4ERR_IO =3D 5, - NFS4ERR_NXIO =3D 6, - NFS4ERR_ACCESS =3D 13, - NFS4ERR_EXIST =3D 17, - NFS4ERR_XDEV =3D 18, - /* Unused/reserved 19 */ - NFS4ERR_NOTDIR =3D 20, - NFS4ERR_ISDIR =3D 21, - NFS4ERR_INVAL =3D 22, - NFS4ERR_FBIG =3D 27, - NFS4ERR_NOSPC =3D 28, - NFS4ERR_ROFS =3D 30, - NFS4ERR_MLINK =3D 31, - NFS4ERR_NAMETOOLONG =3D 63, - NFS4ERR_NOTEMPTY =3D 66, - NFS4ERR_DQUOT =3D 69, - NFS4ERR_STALE =3D 70, - NFS4ERR_BADHANDLE =3D 10001, - NFS4ERR_BAD_COOKIE =3D 10003, - NFS4ERR_NOTSUPP =3D 10004, - NFS4ERR_TOOSMALL =3D 10005, - NFS4ERR_SERVERFAULT =3D 10006, - NFS4ERR_BADTYPE =3D 10007, - NFS4ERR_DELAY =3D 10008, - NFS4ERR_SAME =3D 10009, - NFS4ERR_DENIED =3D 10010, - NFS4ERR_EXPIRED =3D 10011, - NFS4ERR_LOCKED =3D 10012, - NFS4ERR_GRACE =3D 10013, - NFS4ERR_FHEXPIRED =3D 10014, - NFS4ERR_SHARE_DENIED =3D 10015, - NFS4ERR_WRONGSEC =3D 10016, - NFS4ERR_CLID_INUSE =3D 10017, - NFS4ERR_RESOURCE =3D 10018, - NFS4ERR_MOVED =3D 10019, - NFS4ERR_NOFILEHANDLE =3D 10020, - NFS4ERR_MINOR_VERS_MISMATCH =3D 10021, - NFS4ERR_STALE_CLIENTID =3D 10022, - NFS4ERR_STALE_STATEID =3D 10023, - NFS4ERR_OLD_STATEID =3D 10024, - NFS4ERR_BAD_STATEID =3D 10025, - NFS4ERR_BAD_SEQID =3D 10026, - NFS4ERR_NOT_SAME =3D 10027, - NFS4ERR_LOCK_RANGE =3D 10028, - NFS4ERR_SYMLINK =3D 10029, - NFS4ERR_RESTOREFH =3D 10030, - NFS4ERR_LEASE_MOVED =3D 10031, - NFS4ERR_ATTRNOTSUPP =3D 10032, - NFS4ERR_NO_GRACE =3D 10033, - NFS4ERR_RECLAIM_BAD =3D 10034, - NFS4ERR_RECLAIM_CONFLICT =3D 10035, - NFS4ERR_BADXDR =3D 10036, - NFS4ERR_LOCKS_HELD =3D 10037, - NFS4ERR_OPENMODE =3D 10038, - NFS4ERR_BADOWNER =3D 10039, - NFS4ERR_BADCHAR =3D 10040, - NFS4ERR_BADNAME =3D 10041, - NFS4ERR_BAD_RANGE =3D 10042, - NFS4ERR_LOCK_NOTSUPP =3D 10043, - NFS4ERR_OP_ILLEGAL =3D 10044, - NFS4ERR_DEADLOCK =3D 10045, - NFS4ERR_FILE_OPEN =3D 10046, - NFS4ERR_ADMIN_REVOKED =3D 10047, - NFS4ERR_CB_PATH_DOWN =3D 10048, - - /* nfs41 */ - NFS4ERR_BADIOMODE =3D 10049, - NFS4ERR_BADLAYOUT =3D 10050, - NFS4ERR_BAD_SESSION_DIGEST =3D 10051, - NFS4ERR_BADSESSION =3D 10052, - NFS4ERR_BADSLOT =3D 10053, - NFS4ERR_COMPLETE_ALREADY =3D 10054, - NFS4ERR_CONN_NOT_BOUND_TO_SESSION =3D 10055, - NFS4ERR_DELEG_ALREADY_WANTED =3D 10056, - NFS4ERR_BACK_CHAN_BUSY =3D 10057, /* backchan reqs outstanding */ - NFS4ERR_LAYOUTTRYLATER =3D 10058, - NFS4ERR_LAYOUTUNAVAILABLE =3D 10059, - NFS4ERR_NOMATCHING_LAYOUT =3D 10060, - NFS4ERR_RECALLCONFLICT =3D 10061, - NFS4ERR_UNKNOWN_LAYOUTTYPE =3D 10062, - NFS4ERR_SEQ_MISORDERED =3D 10063, /* unexpected seq.id in req */ - NFS4ERR_SEQUENCE_POS =3D 10064, /* [CB_]SEQ. op not 1st op */ - NFS4ERR_REQ_TOO_BIG =3D 10065, /* request too big */ - NFS4ERR_REP_TOO_BIG =3D 10066, /* reply too big */ - NFS4ERR_REP_TOO_BIG_TO_CACHE =3D 10067, /* rep. not all cached */ - NFS4ERR_RETRY_UNCACHED_REP =3D 10068, /* retry & rep. uncached */ - NFS4ERR_UNSAFE_COMPOUND =3D 10069, /* retry/recovery too hard */ - NFS4ERR_TOO_MANY_OPS =3D 10070, /* too many ops in [CB_]COMP */ - NFS4ERR_OP_NOT_IN_SESSION =3D 10071, /* op needs [CB_]SEQ. op */ - NFS4ERR_HASH_ALG_UNSUPP =3D 10072, /* hash alg. not supp. */ - /* Error 10073 is unused. */ - NFS4ERR_CLIENTID_BUSY =3D 10074, /* clientid has state */ - NFS4ERR_PNFS_IO_HOLE =3D 10075, /* IO to _SPARSE file hole */ - NFS4ERR_SEQ_FALSE_RETRY =3D 10076, /* retry not original */ - NFS4ERR_BAD_HIGH_SLOT =3D 10077, /* sequence arg bad */ - NFS4ERR_DEADSESSION =3D 10078, /* persistent session dead */ - NFS4ERR_ENCR_ALG_UNSUPP =3D 10079, /* SSV alg mismatch */ - NFS4ERR_PNFS_NO_LAYOUT =3D 10080, /* direct I/O with no layout */ - NFS4ERR_NOT_ONLY_OP =3D 10081, /* bad compound */ - NFS4ERR_WRONG_CRED =3D 10082, /* permissions:state change */ - NFS4ERR_WRONG_TYPE =3D 10083, /* current operation mismatch */ - NFS4ERR_DIRDELEG_UNAVAIL =3D 10084, /* no directory delegation */ - NFS4ERR_REJECT_DELEG =3D 10085, /* on callback */ - NFS4ERR_RETURNCONFLICT =3D 10086, /* outstanding layoutreturn */ - NFS4ERR_DELEG_REVOKED =3D 10087, /* deleg./layout revoked */ - - /* nfs42 */ - NFS4ERR_PARTNER_NOTSUPP =3D 10088, - NFS4ERR_PARTNER_NO_AUTH =3D 10089, - NFS4ERR_UNION_NOTSUPP =3D 10090, - NFS4ERR_OFFLOAD_DENIED =3D 10091, - NFS4ERR_WRONG_LFS =3D 10092, - NFS4ERR_BADLABEL =3D 10093, - NFS4ERR_OFFLOAD_NO_REQS =3D 10094, - - /* xattr (RFC8276) */ - NFS4ERR_NOXATTR =3D 10095, - NFS4ERR_XATTR2BIG =3D 10096, - - /* can be used for internal errors */ - NFS4ERR_FIRST_FREE -}; - /* error codes for internal client use */ #define NFS4ERR_RESET_TO_MDS 12001 #define NFS4ERR_RESET_TO_PNFS 12002 diff --git a/include/linux/sunrpc/xdrgen/nfs4_1.h b/include/linux/sunrpc/xd= rgen/nfs4_1.h index 4ac54bdbd335..f761c3ddb4c7 100644 --- a/include/linux/sunrpc/xdrgen/nfs4_1.h +++ b/include/linux/sunrpc/xdrgen/nfs4_1.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Generated by xdrgen. Manual edits will be lost. */ /* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x */ -/* XDR specification modification time: Thu Jan 8 23:12:07 2026 */ +/* XDR specification modification time: Wed Mar 25 11:39:22 2026 */ =20 #ifndef _LINUX_XDRGEN_NFS4_1_DEF_H #define _LINUX_XDRGEN_NFS4_1_DEF_H @@ -9,15 +9,150 @@ #include #include =20 -typedef s64 int64_t; +typedef s32 int32_t; =20 typedef u32 uint32_t; =20 +typedef s64 int64_t; + +typedef u64 uint64_t; + +enum { NFS4_VERIFIER_SIZE =3D 8 }; + +enum { NFS4_FHSIZE =3D 128 }; + +enum nfsstat4 { + NFS4_OK =3D 0, + NFS4ERR_PERM =3D 1, + NFS4ERR_NOENT =3D 2, + NFS4ERR_IO =3D 5, + NFS4ERR_NXIO =3D 6, + NFS4ERR_ACCESS =3D 13, + NFS4ERR_EXIST =3D 17, + NFS4ERR_XDEV =3D 18, + NFS4ERR_NOTDIR =3D 20, + NFS4ERR_ISDIR =3D 21, + NFS4ERR_INVAL =3D 22, + NFS4ERR_FBIG =3D 27, + NFS4ERR_NOSPC =3D 28, + NFS4ERR_ROFS =3D 30, + NFS4ERR_MLINK =3D 31, + NFS4ERR_NAMETOOLONG =3D 63, + NFS4ERR_NOTEMPTY =3D 66, + NFS4ERR_DQUOT =3D 69, + NFS4ERR_STALE =3D 70, + NFS4ERR_BADHANDLE =3D 10001, + NFS4ERR_BAD_COOKIE =3D 10003, + NFS4ERR_NOTSUPP =3D 10004, + NFS4ERR_TOOSMALL =3D 10005, + NFS4ERR_SERVERFAULT =3D 10006, + NFS4ERR_BADTYPE =3D 10007, + NFS4ERR_DELAY =3D 10008, + NFS4ERR_SAME =3D 10009, + NFS4ERR_DENIED =3D 10010, + NFS4ERR_EXPIRED =3D 10011, + NFS4ERR_LOCKED =3D 10012, + NFS4ERR_GRACE =3D 10013, + NFS4ERR_FHEXPIRED =3D 10014, + NFS4ERR_SHARE_DENIED =3D 10015, + NFS4ERR_WRONGSEC =3D 10016, + NFS4ERR_CLID_INUSE =3D 10017, + NFS4ERR_RESOURCE =3D 10018, + NFS4ERR_MOVED =3D 10019, + NFS4ERR_NOFILEHANDLE =3D 10020, + NFS4ERR_MINOR_VERS_MISMATCH =3D 10021, + NFS4ERR_STALE_CLIENTID =3D 10022, + NFS4ERR_STALE_STATEID =3D 10023, + NFS4ERR_OLD_STATEID =3D 10024, + NFS4ERR_BAD_STATEID =3D 10025, + NFS4ERR_BAD_SEQID =3D 10026, + NFS4ERR_NOT_SAME =3D 10027, + NFS4ERR_LOCK_RANGE =3D 10028, + NFS4ERR_SYMLINK =3D 10029, + NFS4ERR_RESTOREFH =3D 10030, + NFS4ERR_LEASE_MOVED =3D 10031, + NFS4ERR_ATTRNOTSUPP =3D 10032, + NFS4ERR_NO_GRACE =3D 10033, + NFS4ERR_RECLAIM_BAD =3D 10034, + NFS4ERR_RECLAIM_CONFLICT =3D 10035, + NFS4ERR_BADXDR =3D 10036, + NFS4ERR_LOCKS_HELD =3D 10037, + NFS4ERR_OPENMODE =3D 10038, + NFS4ERR_BADOWNER =3D 10039, + NFS4ERR_BADCHAR =3D 10040, + NFS4ERR_BADNAME =3D 10041, + NFS4ERR_BAD_RANGE =3D 10042, + NFS4ERR_LOCK_NOTSUPP =3D 10043, + NFS4ERR_OP_ILLEGAL =3D 10044, + NFS4ERR_DEADLOCK =3D 10045, + NFS4ERR_FILE_OPEN =3D 10046, + NFS4ERR_ADMIN_REVOKED =3D 10047, + NFS4ERR_CB_PATH_DOWN =3D 10048, + NFS4ERR_BADIOMODE =3D 10049, + NFS4ERR_BADLAYOUT =3D 10050, + NFS4ERR_BAD_SESSION_DIGEST =3D 10051, + NFS4ERR_BADSESSION =3D 10052, + NFS4ERR_BADSLOT =3D 10053, + NFS4ERR_COMPLETE_ALREADY =3D 10054, + NFS4ERR_CONN_NOT_BOUND_TO_SESSION =3D 10055, + NFS4ERR_DELEG_ALREADY_WANTED =3D 10056, + NFS4ERR_BACK_CHAN_BUSY =3D 10057, + NFS4ERR_LAYOUTTRYLATER =3D 10058, + NFS4ERR_LAYOUTUNAVAILABLE =3D 10059, + NFS4ERR_NOMATCHING_LAYOUT =3D 10060, + NFS4ERR_RECALLCONFLICT =3D 10061, + NFS4ERR_UNKNOWN_LAYOUTTYPE =3D 10062, + NFS4ERR_SEQ_MISORDERED =3D 10063, + NFS4ERR_SEQUENCE_POS =3D 10064, + NFS4ERR_REQ_TOO_BIG =3D 10065, + NFS4ERR_REP_TOO_BIG =3D 10066, + NFS4ERR_REP_TOO_BIG_TO_CACHE =3D 10067, + NFS4ERR_RETRY_UNCACHED_REP =3D 10068, + NFS4ERR_UNSAFE_COMPOUND =3D 10069, + NFS4ERR_TOO_MANY_OPS =3D 10070, + NFS4ERR_OP_NOT_IN_SESSION =3D 10071, + NFS4ERR_HASH_ALG_UNSUPP =3D 10072, + NFS4ERR_CLIENTID_BUSY =3D 10074, + NFS4ERR_PNFS_IO_HOLE =3D 10075, + NFS4ERR_SEQ_FALSE_RETRY =3D 10076, + NFS4ERR_BAD_HIGH_SLOT =3D 10077, + NFS4ERR_DEADSESSION =3D 10078, + NFS4ERR_ENCR_ALG_UNSUPP =3D 10079, + NFS4ERR_PNFS_NO_LAYOUT =3D 10080, + NFS4ERR_NOT_ONLY_OP =3D 10081, + NFS4ERR_WRONG_CRED =3D 10082, + NFS4ERR_WRONG_TYPE =3D 10083, + NFS4ERR_DIRDELEG_UNAVAIL =3D 10084, + NFS4ERR_REJECT_DELEG =3D 10085, + NFS4ERR_RETURNCONFLICT =3D 10086, + NFS4ERR_DELEG_REVOKED =3D 10087, + NFS4ERR_PARTNER_NOTSUPP =3D 10088, + NFS4ERR_PARTNER_NO_AUTH =3D 10089, + NFS4ERR_UNION_NOTSUPP =3D 10090, + NFS4ERR_OFFLOAD_DENIED =3D 10091, + NFS4ERR_WRONG_LFS =3D 10092, + NFS4ERR_BADLABEL =3D 10093, + NFS4ERR_OFFLOAD_NO_REQS =3D 10094, + NFS4ERR_NOXATTR =3D 10095, + NFS4ERR_XATTR2BIG =3D 10096, + NFS4ERR_FIRST_FREE =3D 10097, +}; + +typedef enum nfsstat4 nfsstat4; + +typedef opaque attrlist4; + typedef struct { u32 count; uint32_t *element; } bitmap4; =20 +typedef u8 verifier4[NFS4_VERIFIER_SIZE]; + +typedef uint64_t nfs_cookie4; + +typedef opaque nfs_fh4; + typedef opaque utf8string; =20 typedef utf8string utf8str_cis; @@ -26,11 +161,30 @@ typedef utf8string utf8str_cs; =20 typedef utf8string utf8str_mixed; =20 +typedef utf8str_cs component4; + +typedef utf8str_cs linktext4; + +typedef struct { + u32 count; + component4 *element; +} pathname4; + struct nfstime4 { int64_t seconds; uint32_t nseconds; }; =20 +struct fattr4 { + bitmap4 attrmask; + attrlist4 attr_vals; +}; + +struct stateid4 { + uint32_t seqid; + u8 other[12]; +}; + typedef bool fattr4_offline; =20 enum { FATTR4_OFFLINE =3D 83 }; @@ -216,11 +370,98 @@ enum { FATTR4_POSIX_DEFAULT_ACL =3D 91 }; =20 enum { FATTR4_POSIX_ACCESS_ACL =3D 92 }; =20 -#define NFS4_int64_t_sz \ - (XDR_hyper) +enum notify_type4 { + NOTIFY4_CHANGE_CHILD_ATTRS =3D 0, + NOTIFY4_CHANGE_DIR_ATTRS =3D 1, + NOTIFY4_REMOVE_ENTRY =3D 2, + NOTIFY4_ADD_ENTRY =3D 3, + NOTIFY4_RENAME_ENTRY =3D 4, + NOTIFY4_CHANGE_COOKIE_VERIFIER =3D 5, +}; + +typedef enum notify_type4 notify_type4; + +struct notify_entry4 { + component4 ne_file; + struct fattr4 ne_attrs; +}; + +struct prev_entry4 { + struct notify_entry4 pe_prev_entry; + nfs_cookie4 pe_prev_entry_cookie; +}; + +struct notify_remove4 { + struct notify_entry4 nrm_old_entry; + nfs_cookie4 nrm_old_entry_cookie; +}; + +struct notify_add4 { + struct { + u32 count; + struct notify_remove4 *element; + } nad_old_entry; + struct notify_entry4 nad_new_entry; + struct { + u32 count; + nfs_cookie4 *element; + } nad_new_entry_cookie; + struct { + u32 count; + struct prev_entry4 *element; + } nad_prev_entry; + bool nad_last_entry; +}; + +struct notify_attr4 { + struct notify_entry4 na_changed_entry; +}; + +struct notify_rename4 { + struct notify_remove4 nrn_old_entry; + struct notify_add4 nrn_new_entry; +}; + +struct notify_verifier4 { + verifier4 nv_old_cookieverf; + verifier4 nv_new_cookieverf; +}; + +typedef opaque notifylist4; + +struct notify4 { + bitmap4 notify_mask; + notifylist4 notify_vals; +}; + +struct CB_NOTIFY4args { + struct stateid4 cna_stateid; + nfs_fh4 cna_fh; + struct { + u32 count; + struct notify4 *element; + } cna_changes; +}; + +struct CB_NOTIFY4res { + nfsstat4 cnr_status; +}; + +#define NFS4_int32_t_sz \ + (XDR_int) #define NFS4_uint32_t_sz \ (XDR_unsigned_int) +#define NFS4_int64_t_sz \ + (XDR_hyper) +#define NFS4_uint64_t_sz \ + (XDR_unsigned_hyper) +#define NFS4_nfsstat4_sz (XDR_int) +#define NFS4_attrlist4_sz (XDR_unsigned_int) #define NFS4_bitmap4_sz (XDR_unsigned_int) +#define NFS4_verifier4_sz (XDR_QUADLEN(NFS4_VERIFIER_SIZE)) +#define NFS4_nfs_cookie4_sz \ + (NFS4_uint64_t_sz) +#define NFS4_nfs_fh4_sz (XDR_unsigned_int + XDR_QUADLEN(NF= S4_FHSIZE)) #define NFS4_utf8string_sz (XDR_unsigned_int) #define NFS4_utf8str_cis_sz \ (NFS4_utf8string_sz) @@ -228,8 +469,17 @@ enum { FATTR4_POSIX_ACCESS_ACL =3D 92 }; (NFS4_utf8string_sz) #define NFS4_utf8str_mixed_sz \ (NFS4_utf8string_sz) +#define NFS4_component4_sz \ + (NFS4_utf8str_cs_sz) +#define NFS4_linktext4_sz \ + (NFS4_utf8str_cs_sz) +#define NFS4_pathname4_sz (XDR_unsigned_int) #define NFS4_nfstime4_sz \ (NFS4_int64_t_sz + NFS4_uint32_t_sz) +#define NFS4_fattr4_sz \ + (NFS4_bitmap4_sz + NFS4_attrlist4_sz) +#define NFS4_stateid4_sz \ + (NFS4_uint32_t_sz + XDR_QUADLEN(12)) #define NFS4_fattr4_offline_sz \ (XDR_bool) #define NFS4_open_arguments4_sz \ @@ -259,5 +509,27 @@ enum { FATTR4_POSIX_ACCESS_ACL =3D 92 }; (NFS4_aclscope4_sz) #define NFS4_fattr4_posix_default_acl_sz (XDR_unsigned_int) #define NFS4_fattr4_posix_access_acl_sz (XDR_unsigned_int) +#define NFS4_notify_type4_sz (XDR_int) +#define NFS4_notify_entry4_sz \ + (NFS4_component4_sz + NFS4_fattr4_sz) +#define NFS4_prev_entry4_sz \ + (NFS4_notify_entry4_sz + NFS4_nfs_cookie4_sz) +#define NFS4_notify_remove4_sz \ + (NFS4_notify_entry4_sz + NFS4_nfs_cookie4_sz) +#define NFS4_notify_add4_sz \ + (XDR_unsigned_int + (1 * (NFS4_notify_remove4_sz)) + NFS4_notify_entry4_s= z + XDR_unsigned_int + (1 * (NFS4_nfs_cookie4_sz)) + XDR_unsigned_int + (1 = * (NFS4_prev_entry4_sz)) + XDR_bool) +#define NFS4_notify_attr4_sz \ + (NFS4_notify_entry4_sz) +#define NFS4_notify_rename4_sz \ + (NFS4_notify_remove4_sz + NFS4_notify_add4_sz) +#define NFS4_notify_verifier4_sz \ + (NFS4_verifier4_sz + NFS4_verifier4_sz) +#define NFS4_notifylist4_sz (XDR_unsigned_int) +#define NFS4_notify4_sz \ + (NFS4_bitmap4_sz + NFS4_notifylist4_sz) +#define NFS4_CB_NOTIFY4args_sz \ + (NFS4_stateid4_sz + NFS4_nfs_fh4_sz + XDR_unsigned_int) +#define NFS4_CB_NOTIFY4res_sz \ + (NFS4_nfsstat4_sz) =20 #endif /* _LINUX_XDRGEN_NFS4_1_DEF_H */ diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h index 4273e0249fcb..289205b53a08 100644 --- a/include/uapi/linux/nfs4.h +++ b/include/uapi/linux/nfs4.h @@ -17,11 +17,9 @@ #include =20 #define NFS4_BITMAP_SIZE 3 -#define NFS4_VERIFIER_SIZE 8 #define NFS4_STATEID_SEQID_SIZE 4 #define NFS4_STATEID_OTHER_SIZE 12 #define NFS4_STATEID_SIZE (NFS4_STATEID_SEQID_SIZE + NFS4_STATEID_OTHER_SI= ZE) -#define NFS4_FHSIZE 128 #define NFS4_MAXPATHLEN PATH_MAX #define NFS4_MAXNAMLEN NAME_MAX #define NFS4_OPAQUE_LIMIT 1024 --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CFF3E481259; Thu, 11 Jun 2026 17:50:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200239; cv=none; b=a3lnaWKWMRkR+BzvcjXpVabL/ywJJa8+Cgty0jraepjo9gIBY1ZJZvpjL6jAcjg5KcLX19kIrQiLK+U8/YNEX83/CV3M6mOuC5x+lh1bP+1uWhKKs4c8VrxYtDDHOEcMtBzaNT18ijBSEgrRz+Dirzb26r+UuECcKpe+r4iKjjI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200239; c=relaxed/simple; bh=5QdCAzFj1xtHr3OX/4DTtTD3Q8MMOgPMdXfNVFwXwfw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kuv1HIzFuVUrDXwanv7Y2uWQ1E4bG0QNdaCyDhkgHAsNNp3GSqkj2IP8N58woarhxex3LW5v1R2M0K1yYmiqTo4HoSRGMvC9ioN1xwusOQskTTndcJwAqMDsllzCT8U3qZdV7QVDxRXg4xtywLco4KOO9sI0dAQgJcbpwVyPq2I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=m1D42YHF; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="m1D42YHF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 147961F00899; Thu, 11 Jun 2026 17:50:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200237; bh=83FiQeH2SCsz+66SuLbU9Iro/2Sv9Pc5c7i5osKqhqk=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=m1D42YHF7IThB6V3IS+v1k484QWgUs7sZPsCilFB4oqOhTAXVyusaEojHf8cKHfEr syc/vh/R277NkMsLdu3MSvn6kH1I0+4ReYUL7ZUyyLuua9j/STlnyMIXUnt6fcah7d K1OU79f/OguKa3buseCDtyjZ4W+1coBIZvLL9tMgMrgTzP8O6eaA+kJ7ZsXYLfQIU+ GSWG6gtMpXLwFBlTwx2QuUUhbCA3GJp5EXtuzJ1WuJT4MrgsGl1QU6bY5Tz4q/Jm09 WdoJihhMT9f3R/x//N9ha5rjT3qFk5r0QkAlcCw7AgcIBzxn1xYbHdzPdSJ1xyDlLB S/tl44ViS3opA== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:09 -0400 Subject: [PATCH v6 03/20] nfs_common: add new NOTIFY4_* flags proposed in RFC8881bis Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-3-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=4503; i=jlayton@kernel.org; h=from:subject:message-id; bh=5QdCAzFj1xtHr3OX/4DTtTD3Q8MMOgPMdXfNVFwXwfw=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVed9Lomu67k0PZRAin1inoQNrbKtzdWshiZ 3rrzN7BfzGJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1XgAKCRAADmhBGVaC FdiOEACR7e0ZQcIKT+2j997S6LNWci6gu0yYegzVa75aQH7e6vzl9WH6xoskP9RHhZx27+lL7kC KvaR8Q00DHCSmUX8Fk+nOlAzGq4Xkc93dszZtTzqkq15wwP1rnsFYYU0qfArqce71ijKM2o8nn+ ibixiUQqRtuyg4mg6aWi8Sal3I6EdqwbJgdXQO4lgBNqtcbbEypkaEn6l2FnxKu6cLVCWm8gyvP Klo2AW5CM5H34hAmE1YWhFoO1nFYL2ywVMG3uTt61zJLA/CPPhOLFtuxVgBuKKqMNh2CR12nzAb a6tLSAufjcVfa0e5VsNs8HMMsbveKJ2bj40Tn4p6KrE0Ao3EnGS/MXF1NSVJc31HE8TGJOxtECU uA2Z2P/BErv7I2YWOZWxWQoaurMJp4nhpmPiC+RWZEzEGiqW5bKZRAGtZNz+FpOaiZAzDlOHoFc CZ8DMTh1eEvu4YIU5sgKEic6ZC+ro73EP9csvCmk+OaNc1c30vfYAYncfcJYQNrHw3qqJeBvOBD ODrkXNE4ycNMQNtogNLh2BvZ5wOgGoqQLffVdKBe7NPozFzJW/yb/C5ndVK+hnqNZd9izlvZ5hY S8eo/cUaiivEoecfxEcbvh/GLEhtc6IJaNMMN7RN7Yn4CjuI2rzNrW4gAFD6QGYAflAd5cyIEvV fUoC362Tfu9cFvw== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 RFC8881bis adds some new flags to GET_DIR_DELEGATION that later patches will consume. In particular, Linux nfsd can't easily provide info about directory cookies and ordering. The new flags allow it to omit that information. There is some risk here -- RFC8881bis is still a working group document, and has been for years. The changes to directory delegations have been stable for the last year or so however, so the hope is that those parts won't change (much). Signed-off-by: Jeff Layton --- Documentation/sunrpc/xdr/nfs4_1.x | 14 +++++++++++++- fs/nfsd/nfs4xdr_gen.c | 13 ++++++++++++- fs/nfsd/nfs4xdr_gen.h | 2 +- include/linux/sunrpc/xdrgen/nfs4_1.h | 13 ++++++++++++- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Documentation/sunrpc/xdr/nfs4_1.x b/Documentation/sunrpc/xdr/n= fs4_1.x index 632f5b579c39..6039eb024e0e 100644 --- a/Documentation/sunrpc/xdr/nfs4_1.x +++ b/Documentation/sunrpc/xdr/nfs4_1.x @@ -416,7 +416,19 @@ enum notify_type4 { NOTIFY4_REMOVE_ENTRY =3D 2, NOTIFY4_ADD_ENTRY =3D 3, NOTIFY4_RENAME_ENTRY =3D 4, - NOTIFY4_CHANGE_COOKIE_VERIFIER =3D 5 + NOTIFY4_CHANGE_COOKIE_VERIFIER =3D 5, + /* Proposed in RFC8881bis */ + NOTIFY4_GFLAG_EXTEND =3D 6, + NOTIFY4_AUFLAG_VALID =3D 7, + NOTIFY4_AUFLAG_USER =3D 8, + NOTIFY4_AUFLAG_GROUP =3D 9, + NOTIFY4_AUFLAG_OTHER =3D 10, + NOTIFY4_CHANGE_AUTH =3D 11, + NOTIFY4_CFLAG_ORDER =3D 12, + NOTIFY4_AUFLAG_GANOW =3D 13, + NOTIFY4_AUFLAG_GALATER =3D 14, + NOTIFY4_CHANGE_GA =3D 15, + NOTIFY4_CHANGE_AMASK =3D 16 }; =20 /* Changed entry information. */ diff --git a/fs/nfsd/nfs4xdr_gen.c b/fs/nfsd/nfs4xdr_gen.c index 5e656d6bbb8e..80369139ef7e 100644 --- a/fs/nfsd/nfs4xdr_gen.c +++ b/fs/nfsd/nfs4xdr_gen.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Generated by xdrgen. Manual edits will be lost. // XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x -// XDR specification modification time: Wed Mar 25 11:39:22 2026 +// XDR specification modification time: Wed Mar 25 11:40:02 2026 =20 #include =20 @@ -590,6 +590,17 @@ xdrgen_decode_notify_type4(struct xdr_stream *xdr, not= ify_type4 *ptr) case NOTIFY4_ADD_ENTRY: case NOTIFY4_RENAME_ENTRY: case NOTIFY4_CHANGE_COOKIE_VERIFIER: + case NOTIFY4_GFLAG_EXTEND: + case NOTIFY4_AUFLAG_VALID: + case NOTIFY4_AUFLAG_USER: + case NOTIFY4_AUFLAG_GROUP: + case NOTIFY4_AUFLAG_OTHER: + case NOTIFY4_CHANGE_AUTH: + case NOTIFY4_CFLAG_ORDER: + case NOTIFY4_AUFLAG_GANOW: + case NOTIFY4_AUFLAG_GALATER: + case NOTIFY4_CHANGE_GA: + case NOTIFY4_CHANGE_AMASK: break; default: return false; diff --git a/fs/nfsd/nfs4xdr_gen.h b/fs/nfsd/nfs4xdr_gen.h index 503fe2ccba51..092a1ed399c7 100644 --- a/fs/nfsd/nfs4xdr_gen.h +++ b/fs/nfsd/nfs4xdr_gen.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Generated by xdrgen. Manual edits will be lost. */ /* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x */ -/* XDR specification modification time: Wed Mar 25 11:39:22 2026 */ +/* XDR specification modification time: Wed Mar 25 11:40:02 2026 */ =20 #ifndef _LINUX_XDRGEN_NFS4_1_DECL_H #define _LINUX_XDRGEN_NFS4_1_DECL_H diff --git a/include/linux/sunrpc/xdrgen/nfs4_1.h b/include/linux/sunrpc/xd= rgen/nfs4_1.h index f761c3ddb4c7..537504069f24 100644 --- a/include/linux/sunrpc/xdrgen/nfs4_1.h +++ b/include/linux/sunrpc/xdrgen/nfs4_1.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Generated by xdrgen. Manual edits will be lost. */ /* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x */ -/* XDR specification modification time: Wed Mar 25 11:39:22 2026 */ +/* XDR specification modification time: Wed Mar 25 11:40:02 2026 */ =20 #ifndef _LINUX_XDRGEN_NFS4_1_DEF_H #define _LINUX_XDRGEN_NFS4_1_DEF_H @@ -377,6 +377,17 @@ enum notify_type4 { NOTIFY4_ADD_ENTRY =3D 3, NOTIFY4_RENAME_ENTRY =3D 4, NOTIFY4_CHANGE_COOKIE_VERIFIER =3D 5, + NOTIFY4_GFLAG_EXTEND =3D 6, + NOTIFY4_AUFLAG_VALID =3D 7, + NOTIFY4_AUFLAG_USER =3D 8, + NOTIFY4_AUFLAG_GROUP =3D 9, + NOTIFY4_AUFLAG_OTHER =3D 10, + NOTIFY4_CHANGE_AUTH =3D 11, + NOTIFY4_CFLAG_ORDER =3D 12, + NOTIFY4_AUFLAG_GANOW =3D 13, + NOTIFY4_AUFLAG_GALATER =3D 14, + NOTIFY4_CHANGE_GA =3D 15, + NOTIFY4_CHANGE_AMASK =3D 16, }; =20 typedef enum notify_type4 notify_type4; --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EDF7F480352; Thu, 11 Jun 2026 17:50:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200241; cv=none; b=uBtRsX0JAY7i5E50cuC9rKLSoOO3u7w90hFGox6TRNRhuxMypYOi2IT/NFWq2+X/J1ZF9YFM9ZBYOa7aVKZHv1wLvqSPqBAiYA+Yj9+xxTVUJVjJlEGvpzjARzFF/wdgqZfqpcSZQhn0fCoY09x0zLAVGV5JXHwwdGBo4oU0eEk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200241; c=relaxed/simple; bh=9D/1Ecxaoz+pUGRSVNpZO5nIi/SNoL2Xg6pvQtEKUW0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PDYjsj5tz7QesuB6ZlFwTUUu8BUWhoPrxhsseW7zMobkm23nUPPJcbKooxlhjQMarS5j4BYRPPyGZCSjxTLuSK/E3yWr8Ha/85o1u3y//XDwAENykP16RhgM4vnNkd1gj7SE/SzotcPE/tq510arjzuvf1DyVpGxYo418Wz+zH8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PupIT0XG; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PupIT0XG" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0288E1F00898; Thu, 11 Jun 2026 17:50:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200239; bh=0RsP7KqA+6ek5yn/DNGISIDQXloZMbV5Hp6UvSNf/iA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=PupIT0XG0CTHvcnJa34gD6PjYzNoP8c/VlyXvM5hSKP9sBjyibO7lMhcFFGHKDLLQ uud9aNFhfCOYcLIH2Acb3ut3uDwtKRNjKLFl1fOGhz2Nsxqdeq09zXzmB99JOvo8P6 UdsLnZ7LrN630Ymy5mnZ9vFBENi8EJRemdAefvm/RwjyXqipnpL4/Cg3AH9PWM3Rna W0WJzU5/68pKW1O605jiWtb+0nw6CyQrilrulhKPjSCd+sunJXtp+ynP7lWBuof4Sw G9UMbhkVWHIwsJv/LRDzL7iVdPrvFTAUjmEJJuZwYzZDKYLrkaE57wKcHFSyNVjTet bU/33GC4bvQBg== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:10 -0400 Subject: [PATCH v6 04/20] nfsd: allow nfsd to get a dir lease with an ignore mask Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-4-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2515; i=jlayton@kernel.org; h=from:subject:message-id; bh=9D/1Ecxaoz+pUGRSVNpZO5nIi/SNoL2Xg6pvQtEKUW0=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVe5wNrPKB/0xM/0UFgrppj/FHQi7M+2ic7P OuNHE8VssKJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1XgAKCRAADmhBGVaC FTLSD/0SmPbqo3Lx3070lqd1kO0fIiUY7v6ALGoI8EJK6HjvOnZjvq/TVJdG2EtE64TNlrLLfdR RJoho89AlNlIyvoO8Kl0/PiINpPrrIAa5nKQ2H5/YKF1bcagNb/FDknJo1LwT0nAw8zFszgeR5H mARoWTX5Lh5wIvJh2PBig1hqVAduxO3RnddOLy4MeZGPPhhWn0qMFt4GtA4pvkFwEhZDrWOMuxh RUyZrBxmsErD2q0GJgb7sjpsL164s/qprChqT/Dp7ESCGl8SW+KzQbMcIIiPWXhE2Fts6ClopVz V8hCgNKoZ9eC+bmoVd8iFMg9VGqcfCEf8nf0V5Thld0CvNkwa0EYrMTYkcJmB3wYxWROlKReetZ XTF+H/0z36042LntueINNGI74yCOzoKKST2X0fyDbW55ZI5wsM0RB+MTp7GuIedoxWHrnfpdr0B EUT0JIvfDgrnUdt0Mg/84wd7CxLOvWfTkV2+6YKpJ46Dcs5AzG+sO/06yWTdMN4nafOPWWIPa9e b45f8HnfIukxq6Yd6x5RwOz9FjCWGo+UEqdqKB5T+qH0zUKWiRM4RmR4Xgd4mMroeGV6YFYPxD8 RMypH33WtsVF8dlUuw66WR+nORJ7HrFYrZmwAcFzKVfB0nhjObr6UN/78szWjr+bS5VwuHKRgkL WKwUMf2MsyOpeuQ== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 When requesting a directory lease, enable the FL_IGN_DIR_* bits that correspond to the requested notification types. In nfsd_get_dir_deleg(), gddr_notification[0] will ultimately represent the notifications that will be provided to the client. For now, that field is always set to 0. That will change once the upper layers are ready to start ignoring certain events. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4state.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 489558bf124c..ae8505747dc2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -6119,7 +6119,22 @@ static bool nfsd4_cb_channel_good(struct nfs4_client= *clp) return clp->cl_minorversion && clp->cl_cb_state =3D=3D NFSD4_CB_UNKNOWN; } =20 -static struct file_lease *nfs4_alloc_init_lease(struct nfs4_delegation *dp) +static unsigned int +nfsd_notify_to_ignore(u32 notify) +{ + unsigned int mask =3D 0; + + if (notify & BIT(NOTIFY4_REMOVE_ENTRY)) + mask |=3D FL_IGN_DIR_DELETE; + if (notify & BIT(NOTIFY4_ADD_ENTRY)) + mask |=3D FL_IGN_DIR_CREATE; + if (notify & BIT(NOTIFY4_RENAME_ENTRY)) + mask |=3D FL_IGN_DIR_RENAME; + + return mask; +} + +static struct file_lease *nfs4_alloc_init_lease(struct nfs4_delegation *dp= , u32 notify) { struct file_lease *fl; =20 @@ -6127,7 +6142,7 @@ static struct file_lease *nfs4_alloc_init_lease(struc= t nfs4_delegation *dp) if (!fl) return NULL; fl->fl_lmops =3D &nfsd_lease_mng_ops; - fl->c.flc_flags =3D FL_DELEG; + fl->c.flc_flags =3D FL_DELEG | nfsd_notify_to_ignore(notify); fl->c.flc_type =3D deleg_is_read(dp->dl_type) ? F_RDLCK : F_WRLCK; fl->c.flc_owner =3D (fl_owner_t)dp; fl->c.flc_pid =3D current->tgid; @@ -6344,7 +6359,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct n= fs4_ol_stateid *stp, if (stp->st_stid.sc_export) dp->dl_stid.sc_export =3D exp_get(stp->st_stid.sc_export); =20 - fl =3D nfs4_alloc_init_lease(dp); + fl =3D nfs4_alloc_init_lease(dp, 0); if (!fl) goto out_clnt_odstate; =20 @@ -9771,7 +9786,11 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *csta= te, dp->dl_stid.sc_export =3D exp_get(cstate->current_fh.fh_export); =20 - fl =3D nfs4_alloc_init_lease(dp); + /* + * NB: gddr_notification[0] represents the notifications that + * will be granted to the client + */ + fl =3D nfs4_alloc_init_lease(dp, gdd->gddr_notification[0]); if (!fl) goto out_put_stid; =20 --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A237D4A33E5; Thu, 11 Jun 2026 17:50:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200242; cv=none; b=XSZZ7azi/Y7W806MaidK+t1J8H8HX3nV8tURslJJBq7NarLi/cK7b2ZVZrUwJ/QUsiWnY1O+rZmM/TJuEQlQyS2IXxtdxLi0C+hxVChRVrVoy4sHk2yboTeHILxGTd6KMtOadRJZHJq1uuJ0hi5NeYyxbJfENZqJ62R4069WpUM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200242; c=relaxed/simple; bh=2mj7rilJ3++y8iwjD02Sk6de1eteiT1OmZ8l6jAnzs0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=NG3i6dxMmcDEItXHccMNKY/k7SRWlP5tca7E7ybkn1Ph2hfRJU1FO6chUkvjy7teTAzeZ6NH/xOef8+IFMSaAnNE5wSyhJnKMJycaTYhFu2Sb7Ff7hYoZqvn0qlP1w9KFRL82ZpdDvAssJrfdFTypC5F4jFZ5OuuLgHn89B7Ats= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZHrCF75s; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZHrCF75s" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DE5EF1F00893; Thu, 11 Jun 2026 17:50:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200241; bh=rlSdhSVKpu6D4XddoJBpjIt8rwUphSQXIugI32Vz1KI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=ZHrCF75skNgV8Ac7OHFU+mv/6QhEjLPbYL9YEMPJrmu8JfUUJ0Yegcz9pj2YvMOUJ 7/6Gtj0Ix+Dm6udPPi0ZleHXyVyS1ZKgQ9FEplJmLw0akjgF9jVePdKvT29gtTuRo0 OPpscY5N4ZV5Xc/zmi7BMt7jJ+H+utUZq31kaG8o5Zp+768yOuyU8cHMpm++QZ56O/ +9b5ZXIGF+2HV0eJCiD1RNW0KPM1HVPpxvBMeK8eudUxk6kXjt8H0XNsBQ+fc51/IP a9lPNcCF9XlvD+mbjmAKNfBmQI7wEbRnMEb3FDKnEPApntgIaQURnV5A3EOBnal1vX Z/G0Kgw5gMNTA== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:11 -0400 Subject: [PATCH v6 05/20] nfsd: update the fsnotify mark when setting or removing a dir delegation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-5-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5219; i=jlayton@kernel.org; h=from:subject:message-id; bh=2mj7rilJ3++y8iwjD02Sk6de1eteiT1OmZ8l6jAnzs0=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVe1rHK5wRojzx2heBdNq/ZpBQhnXKzxHfA/ ytJQMeOa9qJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1XgAKCRAADmhBGVaC FW73D/4jWQouGujqRB8d0B8Asj2gJ5HanD4kwefGctXhoPEO6LU+ZsxKDxaHu0+w+Oo2Fkl2FGH 9SW/9aRYB1G+dcGH/y8u/b8JweYLk+DA9kvGcOhuUu0gJhjSNrZ87ULAmoptb+litv0UDCf9bq7 +olaofq2WatUumEqw3WaakqIMRL0zpPzvc4wTlgK3TJpKBVO2UH5SvkVH0QN2oos4YyYUtZrdxS 3H+bQ+BzJ6c/B3prVy416fUHcCxmLD/NqyRxeSElwWIQP1Muw5wQds6wjW7+aZbN0BwYsUELlMw 3rGqskbT47lO+ne41D51vsVF10tJHH4IzjJo8j8az7ELYDjHz50MsiB8EreKVqa19XoWu3nfukV ofKmIb29CdvFs/moZdpNpw1SX8xW6j/uZB1lMXI2S1yi2hPmNu3GX0Ue1wFyzLo10lAT49Kh67u 22HJSNecNKQXTF7y4G0WCmeJtJFKry25oTrFlwwDsTyK0FqheylEX0kA3qYx/Pd5GSWuLJkBn3F Zpagq2vpisZe1QI6//UdaZe7Zqq+l72gFhqWxBpsnTI1HZ47PymtSQ7omwHis7YFCTqSJtQuHCW aoaocJl5O1slW8Fo+CA1EmItr60G/27SWj3bHlFsIzy0sVVLPdDOEJukhg6fZCSnJ9tguzuWP57 Xo6AlHbImHopfmg== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Add a new helper function that will update the mask on the nfsd_file's fsnotify_mark to be a union of all current directory delegations on an inode. Call that when directory delegations are added or removed, since that can change what fsnotify events nfsd requires from the VFS layer. The fsnotify_mark is shared by every nfsd_file open on the inode, so concurrent delegation adds and removes on the same directory can run nfsd_fsnotify_recalc_mask() in parallel. Because it reads the lease state and updates the mark in two separate locked sections, a recalc working from a stale snapshot of the lease list could clobber a concurrent update and leave the mark missing required events. Add an nfm_recalc_mutex to the nfsd_file_mark and hold it across the recalc to serialize callers. Reviewed-by: Jan Kara Signed-off-by: Jeff Layton --- fs/nfsd/filecache.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++= +++ fs/nfsd/filecache.h | 3 +++ fs/nfsd/nfs4state.c | 5 +++-- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index 1ea2bfd51825..c5f2c5768324 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -192,6 +192,7 @@ nfsd_file_mark_find_or_create(struct inode *inode) fsnotify_init_mark(&new->nfm_mark, nfsd_file_fsnotify_group); new->nfm_mark.mask =3D FS_ATTRIB|FS_DELETE_SELF; refcount_set(&new->nfm_ref, 1); + mutex_init(&new->nfm_recalc_mutex); =20 err =3D fsnotify_add_inode_mark(&new->nfm_mark, inode, 0); =20 @@ -1473,3 +1474,54 @@ int nfsd_file_cache_stats_show(struct seq_file *m, v= oid *v) seq_printf(m, "mean age (ms): -\n"); return 0; } + +/** + * nfsd_fsnotify_recalc_mask - recalculate the fsnotify mask for a nfsd_fi= le + * @nf: nfsd_file to recalculate the mask on + * + * When a directory nfsd_file has a delegation added or removed, that may + * change the events that nfsd requires from the VFS layer. This function + * recalculates the fsnotify mask based on the leases present. + */ +void nfsd_fsnotify_recalc_mask(struct nfsd_file *nf) +{ + struct inode *inode =3D file_inode(nf->nf_file); + u32 lease_mask, set =3D 0, clear =3D 0; + struct fsnotify_mark *mark; + + /* This is only needed when adding or removing dir delegs */ + if (!S_ISDIR(inode->i_mode) || !nf->nf_mark) + return; + + mark =3D &nf->nf_mark->nfm_mark; + + /* + * The mark is shared by every nfsd_file on this inode, so concurrent + * delegation add/remove on the same directory can recalc it in + * parallel. Serialize the read of the lease state and the update of + * the mark so that a recalc working from a stale snapshot of the + * lease list can't clobber a concurrent recalc's update. + */ + mutex_lock(&nf->nf_mark->nfm_recalc_mutex); + + /* Set up notifications for any ignored delegation events */ + lease_mask =3D inode_lease_ignore_mask(inode); + + if (lease_mask & FL_IGN_DIR_CREATE) + set |=3D FS_CREATE | FS_MOVED_TO; + else + clear |=3D FS_CREATE | FS_MOVED_TO; + + if (lease_mask & FL_IGN_DIR_DELETE) + set |=3D FS_DELETE | FS_MOVED_FROM; + else + clear |=3D FS_DELETE | FS_MOVED_FROM; + + if (lease_mask & FL_IGN_DIR_RENAME) + set |=3D FS_RENAME; + else + clear |=3D FS_RENAME; + + fsnotify_modify_mark_mask(mark, set, clear); + mutex_unlock(&nf->nf_mark->nfm_recalc_mutex); +} diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h index 683b6437cacc..b224902b438d 100644 --- a/fs/nfsd/filecache.h +++ b/fs/nfsd/filecache.h @@ -26,6 +26,8 @@ struct nfsd_file_mark { struct fsnotify_mark nfm_mark; refcount_t nfm_ref; + /* serializes nfsd_fsnotify_recalc_mask() against itself */ + struct mutex nfm_recalc_mutex; }; =20 /* @@ -86,4 +88,5 @@ __be32 nfsd_file_acquire_local(struct net *net, struct sv= c_cred *cred, __be32 nfsd_file_acquire_dir(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file **pnf); int nfsd_file_cache_stats_show(struct seq_file *m, void *v); +void nfsd_fsnotify_recalc_mask(struct nfsd_file *nf); #endif /* _FS_NFSD_FILECACHE_H */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ae8505747dc2..0cbb37f73ee7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1255,6 +1255,7 @@ static void nfs4_unlock_deleg_lease(struct nfs4_deleg= ation *dp) =20 nfsd4_finalize_deleg_timestamps(dp, nf->nf_file); kernel_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); + nfsd_fsnotify_recalc_mask(nf); put_deleg_file(fp); } =20 @@ -9725,8 +9726,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, = struct dentry *dentry, * @nf: nfsd_file opened on the directory * * Given a GET_DIR_DELEGATION request @gdd, attempt to acquire a delegation - * on the directory to which @nf refers. Note that this does not set up any - * sort of async notifications for the delegation. + * on the directory to which @nf refers. */ struct nfs4_delegation * nfsd_get_dir_deleg(struct nfsd4_compound_state *cstate, @@ -9816,6 +9816,7 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstat= e, =20 if (!status) { put_nfs4_file(fp); + nfsd_fsnotify_recalc_mask(nf); return dp; } =20 --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C1B574A13BD; Thu, 11 Jun 2026 17:50:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200245; cv=none; b=M2Iqd++yMnjf6zSWB5dePZnMitWmx2HPkfI1iazyjPA3SjDzTqVrcpmDHvvEcaChJlpjyQEGPVRS5Ai2p6egmozJIKpmgLL5hFQ+iPk1juZ0YB2k88+K1s50FMJuCrF6OfzEoA+orpdY+XyICf4Lkj3Oh8N0j5qQduYTnMpKsjg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200245; c=relaxed/simple; bh=e76Cj4t7vZ74CIrCBdGtHE4fA2leVDhN748tl1SGulo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ELCJiosJir5sD/5kzdMtVc9Lvybye3e3OUFzTeoWfZABkZ1n84S400n8Y+Kt0ohJHP8o3D78tW8c0VyYxfV1Sg7F4QPvJoaOyD/0qChSls5dDDyOP7LQzDZw8lLfSspVHKGxVjM4h0V7vGD92A0Ks3HEsIvuynQzIz4EJC3oSNY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UQXOY62j; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UQXOY62j" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C63811F00898; Thu, 11 Jun 2026 17:50:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200243; bh=EThRh57fPLePzVxsH7+4kVjCWJt6EICg8XpCZoiOIfs=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=UQXOY62jeZX6BSL8teLBljwzbS46AR0oBxtM6JyzQwjJFvafpHXzvscQZKaxqwLfE N5QY5s8K5XuyPdAxJMVrrRipFxzHW6dxCWcnlsYuLKuaF37Jh5wLbcQZ2j92dE78xc Yoxs5RZ1t8fweHeDoL89Ivih0zQR0LkmkLVJ3TYb1RdZkUtCPvlQqtfcQUCFdiVJyY 4z17JJUUorIK7ODvgBkRGFaLQRvb7S/SiC+5cWxvsfO/dkk6/JQnkQ38T7K55AbsFp 2O19er3p6inPxVDZL7cIf9J1j0r5m8j7TIByfX/lwZonneC0rD+6BFGkttir/kp9VP RQoEIwGJRKPRQ== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:12 -0400 Subject: [PATCH v6 06/20] nfsd: make nfsd4_callback_ops->prepare operation bool return Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-6-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3301; i=jlayton@kernel.org; h=from:subject:message-id; bh=e76Cj4t7vZ74CIrCBdGtHE4fA2leVDhN748tl1SGulo=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVfl3yYpN26Lr0yrqUl4ufxN7NY4vM49XAbp /lNIUjbVTaJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1XwAKCRAADmhBGVaC FbG8D/9MkOI+lBcG+58c0zD5TjTtFMl4hrEQ2SsLPTWZ4RRG2c7iAumAn5f5GBBAH2GW2xfORI5 4QWoRX7BiNGD47s7Be7L0NGIE8NXjGbgQ8KotRvRmkSswCk+OCPKeCN3PXWxihnybhW81lVS8vE eif/KcnZTk0zmlE2GJakwik9zuvW6JIvmat7iw2yN6jZwoIyssNkefl1x+AASpmeTBeGJ6w6Bia xt0Ch69Huv4dGZ5EZ0Ula/a0QjPnFrU5n+05jSw5pqXHRpZ2GxBDFc5Ni0cpxzbgKFCgSa+5d1f gQ80fEJBnhgDGlNZFKcwskxMCHxwVOc65NkqjXTgde3SX6S4Q12pos3dC7y0RuC9/5Iun6kkqLK V7vsQkiZnwPSN9mRw73QMN9a1kUhVXoMEgluZwTpSyNngA0iYwbawl/oESzVIaZxGYVfMj2ZdGG e2dWpXYWURpMXyjlq+IAGaAi7gVxblMmQ0M9MA58VmyD/ZjMivpuDakAJv/Eap1dJoGfaLedo0C zmess2cTKtzL6nELQ3V3GkSM96HAemWZdBWG3NlpJx8p1HFKZJJilNAbbe5GPLIPOYsKpPv78gN hqkDqZY4ZEn20SjR7eQh6arX6rIh70dBP/d3pT8JwAzJAAUFNkLh0pngxCxzJgTBn3w44KhA9o8 MtYtCwtym65t5zg== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 For a CB_NOTIFY operation, we need to stop processing the callback if an allocation fails. Change the ->prepare callback operation to return true if processing should continue, and false otherwise. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4callback.c | 5 ++++- fs/nfsd/nfs4layouts.c | 3 ++- fs/nfsd/nfs4state.c | 6 ++++-- fs/nfsd/state.h | 6 +++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 1628bb9ef9dd..a3c46905fd47 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -1786,7 +1786,10 @@ nfsd4_run_cb_work(struct work_struct *work) =20 if (!test_and_clear_bit(NFSD4_CALLBACK_REQUEUE, &cb->cb_flags)) { if (cb->cb_ops && cb->cb_ops->prepare) - cb->cb_ops->prepare(cb); + if (!cb->cb_ops->prepare(cb)) { + nfsd41_destroy_cb(cb); + return; + } } =20 cb->cb_msg.rpc_cred =3D clp->cl_cb_cred; diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 279ff1e9dffb..4c3f253c7d07 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -659,7 +659,7 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls, st= ruct nfsd_file *file) } } =20 -static void +static bool nfsd4_cb_layout_prepare(struct nfsd4_callback *cb) { struct nfs4_layout_stateid *ls =3D @@ -668,6 +668,7 @@ nfsd4_cb_layout_prepare(struct nfsd4_callback *cb) mutex_lock(&ls->ls_mutex); nfs4_inc_and_copy_stateid(&ls->ls_recall_sid, &ls->ls_stid); mutex_unlock(&ls->ls_mutex); + return true; } =20 static int diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0cbb37f73ee7..1ff954a18f93 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -357,12 +357,13 @@ remove_blocked_locks(struct nfs4_lockowner *lo) } } =20 -static void +static bool nfsd4_cb_notify_lock_prepare(struct nfsd4_callback *cb) { struct nfsd4_blocked_lock *nbl =3D container_of(cb, struct nfsd4_blocked_lock, nbl_cb); locks_delete_block(&nbl->nbl_lock); + return true; } =20 static int @@ -5599,7 +5600,7 @@ bool nfsd_wait_for_delegreturn(struct svc_rqst *rqstp= , struct inode *inode) return timeo > 0; } =20 -static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) +static bool nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) { struct nfs4_delegation *dp =3D cb_to_delegation(cb); struct nfsd_net *nn =3D net_generic(dp->dl_stid.sc_client->net, @@ -5620,6 +5621,7 @@ static void nfsd4_cb_recall_prepare(struct nfsd4_call= back *cb) list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); } spin_unlock(&nn->deleg_lock); + return true; } =20 static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index f44ea672670f..4c6765a4cf22 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -98,9 +98,9 @@ struct nfsd4_callback { }; =20 struct nfsd4_callback_ops { - void (*prepare)(struct nfsd4_callback *); - int (*done)(struct nfsd4_callback *, struct rpc_task *); - void (*release)(struct nfsd4_callback *); + bool (*prepare)(struct nfsd4_callback *cb); + int (*done)(struct nfsd4_callback *cb, struct rpc_task *task); + void (*release)(struct nfsd4_callback *cb); uint32_t opcode; }; =20 --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B07044BC03A; Thu, 11 Jun 2026 17:50:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200247; cv=none; b=aY/qmg3WPuDh8MoKttG623OQr/NmzAUD1MYjqwtCq7PiAaBjC4lceYNMPgq3AM657Odutc4cNPsDEzzqA/Z8XepW+bEwFjMOGSi2lDjGK+OseZlDXitd7WV9R1SYR7XRbmtZ3tTl6QZA6DT1v1WDanhRO/mir0jht0UDLe1fn0M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200247; c=relaxed/simple; bh=/v4AGcwQ+jnip7ZQR/LFyLLB2ScGGRIhZ59DQDHD4ok=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mnDfT+uXT3JjDLxLbltupLl7IomW7zYNwOl63PwFrDoE026iRrWWrASO3v4I6LqBLfA/pW/8Kff0Vzrtj9PhZ7dHVKpJ0mJEg59nRCHB5OrnDWXWsI7EHw58FKlwFhcAZlYOiOaqgu59QOo2SrsEIK5DxKRdsujEq3L/xZ64s4w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CfMInuf6; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="CfMInuf6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AD7491F00899; Thu, 11 Jun 2026 17:50:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200245; bh=lXV96LtnO9o/mjSP+w7I8N2g9RxbMO5a1AjpS6Fy6rM=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=CfMInuf6GALvKyof2wLkTqvLrMEw0MCWdmX4Qva/i2/xcUM7huaEXqo/0Ev/jD3j/ gbMBetlXxk04GZufE4TaFlV/slyD0KqKuJhdDUINZmQ6a8H6B2wOMdUsAYHYoF7mI1 Fpteb2gKg3za/VBfH0o0+3yLxpZWvraWjKiWaVCkjgwU/3PzPzkwullSUNMqvXFG/v xOmoKyAhI4InR1m3Vu/mts06zqf6mVxwS4baWTjv5bl8z4PVM8RxF3PF6ybJ59LfTM Lbx4lQyxGC20OKF6R4H9FimG06MNEqNU/86MSPgQt3HBmujnCGKfIlR1gA5X8RFx7M nkF6Ln6/2D89g== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:13 -0400 Subject: [PATCH v6 07/20] nfsd: add callback encoding and decoding linkages for CB_NOTIFY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-7-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=4063; i=jlayton@kernel.org; h=from:subject:message-id; bh=/v4AGcwQ+jnip7ZQR/LFyLLB2ScGGRIhZ59DQDHD4ok=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVf5E600Pbka7zLUe4XVEcHBrlrLjke+Oy+a 7uzDtX1T9qJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1XwAKCRAADmhBGVaC FVlXD/49+9hmWEvkURRaV61VyLU0RgQ5Aw3ZrAVuX2dsy1WgmFkhXdgQo6TaGZSPMnzNw0uAJZB O/5RKbso3N7UaJha2OZ43xYRXd/p+MlA4nnc+fZuZOxgf9p3Azcf3ylBLMN1wcNFU51UQTesCyc CZsgWxNHgUFN8XBFfKVvhkSr8Mpagta0ZHP/8VkBxIPNQtyaSasafLm3gK3T6Kd2GjyWWqnlTGt F82JmWidz8+rUT+4699n/a8FM9r8tpM41n3/jlYX4rmgGw8AYw5WOEdr+1OFRlz1y8oskj+gSf4 1BChBuxNuIL6MlEpzQhZPrZhcH27fLnOpNYLidZbyxqRwz1j/RseTZQIdnON+vHCVtkp0k8w06y VmTEnYRKfKOybQB+i2cZ17Ypp/NiulMiga0jyp1pTp5xk+GYTMmXYNK71y+5V+JQ4RkTm9gBlIH X98U8+/LaZsEkQzTd/hPHrXzRL612SA9Rl3JJfkiA6Gly7rsSq8Yc+EZ3HRBIWIkUKfweL5Czce m2bnpdoFrXsh/Nz7XZL3IBOVEUqnnfkZAZvnCNH4n3upIG36WnjhcGB3fOeNHaFlVuVCVuM3WbR 0h+rFStdmkId46fgRlnmdWgJhwFA+J9sdzwv82/tvohc8W2D3WkFzuSpL7XQV/fF6R7MYcYRdYq /IPdVwWAfHhWFjw== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Add routines for encoding and decoding CB_NOTIFY messages. These call into the code generated by xdrgen to do the actual encoding and decoding. For now, the encoder is a stub. Later patches will flesh out the payload encoding. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4callback.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/state.h | 8 ++++++++ fs/nfsd/xdr4cb.h | 12 ++++++++++++ 3 files changed, 66 insertions(+) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index a3c46905fd47..ca4dd2f969eb 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -887,6 +887,51 @@ static void encode_stateowner(struct xdr_stream *xdr, = struct nfs4_stateowner *so xdr_encode_opaque(p, so->so_owner.data, so->so_owner.len); } =20 +static void nfs4_xdr_enc_cb_notify(struct rpc_rqst *req, + struct xdr_stream *xdr, + const void *data) +{ + const struct nfsd4_callback *cb =3D data; + struct nfs4_cb_compound_hdr hdr =3D { + .ident =3D 0, + .minorversion =3D cb->cb_clp->cl_minorversion, + }; + struct CB_NOTIFY4args args =3D { }; + + WARN_ON_ONCE(hdr.minorversion =3D=3D 0); + + encode_cb_compound4args(xdr, &hdr); + encode_cb_sequence4args(xdr, cb, &hdr); + + /* + * FIXME: get stateid and fh from delegation. Inline the cna_changes + * buffer, and zero it. + */ + xdrgen_encode_CB_NOTIFY4args(xdr, &args); + + hdr.nops++; + encode_cb_nops(&hdr); +} + +static int nfs4_xdr_dec_cb_notify(struct rpc_rqst *rqstp, + struct xdr_stream *xdr, + void *data) +{ + struct nfsd4_callback *cb =3D data; + struct nfs4_cb_compound_hdr hdr; + int status; + + status =3D decode_cb_compound4res(xdr, &hdr); + if (unlikely(status)) + return status; + + status =3D decode_cb_sequence4res(xdr, cb); + if (unlikely(status || cb->cb_seq_status)) + return status; + + return decode_cb_op_status(xdr, OP_CB_NOTIFY, &cb->cb_status); +} + static void nfs4_xdr_enc_cb_notify_lock(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) @@ -1048,6 +1093,7 @@ static const struct rpc_procinfo nfs4_cb_procedures[]= =3D { #ifdef CONFIG_NFSD_PNFS PROC(CB_LAYOUT, COMPOUND, cb_layout, cb_layout), #endif + PROC(CB_NOTIFY, COMPOUND, cb_notify, cb_notify), PROC(CB_NOTIFY_LOCK, COMPOUND, cb_notify_lock, cb_notify_lock), PROC(CB_OFFLOAD, COMPOUND, cb_offload, cb_offload), PROC(CB_RECALL_ANY, COMPOUND, cb_recall_any, cb_recall_any), diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 4c6765a4cf22..9f321e9ed76d 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -190,6 +190,13 @@ struct nfs4_cb_fattr { u64 ncf_cur_fsize; }; =20 +/* + * FIXME: the current backchannel encoder can't handle a send buffer longer + * than a single page (see bc_malloc/bc_free). + */ +#define NOTIFY4_EVENT_QUEUE_SIZE 3 +#define NOTIFY4_PAGE_ARRAY_SIZE 1 + /* * Represents a delegation stateid. The nfs4_client holds references to th= ese * and they are put when it is being destroyed or when the delegation is @@ -776,6 +783,7 @@ enum nfsd4_cb_op { NFSPROC4_CLNT_CB_NOTIFY_LOCK, NFSPROC4_CLNT_CB_RECALL_ANY, NFSPROC4_CLNT_CB_GETATTR, + NFSPROC4_CLNT_CB_NOTIFY, }; =20 /* Returns true iff a is later than b: */ diff --git a/fs/nfsd/xdr4cb.h b/fs/nfsd/xdr4cb.h index f4e29c0c701c..b06d0170d7c4 100644 --- a/fs/nfsd/xdr4cb.h +++ b/fs/nfsd/xdr4cb.h @@ -33,6 +33,18 @@ cb_sequence_dec_sz + \ op_dec_sz) =20 +#define NFS4_enc_cb_notify_sz (cb_compound_enc_hdr_sz + \ + cb_sequence_enc_sz + \ + 1 + enc_stateid_sz + \ + enc_nfs4_fh_sz + \ + 1 + \ + NOTIFY4_EVENT_QUEUE_SIZE * \ + (2 + (NFS4_OPAQUE_LIMIT >> 2))) + +#define NFS4_dec_cb_notify_sz (cb_compound_dec_hdr_sz + \ + cb_sequence_dec_sz + \ + op_dec_sz) + #define NFS4_enc_cb_notify_lock_sz (cb_compound_enc_hdr_sz + \ cb_sequence_enc_sz + \ 2 + 1 + \ --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E281941325C; Thu, 11 Jun 2026 17:50:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200251; cv=none; b=Xe+0g6RGoO20OkEJGMUiMc8GBHqpKaE4V7OyFgNEUZVKJHgPxbumFIY6aCEZu2PsWTxQnxCfS90ZL/JqEsEU5hsUl6w5dzx/V9oGlTVI79MSUUUvsJQhcdG0cvt3HkYFSrGXB8s49hh/GQomWPj+odScAYaoY/QYTnEjkwqDEc0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200251; c=relaxed/simple; bh=iN6TK9RWLIPs5Fe0ntwppLzGgSTCWnO9MUgusZhsHUg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tMyhgVWyihSWkfkf0ZZlxJPbSDa+1tMNywsBhqNgxMsdM5opUsXXGBRkn82MJLAxEA6Rc6E8uKEuSWV09aiTHeSs92phtKPVXGI3Dxa0y3CwnGG58mUbAhEypWo6cjD3Kh52qhVMkxLgH15aDesaifXgzZJTav+FwDZmluyngMY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OxQkelA0; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OxQkelA0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 96F171F0089A; Thu, 11 Jun 2026 17:50:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200247; bh=kno+CwgnyMJF0/5i/TqOY2JdOePrnndvsTg7Gt+DwtY=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=OxQkelA0l4ha5xxZYceDjzc6ykwh7/yXgqbPj7EtHYzh4rU4nCq3VCsXNKQYhge3R 4N3anpoU6iNHVplqPdEjqHCF3r91KmAZF6au5U/jyFjTjbu8opogubv88xg/EFOBWe oLzPiwOLB6+SxHE+YJDUiRTLiQKnRAUdoTvUmlTxQ3qPSA6X+GOI1LBwqRu5wRzrDD C9Q3zVKQi2gHsa9HP0E+FzoUVwgDlwUxlJkmyz7lL+4U6l6ZnhFeSr57ovbZyeYJKd elVx8xxYVws65zyx9sv3S3xMSkDjdEJwzwBXBz0WiDvhsrbO6ns5eNTtoJ3s9qPBRB p5HUyHSI08rYg== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:14 -0400 Subject: [PATCH v6 08/20] nfsd: use RCU to protect fi_deleg_file Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-8-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=9332; i=jlayton@kernel.org; h=from:subject:message-id; bh=iN6TK9RWLIPs5Fe0ntwppLzGgSTCWnO9MUgusZhsHUg=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVfvJwv2Rf+SeHOeUBwgIxRwvyXsV2ADT4Cw koLzmcQgc6JAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1XwAKCRAADmhBGVaC FeNvEACNTGhJqOzSwaEnUCctGlsI85zRfGBVu6JjN+HLmAH0yxP2tfAfg3U1evDa6pQNCqA3f7l huAwE8eyw+w3Cq42quD4j7If/W2aILXs403mngVErAWDcE8mIb6jzBttrnPDC84K+rUxe9LoJf9 BxWWN0OoxhT/RXsv9yKle92Vw7xIiCbehice6heOJkPjRBY+0ZMZ5Fz7QLrTQn/31iM/UsRirxp 5qfeYqIaU0q4R4+uZWdA8mzwimdcinroZhoixSo7HwaI0E1WPb3Dqr3PAas8LfRzsHgIK5+BhU2 7mt1JQWUWIQjtDJ5kbVymzbRPRgvRG9QNJgqZiI0pOfTt1RWX4Q2g8tp0fkZFFcaHtd2RllVu2R SvLSTA9d1++xcNlUt9n/25CXqnQC3c/RkcoEe9R+pL8LtHkLGyD3RTOWrostRB0PJ0YOEVBQ2XU xGkznFUizmVlOtNnoJsGDRMB5JffcW5FfGSz5IWMFsBS3ndi5qOIX++4LZjzO1OuRH1qhiuEV1w piEo662rhPB8aAjANVCGrPLrS8utGNITaFOepce4LvgXTO8gNdw3D7L0k8RmZR8DD10q1MI3otq X0X2bU9Ed9rbugZKsa1F7FuRO9LsZltCrKKrcZlj/9HmE2vTJsomXOWohY7VH9fxbEsDbmVuMtQ Fl93TNCTNLwMFhA== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 fi_deleg_file can be NULLed by put_deleg_file() when fi_delegees drops to zero during delegation teardown (e.g. DELEGRETURN). Concurrent accesses from workqueue callbacks -- such as CB_NOTIFY -- can dereference a NULL pointer if they race with this teardown. Annotate fi_deleg_file with __rcu and convert all accessors to use proper RCU primitives: - rcu_assign_pointer() / RCU_INIT_POINTER() for stores - rcu_dereference_protected() for reads under fi_lock or where fi_delegees > 0 guarantees stability This prepares for a subsequent patch that will use rcu_read_lock + rcu_dereference + nfsd_file_get to safely acquire a reference from the CB_NOTIFY callback path without holding fi_lock. The error-path lease teardown in nfsd_get_dir_deleg() is one of these accessors, and it must drop the lease against fi_deleg_file->nf_file rather than this client's nf->nf_file. The lease's flc_file is fi_deleg_file (set in nfs4_alloc_init_lease()), which differs from nf when an earlier client already holds a delegation on the same directory. generic_delete_lease() matches on flc_file, so unlocking the wrong file would fail to remove the lease, leaking it on the inode and then freeing its owning stid underneath it -- a use-after-free once the leaked lease is later broken. Read fi_deleg_file there with rcu_dereference_protected() like the other accessors, and recalculate the fsnotify mask after dropping the lease to match the success path. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Jeff Layton --- fs/nfsd/nfs4layouts.c | 7 ++++--- fs/nfsd/nfs4state.c | 51 ++++++++++++++++++++++++++++++++++-------------= ---- fs/nfsd/state.h | 2 +- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 4c3f253c7d07..22bcb6d09f70 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -248,12 +248,13 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_stat= e *cstate, NFSPROC4_CLNT_CB_LAYOUT); =20 if (parent->sc_type =3D=3D SC_TYPE_DELEG) { - spin_lock(&fp->fi_lock); - ls->ls_file =3D nfsd_file_get(fp->fi_deleg_file); - spin_unlock(&fp->fi_lock); + rcu_read_lock(); + ls->ls_file =3D nfsd_file_get(rcu_dereference(fp->fi_deleg_file)); + rcu_read_unlock(); } else { ls->ls_file =3D find_any_file(fp); } + if (!ls->ls_file) { nfs4_put_stid(stp); return NULL; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 1ff954a18f93..18e81c7f9d19 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1212,7 +1212,9 @@ static void put_deleg_file(struct nfs4_file *fp) =20 spin_lock(&fp->fi_lock); if (--fp->fi_delegees =3D=3D 0) { - swap(nf, fp->fi_deleg_file); + nf =3D rcu_dereference_protected(fp->fi_deleg_file, + lockdep_is_held(&fp->fi_lock)); + RCU_INIT_POINTER(fp->fi_deleg_file, NULL); swap(rnf, fp->fi_rdeleg_file); } spin_unlock(&fp->fi_lock); @@ -1250,7 +1252,7 @@ static void nfsd4_finalize_deleg_timestamps(struct nf= s4_delegation *dp, struct f static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) { struct nfs4_file *fp =3D dp->dl_stid.sc_file; - struct nfsd_file *nf =3D fp->fi_deleg_file; + struct nfsd_file *nf =3D rcu_dereference_protected(fp->fi_deleg_file, 1); =20 WARN_ON_ONCE(!fp->fi_delegees); =20 @@ -3186,7 +3188,8 @@ static int nfs4_show_deleg(struct seq_file *s, struct= nfs4_stid *st) /* XXX: lease time, whether it's being recalled. */ =20 spin_lock(&nf->fi_lock); - file =3D nf->fi_deleg_file; + file =3D rcu_dereference_protected(nf->fi_deleg_file, + lockdep_is_held(&nf->fi_lock)); if (file) { seq_puts(s, ", "); nfs4_show_superblock(s, file); @@ -4995,7 +4998,7 @@ static void nfsd4_file_init(const struct svc_fh *fh, = struct nfs4_file *fp) INIT_LIST_HEAD(&fp->fi_delegations); INIT_LIST_HEAD(&fp->fi_clnt_odstate); fh_copy_shallow(&fp->fi_fhandle, &fh->fh_handle); - fp->fi_deleg_file =3D NULL; + RCU_INIT_POINTER(fp->fi_deleg_file, NULL); fp->fi_rdeleg_file =3D NULL; fp->fi_had_conflict =3D false; fp->fi_share_deny =3D 0; @@ -6149,7 +6152,7 @@ static struct file_lease *nfs4_alloc_init_lease(struc= t nfs4_delegation *dp, u32 fl->c.flc_type =3D deleg_is_read(dp->dl_type) ? F_RDLCK : F_WRLCK; fl->c.flc_owner =3D (fl_owner_t)dp; fl->c.flc_pid =3D current->tgid; - fl->c.flc_file =3D dp->dl_stid.sc_file->fi_deleg_file->nf_file; + fl->c.flc_file =3D rcu_dereference_protected(dp->dl_stid.sc_file->fi_dele= g_file, 1)->nf_file; return fl; } =20 @@ -6157,7 +6160,7 @@ static int nfsd4_check_conflicting_opens(struct nfs4_= client *clp, struct nfs4_file *fp) { struct nfs4_ol_stateid *st; - struct file *f =3D fp->fi_deleg_file->nf_file; + struct file *f =3D rcu_dereference_protected(fp->fi_deleg_file, 1)->nf_fi= le; struct inode *ino =3D file_inode(f); int writes; =20 @@ -6234,7 +6237,7 @@ nfsd4_verify_deleg_dentry(struct nfsd4_open *open, st= ruct nfs4_file *fp, =20 exp_put(exp); dput(child); - if (child !=3D file_dentry(fp->fi_deleg_file->nf_file)) + if (child !=3D file_dentry(rcu_dereference_protected(fp->fi_deleg_file, 1= )->nf_file)) return -EAGAIN; =20 return 0; @@ -6340,8 +6343,9 @@ nfs4_set_delegation(struct nfsd4_open *open, struct n= fs4_ol_stateid *stp, status =3D -EAGAIN; else if (nfsd4_verify_setuid_write(open, nf)) status =3D -EAGAIN; - else if (!fp->fi_deleg_file) { - fp->fi_deleg_file =3D nf; + else if (!rcu_dereference_protected(fp->fi_deleg_file, + lockdep_is_held(&fp->fi_lock))) { + rcu_assign_pointer(fp->fi_deleg_file, nf); /* increment early to prevent fi_deleg_file from being * cleared */ fp->fi_delegees =3D 1; @@ -6366,7 +6370,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct n= fs4_ol_stateid *stp, if (!fl) goto out_clnt_odstate; =20 - status =3D kernel_setlease(fp->fi_deleg_file->nf_file, + status =3D kernel_setlease(rcu_dereference_protected(fp->fi_deleg_file, 1= )->nf_file, fl->c.flc_type, &fl, NULL); if (fl) locks_free_lease(fl); @@ -6387,7 +6391,7 @@ nfs4_set_delegation(struct nfsd4_open *open, struct n= fs4_ol_stateid *stp, * Now that the deleg is set, check again to ensure that nothing * raced in and changed the mode while we weren't looking. */ - status =3D nfsd4_verify_setuid_write(open, fp->fi_deleg_file); + status =3D nfsd4_verify_setuid_write(open, rcu_dereference_protected(fp->= fi_deleg_file, 1)); if (status) goto out_unlock; =20 @@ -6408,7 +6412,8 @@ nfs4_set_delegation(struct nfsd4_open *open, struct n= fs4_ol_stateid *stp, =20 return dp; out_unlock: - kernel_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); + kernel_setlease(rcu_dereference_protected(fp->fi_deleg_file, 1)->nf_file, + F_UNLCK, NULL, (void **)&dp); out_clnt_odstate: put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_stid(&dp->dl_stid); @@ -6565,8 +6570,9 @@ nfs4_open_delegation(struct svc_rqst *rqstp, struct n= fsd4_open *open, memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl= _stid.sc_stateid)); =20 if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) { - struct file *f =3D dp->dl_stid.sc_file->fi_deleg_file->nf_file; + struct file *f; =20 + f =3D rcu_dereference_protected(dp->dl_stid.sc_file->fi_deleg_file, 1)->= nf_file; if (!nfsd4_add_rdaccess_to_wrdeleg(rqstp, open, fh, stp) || !nfs4_delegation_stat(dp, currentfh, &stat)) { nfs4_put_stid(&dp->dl_stid); @@ -9765,8 +9771,9 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstat= e, /* existing delegation? */ if (nfs4_delegation_exists(clp, fp)) { status =3D -EAGAIN; - } else if (!fp->fi_deleg_file) { - fp->fi_deleg_file =3D nfsd_file_get(nf); + } else if (!rcu_dereference_protected(fp->fi_deleg_file, + lockdep_is_held(&fp->fi_lock))) { + rcu_assign_pointer(fp->fi_deleg_file, nfsd_file_get(nf)); fp->fi_delegees =3D 1; } else { ++fp->fi_delegees; @@ -9822,8 +9829,18 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *csta= te, return dp; } =20 - /* Something failed. Drop the lease and clean up the stid */ - kernel_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); + /* + * Something failed after the lease was set. Drop the lease and clean + * up the stid. The lease's flc_file is the fi_deleg_file (see + * nfs4_alloc_init_lease()), which is not necessarily this client's + * @nf when an earlier client already holds a delegation on @fp. + * generic_delete_lease() matches on flc_file, so unlock against + * fi_deleg_file or the lease will be leaked (and later freed with the + * stid, leading to a use-after-free when it's eventually broken). + */ + kernel_setlease(rcu_dereference_protected(fp->fi_deleg_file, 1)->nf_file, + F_UNLCK, NULL, (void **)&dp); + nfsd_fsnotify_recalc_mask(nf); out_put_stid: nfs4_put_stid(&dp->dl_stid); out_delegees: diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 9f321e9ed76d..4fca0537ca8b 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -699,7 +699,7 @@ struct nfs4_file { */ atomic_t fi_access[2]; u32 fi_share_deny; - struct nfsd_file *fi_deleg_file; + struct nfsd_file __rcu *fi_deleg_file; struct nfsd_file *fi_rdeleg_file; int fi_delegees; struct knfsd_fh fi_fhandle; --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D67614C6F16; Thu, 11 Jun 2026 17:50:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200254; cv=none; b=EqEB6n8ll9g0hI353c/oqyQ6VdzTcCss70JeBgbKWEpq1Et+qQ0uK8779yOm48kjU3S09wRQNyJv5+NrtLNr7uAu60be5FVITTF9GHa/Ruj1NzZMyTjRdYumxGN+oYsjUHlGkZf+TPy4COkXf2T6ypO7SnoOXXcYG9HGfaeKToQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200254; c=relaxed/simple; bh=xrXr6jUxmyI17X6MLZ6PG+4mPNOR/YYk82fJ8HI+J2o=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tW9BpI6oPeosl2KTwPOZkQqGhLzaVEKLLigZMEJDNFCDLostBxJhlGQ9DcL8rdahSeHe7DJ7ENeGSLYcE0jgEenjboU/cUDVKb/vFVIcecA70hFyIYYntHfRc9ib4ROQYWauT2eHvcBeY90Eznwrrxap71K4vjAZ+Ct4xTnBu/Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=l3w8GaYO; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="l3w8GaYO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7F8D01F00893; Thu, 11 Jun 2026 17:50:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200249; bh=KNRuRyRRwYT8cq2ZFhNIo7FW66TtF6J8eQjeI51vxEk=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=l3w8GaYOryZst+cOSynCv+xQAuCsxwBfRPeOJEel5lzZZ/OcWNSfT8kDgThGImxLN MBhEJkuls4uIkZCqrZKbYlTi2mm2+AfVlXHmlNiHlBDVjfxpDJXNC4EyS0sPrOOZDW TxOTy1inhiuhPyvdJy3CXQZHWW0kTekuEAOqvCqSiggF8qRcjHkdplGAqBKqZ8YhxM mp5s40uaIlupmHWLeF/IlSh0cdhsmoBUGJaNIKxRtdHczSaja4s4CtKAN4mbT0hrnx KrJI1zrW8pM74CI/Gthr+lDQDw3sSXjQN9JRhDgun1ptIaeVcOL/H3qCqJ7NzDRc1W 4i081icWyx0ng== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:15 -0400 Subject: [PATCH v6 09/20] nfsd: add data structures for handling CB_NOTIFY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-9-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=9133; i=jlayton@kernel.org; h=from:subject:message-id; bh=xrXr6jUxmyI17X6MLZ6PG+4mPNOR/YYk82fJ8HI+J2o=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVgnOSNphgivHYsyI9O0Ih5t/KN2CYTpEfOx BZrxKQsSrOJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1YAAKCRAADmhBGVaC FR2ZD/9Rk7cCX9Q3bacPq6XKz7/KJT4vEJ7wJtITZBaN3jQ1oznK4lQzQijBmE0XxRs1wLi7B5N BcOq+wWBDrMVY90BrdlNQTfqb6/NrZRiVPAqeEUf5x6somrgb0lt5LdiyDa/oU1amA5Fo8pLwkA Ko9kUzbwx8T1aIW5dQ9V155kZrbpNyig1QFgI37BgPH7N5QFBKaYgKkbvbobDBHb2Gr5HXhlaWZ d17GK8j80/4vn58Rnj88TTpH1DXUUxQe/Kcypehj/6EKsIRBYbZ4J/7vVGnueBt8h8Juw4NsuLE rHm9/KkTWLsgG7t9ainREYUIsKuwoBf0c1CJTmhOCz0nByax1VzTr9oSPzaoSlmCuxEHBH4EsmW yblxSXC+sDVwDZraQffyPJKDXgxgICuSoqQHRAxnx9icN6+fiHNw2idATQH4V/ZG6A8PMMF4NyF B09ccmYRTYSsQNMzA27cAuRlKegw6OI8/uBZWkjVgeMJMOW5UxgvnFvanbalP38Wee+U11dKnQO nMgxdz+TBo3qUY0aFxJAI1xrxagURBSZJOJsEsE03qt38cEcPDOBvhd24dxndRobdjpSKbtTe/y Whk0XAVBjIpyHmOBCnZkKS90AS1hGLH14wt4Ir3bcsfdKXWqzW6biOslcl2Kav7mk7w13hXkxLe dkOv8ueyzWd87Ow== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Add the data structures, allocation helpers, and callback operations needed for directory delegation CB_NOTIFY support: - struct nfsd_notify_event: carries fsnotify events for CB_NOTIFY - struct nfsd4_cb_notify: per-delegation state for notification handling - Union dl_cb_fattr with dl_cb_notify in nfs4_delegation since a delegation is either a regular file delegation or a directory delegation, never both Refactor alloc_init_deleg() into a common __alloc_init_deleg() base with a pluggable sc_free callback, and add alloc_init_dir_deleg() which allocates the page array and notify4 buffer needed for CB_NOTIFY encoding. Add skeleton nfsd4_cb_notify_ops with done/release handlers that will be filled in when the notification path is wired up. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4state.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++--= ---- fs/nfsd/state.h | 47 +++++++++++++++++++- 2 files changed, 152 insertions(+), 16 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 18e81c7f9d19..0a15d7f3b543 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -126,6 +126,7 @@ static void free_session(struct nfsd4_session *); static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; static const struct nfsd4_callback_ops nfsd4_cb_getattr_ops; +static const struct nfsd4_callback_ops nfsd4_cb_notify_ops; =20 static struct workqueue_struct *laundry_wq; =20 @@ -1123,29 +1124,31 @@ static void block_delegations(struct knfsd_fh *fh) } =20 static struct nfs4_delegation * -alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, - struct nfs4_clnt_odstate *odstate, u32 dl_type) +__alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, + struct nfs4_clnt_odstate *odstate, u32 dl_type, + void (*sc_free)(struct nfs4_stid *)) { struct nfs4_delegation *dp; struct nfs4_stid *stid; long n; =20 - dprintk("NFSD alloc_init_deleg\n"); + if (delegation_blocked(&fp->fi_fhandle)) + return NULL; + n =3D atomic_long_inc_return(&num_delegations); if (n < 0 || n > max_delegations) goto out_dec; - if (delegation_blocked(&fp->fi_fhandle)) - goto out_dec; - stid =3D nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg); + + stid =3D nfs4_alloc_stid(clp, deleg_slab, sc_free); if (stid =3D=3D NULL) goto out_dec; - dp =3D delegstateid(stid); =20 /* * delegation seqid's are never incremented. The 4.1 special * meaning of seqid 0 isn't meaningful, really, but let's avoid - * 0 anyway just for consistency and use 1: + * 0 anyway just for consistency and use 1. */ + dp =3D delegstateid(stid); dp->dl_stid.sc_stateid.si_generation =3D 1; INIT_LIST_HEAD(&dp->dl_perfile); INIT_LIST_HEAD(&dp->dl_perclnt); @@ -1155,19 +1158,79 @@ alloc_init_deleg(struct nfs4_client *clp, struct nf= s4_file *fp, dp->dl_type =3D dl_type; dp->dl_retries =3D 1; dp->dl_recalled =3D false; - nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, - &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); - nfsd4_init_cb(&dp->dl_cb_fattr.ncf_getattr, dp->dl_stid.sc_client, - &nfsd4_cb_getattr_ops, NFSPROC4_CLNT_CB_GETATTR); - dp->dl_cb_fattr.ncf_file_modified =3D false; get_nfs4_file(fp); dp->dl_stid.sc_file =3D fp; + nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, + &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); return dp; out_dec: atomic_long_dec(&num_delegations); return NULL; } =20 +static struct nfs4_delegation * +alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, + struct nfs4_clnt_odstate *odstate, u32 dl_type) +{ + struct nfs4_delegation *dp; + + dp =3D __alloc_init_deleg(clp, fp, odstate, dl_type, nfs4_free_deleg); + if (!dp) + return NULL; + + nfsd4_init_cb(&dp->dl_cb_fattr.ncf_getattr, dp->dl_stid.sc_client, + &nfsd4_cb_getattr_ops, NFSPROC4_CLNT_CB_GETATTR); + dp->dl_cb_fattr.ncf_file_modified =3D false; + return dp; +} + +static void nfs4_free_dir_deleg(struct nfs4_stid *stid) +{ + struct nfs4_delegation *dp =3D delegstateid(stid); + struct nfsd4_cb_notify *ncn =3D &dp->dl_cb_notify; + int i; + + for (i =3D 0; i < ncn->ncn_evt_cnt; ++i) + nfsd_notify_event_put(ncn->ncn_evt[i]); + kfree(ncn->ncn_nf); + for (i =3D 0; i < NOTIFY4_PAGE_ARRAY_SIZE; i++) { + if (!ncn->ncn_pages[i]) + break; + put_page(ncn->ncn_pages[i]); + } + nfs4_free_deleg(stid); +} + +static struct nfs4_delegation * +alloc_init_dir_deleg(struct nfs4_client *clp, struct nfs4_file *fp) +{ + struct nfs4_delegation *dp; + struct nfsd4_cb_notify *ncn; + int npages; + + dp =3D __alloc_init_deleg(clp, fp, NULL, NFS4_OPEN_DELEGATE_READ, nfs4_fr= ee_dir_deleg); + if (!dp) + return NULL; + + ncn =3D &dp->dl_cb_notify; + + npages =3D alloc_pages_bulk(GFP_KERNEL, NOTIFY4_PAGE_ARRAY_SIZE, ncn->ncn= _pages); + if (npages !=3D NOTIFY4_PAGE_ARRAY_SIZE) { + nfs4_put_stid(&dp->dl_stid); + return NULL; + } + + ncn->ncn_nf =3D kcalloc(NOTIFY4_EVENT_QUEUE_SIZE, sizeof(*ncn->ncn_nf), G= FP_KERNEL); + if (!ncn->ncn_nf) { + nfs4_put_stid(&dp->dl_stid); + return NULL; + } + spin_lock_init(&ncn->ncn_lock); + nfsd4_init_cb(&ncn->ncn_cb, dp->dl_stid.sc_client, + &nfsd4_cb_notify_ops, NFSPROC4_CLNT_CB_NOTIFY); + return dp; +} + void nfs4_put_stid(struct nfs4_stid *s) { @@ -3408,6 +3471,30 @@ nfsd4_cb_getattr_release(struct nfsd4_callback *cb) nfs4_put_stid(&dp->dl_stid); } =20 +static int +nfsd4_cb_notify_done(struct nfsd4_callback *cb, + struct rpc_task *task) +{ + switch (task->tk_status) { + case -NFS4ERR_DELAY: + rpc_delay(task, 2 * HZ); + return 0; + default: + return 1; + } +} + +static void +nfsd4_cb_notify_release(struct nfsd4_callback *cb) +{ + struct nfsd4_cb_notify *ncn =3D + container_of(cb, struct nfsd4_cb_notify, ncn_cb); + struct nfs4_delegation *dp =3D + container_of(ncn, struct nfs4_delegation, dl_cb_notify); + + nfs4_put_stid(&dp->dl_stid); +} + static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops =3D { .done =3D nfsd4_cb_recall_any_done, .release =3D nfsd4_cb_recall_any_release, @@ -3420,6 +3507,12 @@ static const struct nfsd4_callback_ops nfsd4_cb_geta= ttr_ops =3D { .opcode =3D OP_CB_GETATTR, }; =20 +static const struct nfsd4_callback_ops nfsd4_cb_notify_ops =3D { + .done =3D nfsd4_cb_notify_done, + .release =3D nfsd4_cb_notify_release, + .opcode =3D OP_CB_NOTIFY, +}; + static void nfs4_cb_getattr(struct nfs4_cb_fattr *ncf) { struct nfs4_delegation *dp =3D @@ -9788,7 +9881,7 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstat= e, =20 /* Try to set up the lease */ status =3D -ENOMEM; - dp =3D alloc_init_deleg(clp, fp, NULL, NFS4_OPEN_DELEGATE_READ); + dp =3D alloc_init_dir_deleg(clp, fp); if (!dp) goto out_delegees; if (cstate->current_fh.fh_export) diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 4fca0537ca8b..ac9dd798ea22 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -197,6 +197,45 @@ struct nfs4_cb_fattr { #define NOTIFY4_EVENT_QUEUE_SIZE 3 #define NOTIFY4_PAGE_ARRAY_SIZE 1 =20 +struct nfsd_notify_event { + refcount_t ne_ref; // refcount + u32 ne_mask; // FS_* mask from fsnotify callback + struct dentry *ne_dentry; // dentry reference to target + u32 ne_namelen; // length of ne_name + char ne_name[]; // name of dentry being changed +}; + +static inline struct nfsd_notify_event *nfsd_notify_event_get(struct nfsd_= notify_event *ne) +{ + refcount_inc(&ne->ne_ref); + return ne; +} + +static inline void nfsd_notify_event_put(struct nfsd_notify_event *ne) +{ + if (refcount_dec_and_test(&ne->ne_ref)) { + dput(ne->ne_dentry); + kfree(ne); + } +} + +/* + * Represents a directory delegation. The callback is for handling CB_NOTI= FYs. + * As notifications from fsnotify come in, allocate a new event, take the = ncn_lock, + * and add it to the ncn_evt queue. The CB_NOTIFY prepare handler will tak= e the + * lock, clean out the list and process it. + */ +struct nfsd4_cb_notify { + spinlock_t ncn_lock; // protects the evt queue and count + int ncn_evt_cnt; // count of events in ncn_evt + int ncn_nf_cnt; // count of valid entries in ncn_nf + struct nfsd_notify_event *ncn_evt[NOTIFY4_EVENT_QUEUE_SIZE]; // list of e= vents + struct page *ncn_pages[NOTIFY4_PAGE_ARRAY_SIZE]; // for encoding + struct notify4 *ncn_nf; // array of notify4's to be sent + bool ncn_encode_err; // did encoding fail? + struct nfsd4_callback ncn_cb; // notify4 callback +}; + /* * Represents a delegation stateid. The nfs4_client holds references to th= ese * and they are put when it is being destroyed or when the delegation is @@ -233,8 +272,12 @@ struct nfs4_delegation { bool dl_written; bool dl_setattr; =20 - /* for CB_GETATTR */ - struct nfs4_cb_fattr dl_cb_fattr; + union { + /* for CB_GETATTR */ + struct nfs4_cb_fattr dl_cb_fattr; + /* for CB_NOTIFY */ + struct nfsd4_cb_notify dl_cb_notify; + }; =20 /* For delegated timestamps */ struct timespec64 dl_atime; --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A9DE34C77AC; Thu, 11 Jun 2026 17:50:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200259; cv=none; b=QR+CwS+3fZlrmWUQj2T4Ec3YWi2aswdwWkHHtSyy97pBbOTvXEr4W9K7QnV96MP89DT5PZthAE8XT5A73AyaApcy5Enw9q5xLOccJ10+AqXzHFhJekaGNZziccgQM5gyiwhjdMUPrTdlR55sygG0HOMB82l5kW71PTI7ZC9Gccs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200259; c=relaxed/simple; bh=inFcxERN9iUd4wibHfn2FqhE/ymdHhFRqouCO3pk2Gw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oWhSuqY9EcmmcyfTWuEP3f7LRT0UEAd7digI5fOTHgYcX1jo9pZBFLdfm4z613+Gx3ei5VCBcTxbMI3rhSGdYJtqhyuRHX6KDL1CyAJhzgxKTf9NOyiJSARz7Hxbqz3svcI9AruPdniatKb3YDNhwXYYmQCPpB/ya5+LFj3S7VA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MyseJYe+; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MyseJYe+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6742C1F00898; Thu, 11 Jun 2026 17:50:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200251; bh=FNo7yNWnumL1I0BSU6dY84CxOjcefnedMkq/tuoe15A=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=MyseJYe+vVTzCeg4PIlH1w8YhgUJR3PSuuI0P3A+jG/OprS2wudZaWNQ5eLZTX8xb wb4oAS1qzE4XOP2joK+JgYyL6aMB6L+wyJyDrZKaY/Bxb58NdqBl1RVBCBZLmdQ/O0 OiPlgRw8RK3z/gRHg2Hun9cRkIQB/JSFR2gbVzrldNya+6soicBQaSgq990+hEJdqp NyY496A5jLcQD1OCx5gohm6g1eoPHQWLEHVhB6DAGOhkQiyuTNOPWwPR/EYNCtHObX 4FJbiyyokshHyyAyZoqJr7XD6iCnp0g5x1yWrhUFQ2rFSgh0LZiXpoKSgoOGhOexsO XBvAA15ZaM/Ig== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:16 -0400 Subject: [PATCH v6 10/20] nfsd: add notification handlers for dir events Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-10-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=28846; i=jlayton@kernel.org; h=from:subject:message-id; bh=inFcxERN9iUd4wibHfn2FqhE/ymdHhFRqouCO3pk2Gw=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVgq0icWYR7wRAuf0OLYs0AG9mFz6FNe+izB hv4m3epyu2JAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1YAAKCRAADmhBGVaC FVgGD/wICE6akJBKPPdPFBT2H3tPE8D91Ri+V0ZhpJjzSpArHUTXR/rKvE+hgFEoizT/CmQA+ZR BVeQdQttC1En9xJkdeA9vUUD2GzkRmb+3yVqPTZzjjjCK21nEoj5PWBclJ7neVB6IbXjrAtQXfr 6uUt8LNKsze++RD8/Tl93JJtMZelQZ2kG/hKVM1eWLZOctrCPRVO0TrpbeILSGollmZfSqf0J4L W4FI5zjq1qqlS8SQykac/PRAQucvhTYAARlmV9Twpev23p0Vvhe7Cm8TlDysPV5xna6rKl+B1XX wN9BVvLfouhOMyUR/GuZdntvAwIq4oHzZ8jrM/pgmyCwUkQpwyQ4lIoBx4CPMcrw+fppRr9lbq3 n4C/g7KlS3kIGW1wbuzVXVd7iUZ3ZlUa2sViCfESUMkqI4X/BU/U6FyP8EnlzPchQ7uo3ahasmH olOSPZIvaOWzDz4rh8qHggaD10pi9tam/PpcZWo75SsaQ6RGigiCq8PWjiIS0JtgzrA1jq1Uehl vOFs6b3GkpP4f5oJe0RAyTX+fPbLpNh6ZrfwwGpTDaT/3C2UTmfFtUE2OXsv53JXkfQF5iuufID 0SZ97O6na1c8wvZDKDX3xMtK2BkwHQywqtIe2KAldKpyRzmWLzkcls0WY12tKMRd3K1BfM0AG1X uCFUaAptq6dqgFg== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Add the necessary parts to accept a fsnotify callback for directory change event and create a CB_NOTIFY request for it. When a dir nfsd_file is created set a handle_event callback to handle the notification. Use that to allocate a nfsd_notify_event object and then hand off a reference to each delegation's CB_NOTIFY. If anything fails along the way, recall any affected delegations. Signed-off-by: Jeff Layton --- fs/nfsd/filecache.c | 70 ++++++++--- fs/nfsd/nfs4callback.c | 54 ++++++++- fs/nfsd/nfs4state.c | 322 +++++++++++++++++++++++++++++++++++++++++++++= ---- fs/nfsd/nfs4xdr.c | 117 ++++++++++++++++++ fs/nfsd/state.h | 20 ++- fs/nfsd/trace.h | 23 ++++ fs/nfsd/xdr4.h | 3 + 7 files changed, 564 insertions(+), 45 deletions(-) diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index c5f2c5768324..b9548eb17c77 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -78,6 +78,7 @@ static struct kmem_cache *nfsd_file_mark_slab; static struct list_lru nfsd_file_lru; static unsigned long nfsd_file_flags; static struct fsnotify_group *nfsd_file_fsnotify_group; +static struct fsnotify_group *nfsd_dir_fsnotify_group; static struct delayed_work nfsd_filecache_laundrette; static struct rhltable nfsd_file_rhltable ____cacheline_aligned_in_smp; @@ -153,7 +154,7 @@ static void nfsd_file_mark_put(struct nfsd_file_mark *nfm) { if (refcount_dec_and_test(&nfm->nfm_ref)) { - fsnotify_destroy_mark(&nfm->nfm_mark, nfsd_file_fsnotify_group); + fsnotify_destroy_mark(&nfm->nfm_mark, nfm->nfm_mark.group); fsnotify_put_mark(&nfm->nfm_mark); } } @@ -161,35 +162,37 @@ nfsd_file_mark_put(struct nfsd_file_mark *nfm) static struct nfsd_file_mark * nfsd_file_mark_find_or_create(struct inode *inode) { - int err; - struct fsnotify_mark *mark; struct nfsd_file_mark *nfm =3D NULL, *new; + struct fsnotify_group *group; + struct fsnotify_mark *mark; + int err; + + group =3D S_ISDIR(inode->i_mode) ? nfsd_dir_fsnotify_group : nfsd_file_fs= notify_group; =20 do { - fsnotify_group_lock(nfsd_file_fsnotify_group); - mark =3D fsnotify_find_inode_mark(inode, - nfsd_file_fsnotify_group); + fsnotify_group_lock(group); + mark =3D fsnotify_find_inode_mark(inode, group); if (mark) { nfm =3D nfsd_file_mark_get(container_of(mark, struct nfsd_file_mark, nfm_mark)); - fsnotify_group_unlock(nfsd_file_fsnotify_group); + fsnotify_group_unlock(group); if (nfm) { fsnotify_put_mark(mark); break; } /* Avoid soft lockup race with nfsd_file_mark_put() */ - fsnotify_destroy_mark(mark, nfsd_file_fsnotify_group); + fsnotify_destroy_mark(mark, group); fsnotify_put_mark(mark); } else { - fsnotify_group_unlock(nfsd_file_fsnotify_group); + fsnotify_group_unlock(group); } =20 /* allocate a new nfm */ new =3D kmem_cache_alloc(nfsd_file_mark_slab, GFP_KERNEL); if (!new) return NULL; - fsnotify_init_mark(&new->nfm_mark, nfsd_file_fsnotify_group); + fsnotify_init_mark(&new->nfm_mark, group); new->nfm_mark.mask =3D FS_ATTRIB|FS_DELETE_SELF; refcount_set(&new->nfm_ref, 1); mutex_init(&new->nfm_recalc_mutex); @@ -830,12 +833,36 @@ nfsd_file_fsnotify_handle_event(struct fsnotify_mark = *mark, u32 mask, return 0; } =20 +#ifdef CONFIG_NFSD_V4 +static int +nfsd_dir_fsnotify_handle_event(struct fsnotify_group *group, u32 mask, + const void *data, int data_type, struct inode *dir, + const struct qstr *name, u32 cookie, + struct fsnotify_iter_info *iter_info) +{ + return nfsd_handle_dir_event(mask, dir, data, data_type, name); +} +#else +static int +nfsd_dir_fsnotify_handle_event(struct fsnotify_group *group, u32 mask, + const void *data, int data_type, struct inode *dir, + const struct qstr *name, u32 cookie, + struct fsnotify_iter_info *iter_info) +{ + return 0; +} +#endif =20 static const struct fsnotify_ops nfsd_file_fsnotify_ops =3D { .handle_inode_event =3D nfsd_file_fsnotify_handle_event, .free_mark =3D nfsd_file_mark_free, }; =20 +static const struct fsnotify_ops nfsd_dir_fsnotify_ops =3D { + .handle_event =3D nfsd_dir_fsnotify_handle_event, + .free_mark =3D nfsd_file_mark_free, +}; + int nfsd_file_cache_init(void) { @@ -887,8 +914,7 @@ nfsd_file_cache_init(void) goto out_shrinker; } =20 - nfsd_file_fsnotify_group =3D fsnotify_alloc_group(&nfsd_file_fsnotify_ops, - 0); + nfsd_file_fsnotify_group =3D fsnotify_alloc_group(&nfsd_file_fsnotify_ops= , 0); if (IS_ERR(nfsd_file_fsnotify_group)) { pr_err("nfsd: unable to create fsnotify group: %ld\n", PTR_ERR(nfsd_file_fsnotify_group)); @@ -897,11 +923,23 @@ nfsd_file_cache_init(void) goto out_notifier; } =20 + nfsd_dir_fsnotify_group =3D fsnotify_alloc_group(&nfsd_dir_fsnotify_ops, = 0); + if (IS_ERR(nfsd_dir_fsnotify_group)) { + pr_err("nfsd: unable to create fsnotify group: %ld\n", + PTR_ERR(nfsd_dir_fsnotify_group)); + ret =3D PTR_ERR(nfsd_dir_fsnotify_group); + nfsd_dir_fsnotify_group =3D NULL; + goto out_notify_group; + } + INIT_DELAYED_WORK(&nfsd_filecache_laundrette, nfsd_file_gc_worker); out: if (ret) clear_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags); return ret; +out_notify_group: + fsnotify_put_group(nfsd_file_fsnotify_group); + nfsd_file_fsnotify_group =3D NULL; out_notifier: lease_unregister_notifier(&nfsd_file_lease_notifier); out_shrinker: @@ -1019,6 +1057,8 @@ nfsd_file_cache_shutdown(void) rcu_barrier(); fsnotify_put_group(nfsd_file_fsnotify_group); nfsd_file_fsnotify_group =3D NULL; + fsnotify_put_group(nfsd_dir_fsnotify_group); + nfsd_dir_fsnotify_group =3D NULL; kmem_cache_destroy(nfsd_file_slab); nfsd_file_slab =3D NULL; fsnotify_wait_marks_destroyed(); @@ -1223,10 +1263,8 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct = net *net, open_file: trace_nfsd_file_alloc(nf); =20 - if (type =3D=3D S_IFREG) - nf->nf_mark =3D nfsd_file_mark_find_or_create(inode); - - if (type !=3D S_IFREG || nf->nf_mark) { + nf->nf_mark =3D nfsd_file_mark_find_or_create(inode); + if (nf->nf_mark) { if (file && (file->f_mode & FMODE_OPENED)) { get_file(file); nf->nf_file =3D file; diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index ca4dd2f969eb..59378751d596 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -892,11 +892,15 @@ static void nfs4_xdr_enc_cb_notify(struct rpc_rqst *r= eq, const void *data) { const struct nfsd4_callback *cb =3D data; + struct nfsd4_cb_notify *ncn =3D container_of(cb, struct nfsd4_cb_notify, = ncn_cb); + struct nfs4_delegation *dp =3D container_of(ncn, struct nfs4_delegation, = dl_cb_notify); struct nfs4_cb_compound_hdr hdr =3D { .ident =3D 0, .minorversion =3D cb->cb_clp->cl_minorversion, }; - struct CB_NOTIFY4args args =3D { }; + struct CB_NOTIFY4args args; + unsigned int start; + __be32 *p; =20 WARN_ON_ONCE(hdr.minorversion =3D=3D 0); =20 @@ -904,13 +908,45 @@ static void nfs4_xdr_enc_cb_notify(struct rpc_rqst *r= eq, encode_cb_sequence4args(xdr, cb, &hdr); =20 /* - * FIXME: get stateid and fh from delegation. Inline the cna_changes - * buffer, and zero it. + * nfsd4_cb_notify_prepare() sized the payload against a single page, + * but did not account for the compound, sequence, stateid, and + * filehandle encoded here. If the variable-length encode overflows the + * backchannel send buffer, roll back to before the operation so that a + * truncated CB_NOTIFY is never placed on the wire. */ - xdrgen_encode_CB_NOTIFY4args(xdr, &args); + start =3D xdr_stream_pos(xdr); + + p =3D xdr_reserve_space(xdr, 4); + if (!p) + goto out_err; + *p =3D cpu_to_be32(OP_CB_NOTIFY); + + args.cna_stateid.seqid =3D dp->dl_stid.sc_stateid.si_generation; + memcpy(&args.cna_stateid.other, &dp->dl_stid.sc_stateid.si_opaque, + ARRAY_SIZE(args.cna_stateid.other)); + args.cna_fh.len =3D dp->dl_stid.sc_file->fi_fhandle.fh_size; + args.cna_fh.data =3D dp->dl_stid.sc_file->fi_fhandle.fh_raw; + args.cna_changes.count =3D ncn->ncn_nf_cnt; + args.cna_changes.element =3D ncn->ncn_nf; + if (!xdrgen_encode_CB_NOTIFY4args(xdr, &args)) + goto out_err; =20 hdr.nops++; encode_cb_nops(&hdr); + return; + +out_err: + /* + * Drop the CB_NOTIFY op and emit a valid CB_SEQUENCE-only compound so + * the client still advances its slot. Flag the failure so the done + * handler recalls the delegation and the missed notification is not + * silently lost. The flag is written here in the transmit path and read + * in the done handler; the two are serialized phases of the same + * rpc_task, so no additional barrier is needed. + */ + ncn->ncn_encode_err =3D true; + xdr_truncate_encode(xdr, start); + encode_cb_nops(&hdr); } =20 static int nfs4_xdr_dec_cb_notify(struct rpc_rqst *rqstp, @@ -1408,6 +1444,16 @@ static void nfsd41_destroy_cb(struct nfsd4_callback = *cb) else clear_bit(NFSD4_CALLBACK_RUNNING, &cb->cb_flags); =20 + /* + * Order the clear of NFSD4_CALLBACK_RUNNING above before the ->release() + * callback below. A release op may re-check producer-side state to decide + * whether to requeue itself (see nfsd4_cb_notify_release()), and that + * check must not be reordered ahead of the clear. The plain clear_bit() + * path carries no ordering; clear_and_wake_up_bit() already issues this + * barrier internally, so the extra one is harmless there. + */ + smp_mb__after_atomic(); + if (cb->cb_ops && cb->cb_ops->release) cb->cb_ops->release(cb); nfsd41_cb_inflight_end(clp); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0a15d7f3b543..513cbc1a583f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -55,6 +55,7 @@ #include "netns.h" #include "pnfs.h" #include "filecache.h" +#include "nfs4xdr_gen.h" #include "trace.h" =20 #define NFSDDBG_FACILITY NFSDDBG_PROC @@ -3471,19 +3472,146 @@ nfsd4_cb_getattr_release(struct nfsd4_callback *cb) nfs4_put_stid(&dp->dl_stid); } =20 +static void nfsd_break_one_deleg(struct nfs4_delegation *dp) +{ + bool queued; + + if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags)) + return; + + /* + * We're assuming the state code never drops its reference + * without first removing the lease. Since we're in this lease + * callback (and since the lease code is serialized by the + * flc_lock) we know the server hasn't removed the lease yet, and + * we know it's safe to take a reference. + */ + refcount_inc(&dp->dl_stid.sc_count); + queued =3D nfsd4_run_cb(&dp->dl_recall); + WARN_ON_ONCE(!queued); + if (!queued) { + refcount_dec(&dp->dl_stid.sc_count); + clear_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags); + } +} + +static bool +nfsd4_cb_notify_prepare(struct nfsd4_callback *cb) +{ + struct nfsd4_cb_notify *ncn =3D container_of(cb, struct nfsd4_cb_notify, = ncn_cb); + struct nfs4_delegation *dp =3D container_of(ncn, struct nfs4_delegation, = dl_cb_notify); + struct nfsd_notify_event *events[NOTIFY4_EVENT_QUEUE_SIZE]; + struct xdr_buf xdr =3D { .buflen =3D PAGE_SIZE * NOTIFY4_PAGE_ARRAY_SIZE, + .pages =3D ncn->ncn_pages }; + struct xdr_stream stream; + struct nfsd_file *nf; + int count, i; + bool error =3D false; + + xdr_init_encode_pages(&stream, &xdr); + + spin_lock(&ncn->ncn_lock); + count =3D ncn->ncn_evt_cnt; + + /* spurious queueing? */ + if (count =3D=3D 0) { + spin_unlock(&ncn->ncn_lock); + return false; + } + + /* we can't keep up! */ + if (count > NOTIFY4_EVENT_QUEUE_SIZE) { + spin_unlock(&ncn->ncn_lock); + goto out_recall; + } + + memcpy(events, ncn->ncn_evt, sizeof(*events) * count); + ncn->ncn_evt_cnt =3D 0; + spin_unlock(&ncn->ncn_lock); + + rcu_read_lock(); + nf =3D nfsd_file_get(rcu_dereference(dp->dl_stid.sc_file->fi_deleg_file)); + rcu_read_unlock(); + if (!nf) { + for (i =3D 0; i < count; ++i) + nfsd_notify_event_put(events[i]); + goto out_recall; + } + + for (i =3D 0; i < count; ++i) { + struct nfsd_notify_event *nne =3D events[i]; + + if (!error) { + u32 *maskp =3D (u32 *)xdr_reserve_space(&stream, sizeof(*maskp)); + u8 *p; + + if (!maskp) { + error =3D true; + goto put_event; + } + + p =3D nfsd4_encode_notify_event(&stream, nne, dp, nf, maskp); + if (!p) { + pr_notice("Could not generate CB_NOTIFY from fsnotify mask 0x%x\n", + nne->ne_mask); + error =3D true; + goto put_event; + } + + ncn->ncn_nf[i].notify_mask.count =3D 1; + ncn->ncn_nf[i].notify_mask.element =3D maskp; + ncn->ncn_nf[i].notify_vals.data =3D p; + ncn->ncn_nf[i].notify_vals.len =3D (u8 *)stream.p - p; + } +put_event: + nfsd_notify_event_put(nne); + } + if (!error) { + ncn->ncn_nf_cnt =3D count; + nfsd_file_put(nf); + return true; + } + nfsd_file_put(nf); +out_recall: + nfsd_break_one_deleg(dp); + return false; +} + static int nfsd4_cb_notify_done(struct nfsd4_callback *cb, struct rpc_task *task) { + struct nfsd4_cb_notify *ncn =3D container_of(cb, struct nfsd4_cb_notify, = ncn_cb); + struct nfs4_delegation *dp =3D container_of(ncn, struct nfs4_delegation, = dl_cb_notify); + + if (dp->dl_stid.sc_status) + return 1; + + /* + * The CB_NOTIFY op overflowed the send buffer and was dropped from the + * compound. The notification is lost, so recall the delegation rather + * than leaving the client unaware of the directory change. + */ + if (ncn->ncn_encode_err) { + nfsd_break_one_deleg(dp); + return 1; + } + switch (task->tk_status) { case -NFS4ERR_DELAY: rpc_delay(task, 2 * HZ); return 0; default: + /* For any other hard error, recall the deleg */ + nfsd_break_one_deleg(dp); + fallthrough; + case 0: return 1; } } =20 +static void nfsd4_run_cb_notify(struct nfsd4_cb_notify *ncn); + static void nfsd4_cb_notify_release(struct nfsd4_callback *cb) { @@ -3492,6 +3620,9 @@ nfsd4_cb_notify_release(struct nfsd4_callback *cb) struct nfs4_delegation *dp =3D container_of(ncn, struct nfs4_delegation, dl_cb_notify); =20 + /* Drain events that arrived while this callback was in flight */ + if (READ_ONCE(ncn->ncn_evt_cnt) > 0) + nfsd4_run_cb_notify(ncn); nfs4_put_stid(&dp->dl_stid); } =20 @@ -3508,6 +3639,7 @@ static const struct nfsd4_callback_ops nfsd4_cb_getat= tr_ops =3D { }; =20 static const struct nfsd4_callback_ops nfsd4_cb_notify_ops =3D { + .prepare =3D nfsd4_cb_notify_prepare, .done =3D nfsd4_cb_notify_done, .release =3D nfsd4_cb_notify_release, .opcode =3D OP_CB_NOTIFY, @@ -5767,29 +5899,6 @@ static const struct nfsd4_callback_ops nfsd4_cb_reca= ll_ops =3D { .opcode =3D OP_CB_RECALL, }; =20 -static void nfsd_break_one_deleg(struct nfs4_delegation *dp) -{ - bool queued; - - if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags)) - return; - - /* - * We're assuming the state code never drops its reference - * without first removing the lease. Since we're in this lease - * callback (and since the lease code is serialized by the - * flc_lock) we know the server hasn't removed the lease yet, and - * we know it's safe to take a reference. - */ - refcount_inc(&dp->dl_stid.sc_count); - queued =3D nfsd4_run_cb(&dp->dl_recall); - WARN_ON_ONCE(!queued); - if (!queued) { - refcount_dec(&dp->dl_stid.sc_count); - clear_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags); - } -} - /* Called from break_lease() with flc_lock held. */ static bool nfsd_break_deleg_cb(struct file_lease *fl) @@ -9969,3 +10078,170 @@ void nfsd_update_cmtime_attr(struct file *f, unsig= ned int flags) MINOR(inode->i_sb->s_dev), inode->i_ino, ret); } + +static void +nfsd4_run_cb_notify(struct nfsd4_cb_notify *ncn) +{ + struct nfs4_delegation *dp =3D container_of(ncn, struct nfs4_delegation, = dl_cb_notify); + + if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &ncn->ncn_cb.cb_flags)) + return; + + if (!refcount_inc_not_zero(&dp->dl_stid.sc_count)) + clear_bit(NFSD4_CALLBACK_RUNNING, &ncn->ncn_cb.cb_flags); + else + nfsd4_run_cb(&ncn->ncn_cb); +} + +static struct nfsd_notify_event * +alloc_nfsd_notify_event(u32 mask, const struct qstr *q, struct dentry *den= try, + struct inode *target) +{ + struct nfsd_notify_event *ne; + struct name_snapshot newname; + u32 newnamelen =3D 0; + + /* + * For a rename, @q is the old name and the live dentry carries the new + * name. Snapshot the new name now, while it is guaranteed to describe + * this event: the dentry can be renamed again before the CB_NOTIFY work + * runs, which would corrupt a late read in nfsd4_encode_notify_event(). + */ + if (mask & FS_RENAME) { + take_dentry_name_snapshot(&newname, dentry); + newnamelen =3D newname.name.len; + } + + ne =3D kmalloc(struct_size(ne, ne_name, q->len + 1 + + (newnamelen ? newnamelen + 1 : 0)), GFP_NOFS); + if (!ne) + goto out; + + memcpy(ne->ne_name, q->name, q->len); + ne->ne_name[q->len] =3D '\0'; + ne->ne_namelen =3D q->len; + + ne->ne_newnamelen =3D newnamelen; + if (newnamelen) { + char *p =3D nfsd_notify_event_newname(ne); + + memcpy(p, newname.name.name, newnamelen); + p[newnamelen] =3D '\0'; + } + + refcount_set(&ne->ne_ref, 1); + ne->ne_mask =3D mask; + ne->ne_dentry =3D dget(dentry); + ne->ne_target =3D target; + if (ne->ne_target) + ihold(ne->ne_target); +out: + if (mask & FS_RENAME) + release_dentry_name_snapshot(&newname); + return ne; +} + +static bool +should_notify_deleg(u32 mask, struct file_lease *fl) +{ + /* Don't notify the client generating the event */ + if (nfsd_breaker_owns_lease(fl)) + return false; + + /* Skip if this event wasn't ignored by the lease */ + if ((mask & FS_DELETE) && !(fl->c.flc_flags & FL_IGN_DIR_DELETE)) + return false; + if ((mask & FS_CREATE) && !(fl->c.flc_flags & FL_IGN_DIR_CREATE)) + return false; + if ((mask & FS_RENAME) && !(fl->c.flc_flags & FL_IGN_DIR_RENAME)) + return false; + + return true; +} + +static void +nfsd_recall_all_dir_delegs(const struct inode *dir) +{ + struct file_lock_context *ctx =3D locks_inode_context(dir); + struct file_lock_core *flc; + + spin_lock(&ctx->flc_lock); + list_for_each_entry(flc, &ctx->flc_lease, flc_list) { + struct file_lease *fl =3D container_of(flc, struct file_lease, c); + + if (fl->fl_lmops =3D=3D &nfsd_lease_mng_ops) + nfsd_break_deleg_cb(fl); + } + spin_unlock(&ctx->flc_lock); +} + +int +nfsd_handle_dir_event(u32 mask, const struct inode *dir, const void *data, + int data_type, const struct qstr *name) +{ + struct dentry *dentry =3D fsnotify_data_dentry(data, data_type); + struct inode *target =3D fsnotify_data_rename_target(data, data_type); + struct file_lock_context *ctx; + struct file_lock_core *flc; + struct nfsd_notify_event *evt; + + trace_nfsd_handle_dir_event(mask, dir, name); + + /* Normalize cross-dir rename events to create/delete */ + if (mask & FS_MOVED_FROM) { + mask &=3D ~FS_MOVED_FROM; + mask |=3D FS_DELETE; + } + if (mask & FS_MOVED_TO) { + mask &=3D ~FS_MOVED_TO; + mask |=3D FS_CREATE; + } + + /* + * FS_RENAME fires on the source directory even for a cross-dir + * rename, where the moved entry now lives under a different parent. + * NOTIFY4_RENAME_ENTRY describes an in-place rename, so reporting it + * here would advertise a name absent from this directory. + */ + if ((mask & FS_RENAME) && dentry && d_inode(dentry->d_parent) !=3D dir) + mask &=3D ~FS_RENAME; + + /* Don't do anything if this is not an expected event */ + if (!(mask & (FS_CREATE|FS_DELETE|FS_RENAME))) + return 0; + + ctx =3D locks_inode_context(dir); + if (!ctx || list_empty(&ctx->flc_lease)) + return 0; + + evt =3D alloc_nfsd_notify_event(mask, name, dentry, target); + if (!evt) { + nfsd_recall_all_dir_delegs(dir); + return 0; + } + + spin_lock(&ctx->flc_lock); + list_for_each_entry(flc, &ctx->flc_lease, flc_list) { + struct file_lease *fl =3D container_of(flc, struct file_lease, c); + struct nfs4_delegation *dp =3D flc->flc_owner; + struct nfsd4_cb_notify *ncn =3D &dp->dl_cb_notify; + + if (!should_notify_deleg(mask, fl)) + continue; + + spin_lock(&ncn->ncn_lock); + if (ncn->ncn_evt_cnt >=3D NOTIFY4_EVENT_QUEUE_SIZE) { + /* We're generating notifications too fast. Recall. */ + spin_unlock(&ncn->ncn_lock); + nfsd_break_deleg_cb(fl); + continue; + } + ncn->ncn_evt[ncn->ncn_evt_cnt++] =3D nfsd_notify_event_get(evt); + spin_unlock(&ncn->ncn_lock); + + nfsd4_run_cb_notify(ncn); + } + spin_unlock(&ctx->flc_lock); + nfsd_notify_event_put(evt); + return 0; +} diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b9037d99b564..c6f92ddeb449 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4185,6 +4185,123 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct = xdr_stream *xdr, goto out; } =20 +static bool +nfsd4_setup_notify_entry4(struct notify_entry4 *ne, struct xdr_stream *xdr, + struct dentry *dentry, struct nfs4_delegation *dp, + struct nfsd_file *nf, char *name, u32 namelen) +{ + uint32_t *attrmask; + + /* Reserve space for attrmask */ + attrmask =3D xdr_reserve_space(xdr, 3 * sizeof(uint32_t)); + if (!attrmask) + return false; + + ne->ne_file.data =3D name; + ne->ne_file.len =3D namelen; + ne->ne_attrs.attrmask.element =3D attrmask; + + attrmask[0] =3D 0; + attrmask[1] =3D 0; + attrmask[2] =3D 0; + ne->ne_attrs.attr_vals.data =3D NULL; + ne->ne_attrs.attr_vals.len =3D 0; + ne->ne_attrs.attrmask.count =3D 1; + return true; +} + +/** + * nfsd4_encode_notify_event - encode a notify + * @xdr: stream to which to encode the fattr4 + * @nne: nfsd_notify_event to encode + * @dp: delegation where the event occurred + * @nf: nfsd_file on which event occurred + * @notify_mask: pointer to word where notification mask should be set + * + * Encode @nne into @xdr. The matching bit in @notify_mask is set on + * success. + * + * Return: pointer to the start of the encoded event, or NULL if the + * event could not be encoded. + */ +u8 *nfsd4_encode_notify_event(struct xdr_stream *xdr, struct nfsd_notify_e= vent *nne, + struct nfs4_delegation *dp, struct nfsd_file *nf, + u32 *notify_mask) +{ + u8 *p =3D NULL; + + *notify_mask =3D 0; + + if (nne->ne_mask & FS_DELETE) { + struct notify_remove4 nr =3D { }; + + if (!nfsd4_setup_notify_entry4(&nr.nrm_old_entry, xdr, nne->ne_dentry, d= p, + nf, nne->ne_name, nne->ne_namelen)) + goto out_err; + p =3D (u8 *)xdr->p; + if (!xdrgen_encode_notify_remove4(xdr, &nr)) + goto out_err; + *notify_mask |=3D BIT(NOTIFY4_REMOVE_ENTRY); + } else if (nne->ne_mask & FS_CREATE) { + struct notify_add4 na =3D { }; + struct notify_remove4 old =3D { }; + + if (!nfsd4_setup_notify_entry4(&na.nad_new_entry, xdr, nne->ne_dentry, d= p, + nf, nne->ne_name, nne->ne_namelen)) + goto out_err; + + /* If a file was overwritten, report it in nad_old_entry */ + if (nne->ne_target) { + if (!nfsd4_setup_notify_entry4(&old.nrm_old_entry, xdr, + NULL, dp, nf, + nne->ne_name, nne->ne_namelen)) + goto out_err; + na.nad_old_entry.count =3D 1; + na.nad_old_entry.element =3D &old; + } + + p =3D (u8 *)xdr->p; + if (!xdrgen_encode_notify_add4(xdr, &na)) + goto out_err; + + *notify_mask |=3D BIT(NOTIFY4_ADD_ENTRY); + } else if (nne->ne_mask & FS_RENAME) { + struct notify_rename4 nr =3D { }; + struct notify_remove4 old =3D { }; + char *newname =3D nfsd_notify_event_newname(nne); + + /* Don't send any attributes in the old_entry since they're the same in = new */ + if (!nfsd4_setup_notify_entry4(&nr.nrn_old_entry.nrm_old_entry, xdr, + NULL, dp, nf, nne->ne_name, + nne->ne_namelen)) + goto out_err; + + if (!nfsd4_setup_notify_entry4(&nr.nrn_new_entry.nad_new_entry, xdr, + nne->ne_dentry, dp, nf, newname, + nne->ne_newnamelen)) + goto out_err; + + /* If a file was overwritten, report it in nad_old_entry */ + if (nne->ne_target) { + if (!nfsd4_setup_notify_entry4(&old.nrm_old_entry, xdr, + NULL, dp, nf, newname, + nne->ne_newnamelen)) + goto out_err; + nr.nrn_new_entry.nad_old_entry.count =3D 1; + nr.nrn_new_entry.nad_old_entry.element =3D &old; + } + + p =3D (u8 *)xdr->p; + if (!xdrgen_encode_notify_rename4(xdr, &nr)) + goto out_err; + *notify_mask |=3D BIT(NOTIFY4_RENAME_ENTRY); + } + return p; +out_err: + pr_warn("nfsd: unable to marshal notify event to xdr stream\n"); + return NULL; +} + static void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p, int bytes) { diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index ac9dd798ea22..f8457e0f2b57 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -201,10 +201,23 @@ struct nfsd_notify_event { refcount_t ne_ref; // refcount u32 ne_mask; // FS_* mask from fsnotify callback struct dentry *ne_dentry; // dentry reference to target - u32 ne_namelen; // length of ne_name - char ne_name[]; // name of dentry being changed + struct inode *ne_target; // inode overwritten by rename, or NULL + u32 ne_namelen; // length of ne_name (old name for a rename) + u32 ne_newnamelen; // length of new name (rename only), else 0 + char ne_name[]; // entry name, then new name (rename only) }; =20 +/* + * For a rename, the new name is snapshotted at event-alloc time and stored + * immediately after the (NUL-terminated) old name in ne_name[]. ne_dentry= can + * be renamed again before the CB_NOTIFY work runs, so the new name must n= ot be + * read from the live dentry at encode time. + */ +static inline char *nfsd_notify_event_newname(struct nfsd_notify_event *ne) +{ + return ne->ne_name + ne->ne_namelen + 1; +} + static inline struct nfsd_notify_event *nfsd_notify_event_get(struct nfsd_= notify_event *ne) { refcount_inc(&ne->ne_ref); @@ -214,6 +227,7 @@ static inline struct nfsd_notify_event *nfsd_notify_eve= nt_get(struct nfsd_notify static inline void nfsd_notify_event_put(struct nfsd_notify_event *ne) { if (refcount_dec_and_test(&ne->ne_ref)) { + iput(ne->ne_target); dput(ne->ne_dentry); kfree(ne); } @@ -901,6 +915,8 @@ void nfsd_update_cmtime_attr(struct file *f, unsigned i= nt flags); extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netob= j name, struct xdr_netobj princhash, struct nfsd_net *nn); extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_n= et *nn); +int nfsd_handle_dir_event(u32 mask, const struct inode *dir, const void *d= ata, + int data_type, const struct qstr *name); =20 void put_nfs4_file(struct nfs4_file *fi); extern void nfs4_put_cpntf_state(struct nfsd_net *nn, diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 171e8fdbafb6..db0a0dc70660 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include =20 @@ -1377,6 +1378,28 @@ TRACE_EVENT(nfsd_file_fsnotify_handle_event, __entry->nlink, __entry->mode, __entry->mask) ); =20 +TRACE_EVENT(nfsd_handle_dir_event, + TP_PROTO(u32 mask, const struct inode *dir, const struct qstr *name), + TP_ARGS(mask, dir, name), + TP_STRUCT__entry( + __field(u32, mask) + __field(dev_t, s_dev) + __field(u64, i_ino) + __string_len(name, name ? name->name : NULL, + name ? name->len : 0) + ), + TP_fast_assign( + __entry->mask =3D mask; + __entry->s_dev =3D dir ? dir->i_sb->s_dev : 0; + __entry->i_ino =3D dir ? dir->i_ino : 0; + __assign_str(name); + ), + TP_printk("inode=3D0x%x:0x%x:0x%llx mask=3D%s name=3D%s", + MAJOR(__entry->s_dev), MINOR(__entry->s_dev), + __entry->i_ino, show_fsnotify_mask(__entry->mask), + __get_str(name)) +); + DECLARE_EVENT_CLASS(nfsd_file_gc_class, TP_PROTO( const struct nfsd_file *nf diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 85574b2a139a..62ac790428be 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -970,6 +970,9 @@ __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words, struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, u32 *bmval, struct svc_rqst *, int ignore_crossmnt); +u8 *nfsd4_encode_notify_event(struct xdr_stream *xdr, struct nfsd_notify_e= vent *nne, + struct nfs4_delegation *dd, struct nfsd_file *nf, + u32 *notify_mask); extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *, union nfsd4_op_u *u); extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF2424C900D; Thu, 11 Jun 2026 17:50:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200258; cv=none; b=tMN9YtnzaRefH0yVRPoNMcDs330mJHyUex+Kl+ZQxE+ae0TraFaIb3xTy+wPLH5VRpa22aC+COm1GVFNfQjQ+vnfq0AoRNkacmQBQxmtT1gP6joRaRrBzabqC/2NuTTlz8RGJ8/mAQzbfnzGm26NJR71Af/Py0GCiW68EABI2EI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200258; c=relaxed/simple; bh=802r4p+1lz5i5jQlOrwFPXxz63QK2Wr4Z/HExsacQjc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oeylPE7OhlIWPHM6Y/QBh4TXEvgqoSSu6OD/O/oXLk0TdClMrBJXbPo144qDvS+qH6Cz6BYM+wboSGGVioQK13HpvMbQBJ73VolZSD2/s9pBT6Rs3jbSBzVyBo+Zctz4KuzjnMOTRDPe6sLhRR+klreMIL0Az2WZs39V+sOXyfM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fIjgw4+e; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fIjgw4+e" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 504F11F0089B; Thu, 11 Jun 2026 17:50:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200253; bh=miYBZIfyo1Ir05EQXD379kBMccvvIIFxC/NAks/UKAs=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=fIjgw4+eXOeIQrn5Xg403U8kaqrrUQ9x6mgA0iaqEnv35n5j3uiZrqEhq3E8bwgcb 3YWiAcWpf35YwbkoJkwRiTPK/U8fNrhOc7dYXAeq8Mv9EOY4VNqzzDg/P1vEyp05Np 8ouGnUlWNOrdQ5+8nDqLl5/nbRnmADkP3+oznxwgLoJvK/OalHFAWl1uhc0CtiQfJt 09qh2qUnjBrJRQ4vA8QgOoX/rOe30igRtYrjGajHOdugigJsT78Bi2K7lqByJ5DCkt zRAN6vIQ6kWlkI+kkY1F3koxcZA3UpEg+57OBaSBK9mturYCOdRjEC1CE7vFTBdd53 PTBqGUzpv04gg== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:17 -0400 Subject: [PATCH v6 11/20] nfsd: apply the notify mask to the delegation when requested Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-11-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1720; i=jlayton@kernel.org; h=from:subject:message-id; bh=802r4p+1lz5i5jQlOrwFPXxz63QK2Wr4Z/HExsacQjc=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVhSEkNhvFe4tdhj1qAHb2xP21odVdtxsOg2 AAtNQXPsWiJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1YQAKCRAADmhBGVaC FaWaEADR+7D0Jlgc7HJIo9Un89DX/bKM9pYZ6iAj0pu3uHn6wT13/F/l69KekieIA/dEV+zrT1T X0YgbH+UxsThnKsrgERoUi8MkzVra/PfwgkUc3SRqpXv4Gq2qNLH87R6rCSQ7gMI39LAXmr2BaR 7uOQ+Fmfaymbvk1MrjE9E4B6u4ZJZ6umebr03iVs/GJoQTFWNgzdrB/0PVkL48bTHlHh/SKgHSq 7NOSmuedIyY0NesTbA4mbM2TXH6c7Ar4vR7rpDMxtruJ+OcYp5LeZ6IevDzt+TCq7DSDsYR+9h4 k8T4IbfrRwXpJqn2AIK2OV2nXCbU1NQDZrNFFn6Kf06tgI5+CXgjeM3YplHYgCt1e8ZlfdhPhoC 2cHSQtYGou7mTcp965vwHE4JNqg8RaFfiG5EE5g38WRFsmwfnYDkGnuXVAZOVmwWMQLVcvDVR/t CcIF4UM+PNPThONCqcNMpIm+ZKVPjTJiI6rh0H0ty/AEuBDcXKKtE0Gi7evUzVMYx+3QlBYl0Uv M4Qg36OV7wHBfPmkiSEep7ZC28uvMPEJ7fUTNX6r5ZekTeIbLySx7Hhbcy8rNwAVbhp8KTaW/vo B5ymplToOjdmNWac7PQriw12heM7FhkG42wQQUHskDe8PfktqOhH4shWE3mTVrYvMGF1ee+1ylT l+aKAAveuJJU/Gw== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 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. 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. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4proc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 0c37d7c6d28c..29f7339dc220 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2530,12 +2530,18 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_c= ompound_state *cstate, return status =3D=3D nfserr_same ? nfs_ok : status; } =20 +#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 =3D &u->get_dir_delegation; + u32 requested =3D gdd->gdda_notification_types[0]; struct nfs4_delegation *dd; struct nfsd_file *nf; __be32 status; @@ -2544,6 +2550,12 @@ nfsd4_get_dir_delegation(struct svc_rqst *rqstp, if (status !=3D nfs_ok) return status; =20 + /* No notifications if you don't set NOTIFY4_GFLAG_EXTEND! */ + if (!(requested & BIT(NOTIFY4_GFLAG_EXTEND))) + requested =3D 0; + + gdd->gddr_notification[0] =3D requested & SUPPORTED_NOTIFY_MASK; + /* * RFC 8881, section 18.39.3 says: * --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E3E54C9554; Thu, 11 Jun 2026 17:50:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200260; cv=none; b=JUQbLc15KLA8lxFTkMz9UhFJ9+vWzPHtfQWH6mg2JvptW5Q5e9BTKOANKpZ/XDc96rGkerhox9x+PMF2GXPTGi5BSq0Tu9YZRWqAah561A4T5Ob1oU/zPQJjOz8qkhZH5QKaCROIz4LwsYt7ao9L+gPEqNkYRf6joqlL49MGc+4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200260; c=relaxed/simple; bh=wGyTokg3GKElfqJgrUe3TxVbVZk4gjS9Piw+ozcUGeY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Vhrier1hM9QoHhx5iViy7yaZ8hEsFdxrDrO/Tw/zHxKRJRz0dwg3jAab9cGJaPxKkJHpCqwfvGKIP25EF8X2dD8x2NKKNiYZM6LZyn5N2P1VEu4jZYPPlyGC3diraAqeN0uIkZp7JweGJaa/LVs2gkkDf/aD3IvtQ4ddtmyjFr4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=h3/hvpXS; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="h3/hvpXS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 375831F00899; Thu, 11 Jun 2026 17:50:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200254; bh=boUS2uP29CUMjPXaPJlVrj6lCotQJXHMxNRB/47GSTo=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=h3/hvpXSuyz1eMKbduGBKbrW7a1r/0RHY/SB62k3V6soxSaSWR1vG3187Yn57+vcX Q+XLwecaOFUOdC0Eao3gFzWJmwKkj3gVVrHTe5xuNI++59gy0pUyCt1ED8rr+vBj7p mM9w6EXBrUOqkjS6womUAb3u9zQoU4gdCW2Z3+m1H9mDpFs4MQJBAvU6JnyG2o78T8 9GsAI/FTSBaBAWNl6/2WhOP0ARA3rfmcOD/Qr9eTI5ljmPEwmGDv/sndBgHz/GtmI3 dcHWuTc0CSNH7t3p5rl4oKVcz63Ukd7xaebMGg/iP5rGsiWPJvAXRr7/HhpZM9wPNL zbVkcusxi9r/w== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:18 -0400 Subject: [PATCH v6 12/20] nfsd: add helper to marshal a fattr4 from completed args Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-12-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3412; i=jlayton@kernel.org; h=from:subject:message-id; bh=wGyTokg3GKElfqJgrUe3TxVbVZk4gjS9Piw+ozcUGeY=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVh2+hnPzb54Y1u398dAJ+ySepQoggcUsADU pSr3qrxoSuJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1YQAKCRAADmhBGVaC FaSrD/9VLU61VA/Hq5PrCVRw1JMz099EAQfnA6XLVwJn51G/MfcCJPa2eSd/er+8ljjjZ6pYpZr YJbxiOvaF6bOLhTwPBWOEuu9F5Y+xlhSCx6LdqfYXZUMeTsXpJoF59PBwBhno3mpSE2u2vGdq10 y1lIctNZ2Eczm+qAvcNvxkCFEB4oQUwPdWYYYgDjiduZdr7Zwq7ncIrvmbfVdcs8S+Mahc8eiTm Anxiy1WHvG6s+MR4ryXHXRy/eAlYJVQahauPbj1aGXGrv643EJ6HVGHE7SMZZRhzERWAaSnFEoi Hvfre3sHLxdAQk8XbHwuca5udSTQNUHIW3rOWKjzaQfMQJm/Jj5GyBJeQb2M/XlE3tjrDDeDz8n ptIOlSLAqSieZoJQf4b6DhCE/Z1Rtcmik7EQw71ZTtYoOb2y+wbyAxNQzA7Q3lShkO0o+gg65Vh /z7bIyb3UtxYG3pb6METPlnTvXvpS4AqQqKsnuzNVjCgVM/yFAsuoM2VG+OdTJRBTxnlSTCaUyw LxrY0AYTW1gEYl6e3D3/vHFtcqm32VHtXG9IgipMI49KaYbdziffDfXZkJE3b+XGkFJgGu5lnbx 3bCZ5+oRNWCT/eQTyMjR37cs8ZXbWb8UrWZyaGxAodM9DHL4KTSDgejLIM/ri3YhKtGxT613Sg+ TG3ZWuu31vDvILw== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Break the loop that encodes the actual attr_vals field into a separate function. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4xdr.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c6f92ddeb449..7d162e5fb6ec 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3895,6 +3895,22 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_= ops[] =3D { #endif }; =20 +static __be32 +nfsd4_encode_attr_vals(struct xdr_stream *xdr, u32 *attrmask, struct nfsd4= _fattr_args *args) +{ + DECLARE_BITMAP(attr_bitmap, ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)); + unsigned long bit; + __be32 status; + + bitmap_from_arr32(attr_bitmap, attrmask, ARRAY_SIZE(nfsd4_enc_fattr4_enco= de_ops)); + for_each_set_bit(bit, attr_bitmap, ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops= )) { + status =3D nfsd4_enc_fattr4_encode_ops[bit](xdr, args); + if (status !=3D nfs_ok) + return status; + } + return nfs_ok; +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the file= handle * ourselves. @case_cache is NULL for callers that encode a single dentry @@ -3908,7 +3924,6 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xd= r_stream *xdr, int ignore_crossmnt, struct nfsd_case_attrs_cache *case_cache) { - DECLARE_BITMAP(attr_bitmap, ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)); struct nfs4_delegation *dp =3D NULL; struct nfsd4_fattr_args args; struct svc_fh *tempfh =3D NULL; @@ -3923,7 +3938,6 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xd= r_stream *xdr, .mnt =3D exp->ex_path.mnt, .dentry =3D dentry, }; - unsigned long bit; =20 WARN_ON_ONCE(bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1); WARN_ON_ONCE(!nfsd_attrs_supported(minorversion, bmval)); @@ -4137,27 +4151,22 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct = xdr_stream *xdr, #endif /* CONFIG_NFSD_V4_POSIX_ACLS */ =20 /* attrmask */ - status =3D nfsd4_encode_bitmap4(xdr, attrmask[0], attrmask[1], - attrmask[2]); + status =3D nfsd4_encode_bitmap4(xdr, attrmask[0], attrmask[1], attrmask[2= ]); if (status) goto out; =20 /* attr_vals */ attrlen_offset =3D xdr->buf->len; - if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT))) - goto out_resource; - bitmap_from_arr32(attr_bitmap, attrmask, - ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)); - for_each_set_bit(bit, attr_bitmap, - ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)) { - status =3D nfsd4_enc_fattr4_encode_ops[bit](xdr, &args); - if (status !=3D nfs_ok) - goto out; + if (unlikely(!xdr_reserve_space(xdr, XDR_UNIT))) { + status =3D nfserr_resource; + goto out; } - attrlen =3D cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT); - write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, XDR_UNIT); - status =3D nfs_ok; =20 + status =3D nfsd4_encode_attr_vals(xdr, attrmask, &args); + if (status =3D=3D nfs_ok) { + attrlen =3D cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT); + write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, XDR_UNIT); + } out: #ifdef CONFIG_NFSD_V4_POSIX_ACLS if (args.dpacl) @@ -4180,9 +4189,6 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xd= r_stream *xdr, out_nfserr: status =3D nfserrno(err); goto out; -out_resource: - status =3D nfserr_resource; - goto out; } =20 static bool --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 574C04C957F; Thu, 11 Jun 2026 17:50:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200261; cv=none; b=orPaTLAcQZgvpd4LhbOi0hlDb0sUSbcDgKaOtGwXw4vLLDox2v5X5PwFd5/eM2vudmVYS4xw47UzEMHhibQo0cWJACAzOkhmCS94kz/gKN+4kViMGP8W0ylAxI6cmUBBzQRW45Mxv0q5ebe9u9mG0ThAUVbYJJy8rk1MPs6+FP0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200261; c=relaxed/simple; bh=SeZUHcpxYlvG88yAy9B42bUe1TCQHy1VujzGUXl1RxQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GyhGO0cpxcbEa1PJ095YBlfwjR7lS2zofX98CVvg7QqO9vav+gP4Kp8WaIsWkW3BEQF6LR43w0OI3Skf2mmCU92eT+pD8K9K6GYt2QNJfWV6JLpYs9UfVcpx3NxAtjNtDD8t3X7l3pZH2IzOihBwtFb+SNO8DSFyUR2UgZDF/uk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mP/C6hjg; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mP/C6hjg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1EF951F0089A; Thu, 11 Jun 2026 17:50:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200256; bh=dmd0f6pbCz4d5WUptOFm0ECwKoGxHEd52JM8lI1jNZ8=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=mP/C6hjgRsLe/7m4DiopSQa/UmIq+nSvRbwcLAdCwsr1ruOw7Eo7Rfpg/6YWwc2DY qBsjF/vX6YsfSbK3HvyPiJ5lyQOYXgYvYUNV0lZpPn2e/t24kbmyZYA9ajLlnerGVx sGGG1YYGKkxsXl3Hpi7mp55FoHDnoFfFYtIanOVYL16pMAGeF2mRSykI02RbSn2E1f s2+119KeywAnGRNtfcxAZb7mTFV3KKFedpAGLgNRkyGWOi0iLIMzLTkCVZ5AajoA3f XndOavrb1YAa+Zjz+A8dIs5T7y/CR3N2eQbd1laSioqkc6bIARYfL87eKSwPyNvbqh 70EGo/KTvBhTA== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:19 -0400 Subject: [PATCH v6 13/20] nfsd: allow nfsd4_encode_fattr4_change() to work with no export Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-13-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=846; i=jlayton@kernel.org; h=from:subject:message-id; bh=SeZUHcpxYlvG88yAy9B42bUe1TCQHy1VujzGUXl1RxQ=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvViloBuCoWXKJAgwh5cjzQvC5hw5bEcN9rRM CEJat0HYS+JAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1YgAKCRAADmhBGVaC FcdrEACDmx4r+qzIF8nMXEnogkt5PnwCsrUgUash/2mQZ2LFdoECpmj3B4iNC68R8L+nn5bLzCS Rax9muOfzwTWNx8J7OGz4jlUbI3gZDwdhCYqMFLGINmW4m2mnmeFtQNV5J4POK0XqiHzqKpTHFy n3ApKUNgZ9H2B6vsrLy11lsHvs/SrJqtpp2AcWlXwIVuYY7RYz8201Q9ZFBLd/+cRxXOH2LeZ00 CkHhf+YY9v2KeVHc9nGX+sCaWOCKIXj8azHqacnIs34+NC1Vf8XuQspi8TE8vntR4vCRHZXfHUI 0sLZ7CGTAr29FIR4ha/Q3kz8v8SrGPxJHppDeVauInwKEpVDXJK44OdDa6cVbJ0T5ZBXH807VAU EH77GFU4h33fXfwyHpAariUxefYFndfqQTNsNgWGxxLYzdYZpGiUMHkbClyzXd9A8b1wAoOk2+L uvGggdRaF9MwdjRa+NypmNU1eajvEeEKGTerkxuyFDNwjFPXVNSpjNYh3O5lRkeBfIZ6lg6lRPv E2rt2lWRTmBPA7NvU4fbhBNz9MZUBCKc9418G/uBG+1zgmpcWvbtDguwRNo8YL5cJVBReIReYYA pkUufxkhjSv/GLlmDt6yBv2Ywby3xlaT/Z7zxF7Zm+TWl98GKfP+SRfvKyGQip5fVO+bXGQcSp9 YwH4bCTdfe1/gng== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 In the context of a CB_NOTIFY callback, we may not have easy access to a svc_export. nfsd will not currently grant a delegation on a the V4 root however, so this should be safe. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7d162e5fb6ec..18adab1d7ca2 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3273,7 +3273,7 @@ static __be32 nfsd4_encode_fattr4_change(struct xdr_s= tream *xdr, { const struct svc_export *exp =3D args->exp; =20 - if (unlikely(exp->ex_flags & NFSEXP_V4ROOT)) { + if (exp && unlikely(exp->ex_flags & NFSEXP_V4ROOT)) { u32 flush_time =3D convert_to_wallclock(exp->cd->flush_time); =20 if (xdr_stream_encode_u32(xdr, flush_time) !=3D XDR_UNIT) --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D05C4CA278; Thu, 11 Jun 2026 17:50:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200262; cv=none; b=JL3eaNJy30NHUkp2KVm24kHlKa+vAbkv3mZ4q6YURqoxWjLTUJkwjIEFfHLiznKmrnhswv2Ho0EqTjMGZNCtjIF2+8uY5mmTZ+pB5qzhwCJbQzycpjh4uA1U320sXS9741uJ8o35jDi9/L91NhwJ+Y0FKrwE1qYZoGVGI6AYRAI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200262; c=relaxed/simple; bh=zENUhpmGv6filpPQyCMmrVOTjgbRQ6h8VQJDPTFsxds=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kGA5JXMg8CPQimJlEjJA9RNhULIm5Uq7ks8AWg2qvJsmxXTQFGv6VnIkJ+gQfOmkQ0b/pq9a3SaAkmwGQRMXaNsWZ+e8szjxa1cczKR41EuAsO4UtAQHEA1Ru1dLzKi4z22f6LIlh0qvOc08iSNvXh/Tq6dOeJbu2iwN4cDhUFA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=M2HJXm5I; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="M2HJXm5I" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 06FC81F00893; Thu, 11 Jun 2026 17:50:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200258; bh=EuZLlasoB6D5tya16pZbWZnz9fzJc6QTjGJBD4ZHycE=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=M2HJXm5Immue4QBiKuDAcZDCcycMrySN62KNeZUg1xxPrNbJcjZ2swfdRHQlBtB8Z klKrnZK+h35Oi3qBM4hROUh/gWgKVCM0xjI/S+Ji0xFRpjxW17ZyPtoS4E3YQtDB8v zCRgDOGv91LQCVoPtnJjFa4LCfRW5NGShWHRC3enxOZJbp05z4wCKdzhCCQPw8DsLu iPVX286sSod5+OkkOakp2AnuiMLZg2lyhQhgeJZYjacEZWjlmCs08lxzLAWUTs3Sr3 pnXtrlb+Lxe49nANwTk7pxeh1Qsj9XzZoR75bt21FYKAYBxMz484VViCayTlybyfff +syIffe7LT62w== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:20 -0400 Subject: [PATCH v6 14/20] nfsd: send basic file attributes in CB_NOTIFY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-14-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2682; i=jlayton@kernel.org; h=from:subject:message-id; bh=zENUhpmGv6filpPQyCMmrVOTjgbRQ6h8VQJDPTFsxds=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVjp2Ofx8TBaAmcZfa2RvIBKUKv9yUPBxD0m ztuiJnGNTSJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1YwAKCRAADmhBGVaC FWUgD/9RXPQMR2Ki/viK5ZPJNQrNK7C3S/6VHwcWw1W4u9n1IHZOcd/pmTKyKcp9qfb7pX7EHAN CIB41pzJ1TWvimgzrhVUHkcPesOWOLYNUUZhaz/Zj7wOuNkbzfmhysxD6s65vdIsQ8ESvNLAeZl B8t5UOHBghApny4I1Em6etlYnliswBxhJBuNtcFAUe9Q3Ii57grq3ZxuM+6/Rx/aKJPnbIs+YAH jUuBWNOhQWZ7Jon9jr6tAVhLoW8xXsl8CM4mG+7oCClsSHUu8JSWT4843Zep1+YZfJYqOnF13ny lyBPjTNnKQ0+onJX8DRkQzAaBsH9JPRDmmJpMMVW4vtGD0JhTXWU5c2CeSibWrx3LLs0PUfbBEB RlokBftP49t4lixT8cJeXo1OLP2LFuZ1AAcELHdPcdVmD3S6r4vLPcYjX6i2wUvVzb/i182hfTW ptg4iD1tammoQI4YaFOm1geV5P9O8IjFFxna+e3cm8NQbX0CmP6sZqj5IjR4HMuOOc4IYvwpUzx NETdgBZyDTe08pZHTmHj+WrK/8s7D/AlYg8G+J+cgjsAJhiyQCfT383TNFjy6iE8AbnOKov1Loy 4evEbmD9GfFsEhCBr3snStRpRvM2ax7/O6ZzkUE4nJH5JEvoYzEsoNX0eMSMsOSpy0/oTY2/kML zeHUkUuFflK9PuA== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 In addition to the filename, send attributes about the inode in a CB_NOTIFY event. This patch just adds a the basic inode information that can be acquired via GETATTR. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4xdr.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 18adab1d7ca2..4fb61d05a4a7 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4191,12 +4191,21 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct = xdr_stream *xdr, goto out; } =20 +#define CB_NOTIFY_STATX_REQUEST_MASK (STATX_BASIC_STATS | \ + STATX_BTIME | \ + STATX_CHANGE_COOKIE) + static bool nfsd4_setup_notify_entry4(struct notify_entry4 *ne, struct xdr_stream *xdr, struct dentry *dentry, struct nfs4_delegation *dp, struct nfsd_file *nf, char *name, u32 namelen) { + struct path path =3D { .mnt =3D nf->nf_file->f_path.mnt, + .dentry =3D dentry }; + struct nfsd4_fattr_args args =3D { }; uint32_t *attrmask; + __be32 status; + int ret; =20 /* Reserve space for attrmask */ attrmask =3D xdr_reserve_space(xdr, 3 * sizeof(uint32_t)); @@ -4207,6 +4216,41 @@ nfsd4_setup_notify_entry4(struct notify_entry4 *ne, = struct xdr_stream *xdr, ne->ne_file.len =3D namelen; ne->ne_attrs.attrmask.element =3D attrmask; =20 + /* FIXME: d_find_alias for inode ? */ + if (!path.dentry || !d_inode(path.dentry)) + goto noattrs; + + /* + * It is possible that the client was granted a delegation when a file + * was created. Note that we don't issue a CB_GETATTR here since stale + * attributes are presumably ok. + */ + ret =3D vfs_getattr(&path, &args.stat, CB_NOTIFY_STATX_REQUEST_MASK, AT_S= TATX_SYNC_AS_STAT); + if (ret) + goto noattrs; + + args.change_attr =3D nfsd4_change_attribute(&args.stat); + + attrmask[0] =3D FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE | + FATTR4_WORD0_SIZE | FATTR4_WORD0_FILEID; + attrmask[1] =3D FATTR4_WORD1_MODE | FATTR4_WORD1_NUMLINKS | FATTR4_WORD1_= RAWDEV | + FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | + FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY; + attrmask[2] =3D 0; + + if (args.stat.result_mask & STATX_BTIME) + attrmask[1] |=3D FATTR4_WORD1_TIME_CREATE; + + ne->ne_attrs.attrmask.count =3D 2; + ne->ne_attrs.attr_vals.data =3D (u8 *)xdr->p; + + status =3D nfsd4_encode_attr_vals(xdr, attrmask, &args); + if (status !=3D nfs_ok) + goto noattrs; + + ne->ne_attrs.attr_vals.len =3D (u8 *)xdr->p - ne->ne_attrs.attr_vals.data; + return true; +noattrs: attrmask[0] =3D 0; attrmask[1] =3D 0; attrmask[2] =3D 0; --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB0844D2ECD; Thu, 11 Jun 2026 17:51:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200263; cv=none; b=i7bhslP8+4C6EhyaDzjU9ASvNhAXu7CguXOu7pCho0ggaICI8mK39bMzJNLPMsxPTHKKkIWZM8yyNKehg1Zocl7ct4j2l3X37i/zDO0bIIJXJhjWqGIAuYSUzk7jIaWYHfZoP9MaPqmObiLh/BzJHFvp3zIR436vSGKrLB0WinM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200263; c=relaxed/simple; bh=jP15zhVMi8mCWtQnGto4m9iO8nFpaLdftVTZCij2eh8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=L4wiGo1EiTZBaXuL4aIAvv6xCNcWAWQl4BEaEu+TjV9WZYXvzL9zXSmR7v3J8pZiLp5xq3pnigEQSJQEMWBYEVSNsw+Hf2VkVwarLyFgvHm+pkOx66pMZYVG1X4shu4N4rsheAV61CZauwrFZeZ+gOlSWQddJ7nSCHA0i4XZB48= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KJwZwnJ3; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="KJwZwnJ3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E1A6F1F0089B; Thu, 11 Jun 2026 17:50:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200260; bh=WZDiq9wPHdi9pMWWiupF+UqYu+18kC5+B5IXngIVzlI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=KJwZwnJ3veRChY0Ib6w5m+W5beeexLj40phtltx12aq+6sQHo5zb+RDQOSZr5w3FL 4LE+1zcUoLQMOLRg3Y1Y2lbkjLsfpdZl/+Sqp1AJmTLN8/Gsfge8x3xLuD/qyusN7m 0QyGn+XRyxyZHoBFnuwiS7SuLyvHN6ByswIi/niamC+Pab5s8I1Ujbbd+QZSTaSXy2 tgBdpszSHcUFuE3qcNrCm14S/DhATOybIDa7IkEWJKDwlIzkmm4deKVkVImMboINut 2Vua416LktB3v9hqRrn2rMBPa6ypPeSWA7t6tlN0Qgjl7ikQuU64ZsEqs6E9MLZmj0 wrkvsx+Ejes8w== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:21 -0400 Subject: [PATCH v6 15/20] nfsd: allow encoding a filehandle into fattr4 without a svc_fh Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-15-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5033; i=jlayton@kernel.org; h=from:subject:message-id; bh=jP15zhVMi8mCWtQnGto4m9iO8nFpaLdftVTZCij2eh8=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVjuS+M+6WauRBR5medt60YM0onlYiVTgztt VZFA7/mmMWJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1YwAKCRAADmhBGVaC FaH1EACT3681Kr9ni8JG0ISAGJulorWwJWppQGShrjhIHPxVuOaXs8NQqINRmdXXWbbrT+DT7G9 abcHohi9Nn3gWr3B1Dxnd1juahqw7QPMrC6NobzpkeRg3tV53upBJIkz2DnEBxWIPV+I+IcBp+Y ADafd4XJTYG8DOJwvIED928y6FtSgbMQBXAJSK0BZCYDJ6//Z6bmCiljZ+TWTZDu+Md9HVvkLzv uZK35zZbWJ4IobAvlL3pzQ+dCJE0kvKyCc/Fcx/+hzr8Hx3IqLl6Seh+KD9r68iTRTiX5If0AN7 DcpHCyv3kWtMgtu7Wey9gy+LuAZNJUSVGW6Lre/OMufzLMgu56ah2renNTulWpUYnJsgkXn2UBH MqVq6nBbw5huCtIWNp/hwVoWsuviwYjP2UWXzExapPRiKIt+BLkXAhbsQ93DGpeuYBZ18nMsrfW XE3uSMIBhYaJWR5eZ/6EBhnPLSq9g/VQvHq3pJ/ggZ+O3stUzm/+CZ0smDnjssg7j3J4bFZBcJt tAFxfaLEk+Vzlb151dpgGwOXOHUk3ys15suCJEtFIlVBiXXv/DNpRwM/WyYetuFgwCBkB3F9Kxf l4duPBuMUMSgcBF4KsGRWKyq/4M0xBrvDoq3zlykzdBtheyyCkrs5SuKOLfRGMahWO5VRC/NPLZ CMAVQYJzJlN6Npw== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 The current fattr4 encoder requires a svc_fh in order to encode the filehandle. This is not available in a CB_NOTIFY callback. Add a a new "fhandle" field to struct nfsd4_fattr_args and copy the filehandle into there from the svc_fh. CB_NOTIFY will populate it via other means. A filehandle composed this way may still need a MAC appended on signed exports, so generalize fh_append_mac() to operate on a bare knfsd_fh (plus its maximum size and net) rather than a svc_fh. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4xdr.c | 36 +++++++++++++++++++++--------------- fs/nfsd/nfsfh.c | 10 +++++----- fs/nfsd/nfsfh.h | 1 + 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4fb61d05a4a7..7b19248b1503 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2715,7 +2715,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) } =20 static __be32 nfsd4_encode_nfs_fh4(struct xdr_stream *xdr, - struct knfsd_fh *fh_handle) + const struct knfsd_fh *fh_handle) { return nfsd4_encode_opaque(xdr, fh_handle->fh_raw, fh_handle->fh_size); } @@ -3158,6 +3158,7 @@ struct nfsd4_fattr_args { struct svc_fh *fhp; struct svc_export *exp; struct dentry *dentry; + struct knfsd_fh fhandle; struct kstat stat; struct kstatfs statfs; struct nfs4_acl *acl; @@ -3402,7 +3403,7 @@ static __be32 nfsd4_encode_fattr4_homogeneous(struct = xdr_stream *xdr, static __be32 nfsd4_encode_fattr4_filehandle(struct xdr_stream *xdr, const struct nfsd4_fattr_args *args) { - return nfsd4_encode_nfs_fh4(xdr, &args->fhp->fh_handle); + return nfsd4_encode_nfs_fh4(xdr, &args->fhandle); } =20 static __be32 nfsd4_encode_fattr4_fileid(struct xdr_stream *xdr, @@ -4015,19 +4016,24 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct = xdr_stream *xdr, if (err) goto out_nfserr; } - if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && - !fhp) { - tempfh =3D kmalloc_obj(struct svc_fh); - status =3D nfserr_jukebox; - if (!tempfh) - goto out; - fh_init(tempfh, NFS4_FHSIZE); - status =3D fh_compose(tempfh, exp, dentry, NULL); - if (status) - goto out; - args.fhp =3D tempfh; - } else - args.fhp =3D fhp; + + args.fhp =3D fhp; + if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID))) { + if (!args.fhp) { + tempfh =3D kmalloc_obj(struct svc_fh); + status =3D nfserr_jukebox; + if (!tempfh) + goto out; + fh_init(tempfh, NFS4_FHSIZE); + status =3D fh_compose(tempfh, exp, dentry, NULL); + if (status) + goto out; + args.fhp =3D tempfh; + } + if (args.fhp) + fh_copy_shallow(&args.fhandle, &args.fhp->fh_handle); + } + if (attrmask[0] & (FATTR4_WORD0_CASE_INSENSITIVE | FATTR4_WORD0_CASE_PRESERVING)) { /* diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index b36915401758..3b29cd70d4a1 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -144,16 +144,15 @@ static inline __be32 check_pseudo_root(struct dentry = *dentry, /* Size of a file handle MAC, in 4-octet words */ #define FH_MAC_WORDS (sizeof(__le64) / 4) =20 -static bool fh_append_mac(struct svc_fh *fhp, struct net *net) +bool fh_append_mac(struct knfsd_fh *fh, int fh_maxsize, struct net *net) { struct nfsd_net *nn =3D net_generic(net, nfsd_net_id); - struct knfsd_fh *fh =3D &fhp->fh_handle; siphash_key_t *fh_key =3D nn->fh_key; __le64 hash; =20 if (!fh_key) goto out_no_key; - if (fh->fh_size + sizeof(hash) > fhp->fh_maxsize) + if (fh->fh_size + sizeof(hash) > fh_maxsize) goto out_no_space; =20 hash =3D cpu_to_le64(siphash(&fh->fh_raw, fh->fh_size, fh_key)); @@ -167,7 +166,7 @@ static bool fh_append_mac(struct svc_fh *fhp, struct ne= t *net) =20 out_no_space: pr_warn_ratelimited("NFSD: unable to sign filehandles, fh_size %zu would = be greater than fh_maxsize %d.\n", - fh->fh_size + sizeof(hash), fhp->fh_maxsize); + fh->fh_size + sizeof(hash), fh_maxsize); return false; } =20 @@ -566,7 +565,8 @@ static void _fh_update(struct svc_fh *fhp, struct svc_e= xport *exp, fhp->fh_handle.fh_size +=3D maxsize * 4; =20 if (exp->ex_flags & NFSEXP_SIGN_FH) - if (!fh_append_mac(fhp, exp->cd->net)) + if (!fh_append_mac(&fhp->fh_handle, fhp->fh_maxsize, + exp->cd->net)) fhp->fh_handle.fh_fileid_type =3D FILEID_INVALID; } else { fhp->fh_handle.fh_fileid_type =3D FILEID_ROOT; diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index 5ef7191f8ad8..5dc10b442d6c 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -226,6 +226,7 @@ __be32 fh_getattr(const struct svc_fh *fhp, struct ksta= t *stat); __be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, s= truct svc_fh *); __be32 fh_update(struct svc_fh *); void fh_put(struct svc_fh *); +bool fh_append_mac(struct knfsd_fh *fh, int fh_maxsize, struct net *net); =20 static __inline__ struct svc_fh * fh_copy(struct svc_fh *dst, const struct svc_fh *src) --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C43EB4C957B; Thu, 11 Jun 2026 17:51:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200264; cv=none; b=t1Aw63jeFXIpDmYt7v7tFG7UpJBcRjDIsPAx/pxen+vdU4oeZDFIG5wM/6YxpBJJPuIuH5gfgHmVxA9Rb/gR5V5+XLsj3ng9ofXn7tfH5lLuuI7JDitBz689TzysHiOJGvLw9lJ3D8uWcI9MlZNBc7/Vlh4b2IOEWlplZB8hMHw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200264; c=relaxed/simple; bh=Z9PQXxGT0Za/+E6J+7SEhVY5kT9xYRNXrypAbhZ6NSk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ajNNIfjme3CuGXEqqr6eRkJD7jyYs9sDOsGncGsdzoaZaT8QGjE05D1Or63LX6wtXLCm+5BoDP+WFEaD6dilpiVIpEzRx9f4OA1mzsoByO5xcXZ7WzxPhK3abLYc3zCn0gJ50DUGcTgSJcGfzFu/FdeK7Lz1BejaDmr5XRhkqDM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YrWXFqgR; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YrWXFqgR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 077B71F00899; Thu, 11 Jun 2026 17:51:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200262; bh=Aj4PloKil1ZVzC0RUAlqMUlsXH0YAb7CWvzBrJRFPj8=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=YrWXFqgR3Zu5zF75i6EROWhmb/0Wh/Ob9h38a2Rgc9d2UQX28LpzdRDPaImtNVq+R PhrDc1n9BWlIajK2GCroBT1qp4cmHEp2zaEa0IXogD1cRXRz5reDfsgoMudHKaOc+I HyeumlK7o2EcpQOJVX3JnSmMwuTkSI+2Gh3hDhJVvT69/PCPBLOQbXfJdE0VrUvEsw Ht6MGPNkkJh3odEFgQQkLTl/rfbGxZfoTsd7oU9NdA/o8puo67wUab4/VbFHXBcyN8 Kk8+mkWOJiTlq3alzR2lNyrhVgcxu6TIr5bCilj6LuynaJB/3/BQKqwSUJvKA1FAM2 nFGHvNIwDkSFw== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:22 -0400 Subject: [PATCH v6 16/20] nfsd: add a fi_connectable flag to struct nfs4_file Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-16-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=1426; i=jlayton@kernel.org; h=from:subject:message-id; bh=Z9PQXxGT0Za/+E6J+7SEhVY5kT9xYRNXrypAbhZ6NSk=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVkHJJ9LiOhD1hBMiYj0aqx44RMGJSPzu5lW gtxmbt8NROJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1ZAAKCRAADmhBGVaC FWqBD/sEtNE7sq0gkNRU0ZLqZpdxImrg9QvqecIvF97zxu0C0eM6BB77RWGRcGvDEwrrDHSWQBZ +DjP+TdNekLifpiY6SKWOB9+phicp2qyHrITBaWQH4w6dRkIdwpTaisFFvMBv5Lv3UsKOdEb4ps nCbyEGcC3vyBi38bRkHNjRuVk/FNJjWUVk+shFHiV8uDpThKZcvSfMM3eEfiSvvu0jLST7VZvun UPfahmSCa0RaSOQi9I+IJ/uTci4Q3syQOOyIED9Ye1acJ5ZdfU6WG5Ua4/chD58eFV6rO6tLQni TjMG4qwsDj03SwQNfLC98n39R8oDpTUfDif/edkUoPbXows9z+Uk+mnImlr8iFmb84PsuPE617P D418ZcbXu4zNrFOKHn6tji7C3Oeez37ZEzzNccR71wGTkcbQPBo+5NCHwqd3Ln2m1jL7pPrJ5mr mot8vHxtX9ZWxXdgKAHtNAoTKpetk/dawMg5vjNujqaJlgqoda8K67woZir3yfohJVYxg2AjPPr RGAAH54y0EtzUSmJ4WIKb1SgTj2y5W7zbupxcr3M0YAmu8st/w97ByMdDoT6EXh/Nx2VE7Wq+kX cBm1iu1jEcr2JIFWKqkQ/Bz0mGHLUh6xRQoaRahZpMGqVzEfzcsH/8AnAtDQp6KvLSeQcaiEhec 51xLGKs6/GCPq3g== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 When encoding a filehandle for a CB_NOTIFY, there is no svc_export available, but the server needs to know whether to encode a connectable filehandle. Add a flag to the nfs4_file that tells whether the svc_export under which a directory delegation was acquired has subtree checking enabled, in which case it needs connectable filehandles. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4state.c | 1 + fs/nfsd/state.h | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 513cbc1a583f..aa99783ce901 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5231,6 +5231,7 @@ static void nfsd4_file_init(const struct svc_fh *fh, = struct nfs4_file *fp) memset(fp->fi_access, 0, sizeof(fp->fi_access)); fp->fi_aliased =3D false; fp->fi_inode =3D d_inode(fh->fh_dentry); + fp->fi_connectable =3D !(fh->fh_export->ex_flags & NFSEXP_NOSUBTREECHECK); #ifdef CONFIG_NFSD_PNFS INIT_LIST_HEAD(&fp->fi_lo_states); atomic_set(&fp->fi_lo_recalls, 0); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index f8457e0f2b57..d912e3d04dd7 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -761,6 +761,7 @@ struct nfs4_file { int fi_delegees; struct knfsd_fh fi_fhandle; bool fi_had_conflict; + bool fi_connectable; #ifdef CONFIG_NFSD_PNFS struct list_head fi_lo_states; atomic_t fi_lo_recalls; --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AB3BC4DA52C; Thu, 11 Jun 2026 17:51:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200265; cv=none; b=Zii67888zMmh5B60ACpDqOBxa9MiJAj76CwilwpjWtTlD1Z28QeuKqR4HHLuqLJE+b0syiuv4/xyio4GZnO09Y79V9ccXrC14b9VdVEfbEYCsYQp8uvDJi9G7ITB8i1Z2YQRVYqDdXlYIQkY9CloW5pIzpJqq38TRDgW1C6AdGg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200265; c=relaxed/simple; bh=fPJUVDwF+zuWTm/fTVKoRtFQ3BS17pB3bnUhzV3tirc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=phNXpZliGggzsj0VzQC9f1OaeV7pcUthjg7IF7A+Vt920i/rMdW2xmw9LUtklb+a0FIcL7EH7rdC9upV+1Q02+bORQdmYK8UJarlugM0uaycpNR8oXtgpWKmw6wwmrOC7G6rFeiX2JQ25mfEX7jDLgIJ0F+xLvkQC2/27UekBRQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nLHmydyL; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nLHmydyL" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E45E31F00893; Thu, 11 Jun 2026 17:51:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200264; bh=m+NmgJmH4CWmdHTj5eOO5l9fzqp+r26lhK4EXfyhFsg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=nLHmydyL806rSensVx27jsPRdTk/pRioTOsha1Kt6t75C19gMRyHaJIu80sJgmCms dfWO2uVU5pQCiuACy6PJxA00529pJOfznHbpRiEFvKZrj4GIMMPUEuWm4U7i89jR4M JG9rbGmGEask1j4ud+sVHYqK0xj6JdvBPiczVNBQEt41J7/0FvjrqsoGRUXO6j48xi qNZQXYFFl9ChxHy5up6dpKu9xokZSfIJawp4/1wJnj+rFA7J/loBDvbWoCKmD0MRkd fpwHYt2NedMzxBWT4IsKBS0cC8GKqF9E55N/psneOnEw9Xcr3NZdI8wkzGvQjQE9Gu ZaxZMN5GZJ0eA== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:23 -0400 Subject: [PATCH v6 17/20] nfsd: add the filehandle to returned attributes in CB_NOTIFY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-17-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2651; i=jlayton@kernel.org; h=from:subject:message-id; bh=fPJUVDwF+zuWTm/fTVKoRtFQ3BS17pB3bnUhzV3tirc=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVk8jAKehX4yj38Z8JTHtt78eGDBUE0ZtU8I srAElTilAKJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1ZAAKCRAADmhBGVaC FdICEACLFSwmvCSTp/9Z0dhZOjkKvrdz7NnCMmaAgrLUArWqkyivMhcvOSIy1QrnhtW5o5BHrBK gkUpTcfenTJlixFF6cYZ4RTR/QjpXv1Ufy4Aa26ar86HLKwLuf9ucZo/K70vdJt5ebvSSSeciHb iGs8NolVKtzRAF36Z6DK075ig/6sTSzGm0D5hWmoiP8n2x2m7nRAZ5eL9tzAwSa8dJPA212AOH8 PksCxJL2thU2DMEPuwQjNmYDqrh0wbQ2V2PTliA0DC7wrPzaOlMd/BN3CWNs0zRyxou4jW+88ku GCNJVmE4rYTYovD1TlR6RrbvGhjCfBxxAxEoAb+Uz+e79qDHFcHzP/JaRd7HCsb6H6twhA73w38 MmR9wr4VwZxqKx/fhF7xjYzggbCLgwXK2EBGDGptzk6zFWut9GNaB1/AmH+a4JoSy3oJzOUDMk7 ap08aiMyYe05Ki5jyzIYLNIvQZNlO4gWttuj3KmYsnqbMfWdvIAA40ihGgSks4wIxZzl6wEEFWq Q9lUczYnZMQmpNJh/32AoRuhJpbxSgVL3m0ZuzdRHv7hgfh8muga8c/tgjv8BHBhLrMYGX3+mpH JkxYbZKZ/AyoG5EzFqUts8pD1VYSObY2lLH4Jd1C59C4t2X770+vfnO/GJeFLYkHHZYJMdOMBwn ELbMqBVZ3inN/xg== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 nfsd's usual fh_compose routine requires a svc_export and fills out a svc_fh. In the context of a CB_NOTIFY there is no such export to consult. Add a new routine that composes a filehandle with only a parent filehandle and nfs4_file. Use that to fill out the fhandle field in the nfsd4_fattr_args. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4xdr.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7b19248b1503..15ccd54ffdb6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4197,6 +4197,39 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct x= dr_stream *xdr, goto out; } =20 +static bool +setup_notify_fhandle(struct dentry *dentry, struct nfs4_file *fi, + struct nfsd_file *nf, struct nfsd4_fattr_args *args) +{ + int fileid_type, fsid_len, maxsize, flags =3D 0; + struct knfsd_fh *fhp =3D &args->fhandle; + struct inode *inode =3D d_inode(dentry); + struct inode *parent =3D NULL; + struct fid *fid; + + fsid_len =3D key_len(fi->fi_fhandle.fh_fsid_type); + fhp->fh_size =3D 4 + fsid_len; + + /* Copy first 4 bytes + fsid */ + memcpy(&fhp->fh_raw, &fi->fi_fhandle.fh_raw, fhp->fh_size); + + fid =3D (struct fid *)(fh_fsid(fhp) + fsid_len/4); + maxsize =3D (NFS4_FHSIZE - fhp->fh_size)/4; + + if (fi->fi_connectable && !S_ISDIR(inode->i_mode)) { + parent =3D d_inode(nf->nf_file->f_path.dentry); + flags =3D EXPORT_FH_CONNECTABLE; + } + + fileid_type =3D exportfs_encode_inode_fh(inode, fid, &maxsize, parent, fl= ags); + if (fileid_type < 0 || fileid_type =3D=3D FILEID_INVALID) + return false; + + fhp->fh_fileid_type =3D fileid_type; + fhp->fh_size +=3D maxsize * 4; + return true; +} + #define CB_NOTIFY_STATX_REQUEST_MASK (STATX_BASIC_STATS | \ STATX_BTIME | \ STATX_CHANGE_COOKIE) @@ -4206,6 +4239,7 @@ nfsd4_setup_notify_entry4(struct notify_entry4 *ne, s= truct xdr_stream *xdr, struct dentry *dentry, struct nfs4_delegation *dp, struct nfsd_file *nf, char *name, u32 namelen) { + struct nfs4_file *fi =3D dp->dl_stid.sc_file; struct path path =3D { .mnt =3D nf->nf_file->f_path.mnt, .dentry =3D dentry }; struct nfsd4_fattr_args args =3D { }; @@ -4244,6 +4278,9 @@ nfsd4_setup_notify_entry4(struct notify_entry4 *ne, s= truct xdr_stream *xdr, FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY; attrmask[2] =3D 0; =20 + if (setup_notify_fhandle(dentry, fi, nf, &args)) + attrmask[0] |=3D FATTR4_WORD0_FILEHANDLE; + if (args.stat.result_mask & STATX_BTIME) attrmask[1] |=3D FATTR4_WORD1_TIME_CREATE; =20 --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE06B481641; Thu, 11 Jun 2026 17:51:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200268; cv=none; b=LNt0+7rhKXHjRi7JXZ6vvRS/MTBOJ/qj0exh0vvDXKT2ddtlE3T3xnjLaNh8Pl8nLf/6xAn0z5UP80hdqrYa5PI1ANc87RrFJZ4gT9VpZBHej2Ai5LiBNJ/DtwBmn+Af2QtmGGHdsAbr10awceyNlBXQZ7m0UeaDZr3D2HD/2Z4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200268; c=relaxed/simple; bh=b4hbzahPlTlpr/FchnlHPCHN8IuOc196YmLM1DdFzKI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=M0Vq+vDAUghZBWzneyJ1P0MeeWx0fwmR+V5St+nZ/BCOj8Vvj3a+kOfS5sXzKstrieDYB+D8Pfmm3H0IABlN0meinw6CYuJa5rOVJsIjrobLQkmKuPZg+Q7TqxutbLP9l+dVa+wYKUa5QWk7Lyk5Hg3Ne22uMtyUkzSbuAFd//E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=M1AXUj7r; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="M1AXUj7r" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CC1471F00898; Thu, 11 Jun 2026 17:51:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200266; bh=2+hfBNcjXxvB8tFKrEepFnMvRobBM/QjiUotS5EyytM=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=M1AXUj7r+x9OiRGkH+oaBJAX8kG/Mf42VkwK4aFlYrzK/EBUZVxqVdo8srsBnmqOU 4vGynEwC0J+r95VlEEgD6dZwuXuSh0ypEFaYKTqWGQkb4NIHsazK5ggQVMB0JJ5xG4 k0+stQfOSzIgKuITVk8cm8Q9pftoIKvRZ1UN2Kyp5OKCF0suq90pZkFjHNDbwsVHQJ 9FOtj8dGXoI2RPf1PqTrGkmt85jKHZqxUF23L1gT6+Rs9vF6YcPiNtvtGADSFe0AEU SrLS1KaVNOboTZrP5hia03gvUo3eg6QSIITC6hAVOP0Ihe11NYvl3H1NvsbORbC8QU nvICqcpqVL+bg== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:24 -0400 Subject: [PATCH v6 18/20] nfsd: properly track requested child attributes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-18-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3832; i=jlayton@kernel.org; h=from:subject:message-id; bh=b4hbzahPlTlpr/FchnlHPCHN8IuOc196YmLM1DdFzKI=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVkeo5dXf9jKkyKavEM6bM7iw81vSM1xCGI4 R+MEnDJjSGJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1ZAAKCRAADmhBGVaC FRgwEACmWYwPrkOAKjA66JfwqwPilvsZvp9NFYHfSv3pBH8o9heWcCgvFA78CD4S1uwxB18YIlI VAcNXBStSpg26FRBYqY1CfpWYD1wWIqx12ig4E04Xw33hwvM9z0AyNUrnzuEMnr3YucyQW0Xkn+ ylttzuuFUm+2vMMG9A4M2tEWCJ3e+EmmY5mdtSfeeWcHYEj1cE77+wCeCKRLZQuGrTGLJOVR542 VZbpAr8TJp0nSCBGoA87aXA6xdoXraDWkZUXJjhi85I6VaPwbeVyYlCps5cHifhOvlaowq+Xx45 66Hqz7nAFJLxKPGRZ/TmHGL/G3CEw4wy/fQRZd5vuEuql0e/jajJ3UuaUSUf2pYKmkw09FHSt7R EXAkreapR2F5C7OR9xHOJa2QRpHyo9WkHhL6HgLUyfjM7XcpJqhoAXV4YKr1p0Kxc5R3B1MGJAp 0L38+81OY5LeZjz+qbrKvz+w+s5v3uUWNi5/36/OUCkpXMgqlAcQMvvQYs8ZlSox2SG+w1IZgre tlQzkCRAXWQbfIIFRkyCqzIIYn7Bzw1IgYdjQwTHlnMKyw4W2nyaYqXKWZ3RLKMQplFyKvVHV/a VTIEZcqTF1QxsS1Mq+I6wWo2CrtqHnRfmda4LVF/JEkrZw/+9EfUd12jmtYd+CTyC4SzE9Eqfaw v+dWEP/cR/Txg2g== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Track the union of requested and supported child attributes in the delegation, and only encode the attributes in that union when sending add/remove/rename updates. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4proc.c | 2 ++ fs/nfsd/nfs4state.c | 18 ++++++++++++++++++ fs/nfsd/nfs4xdr.c | 15 ++++++--------- fs/nfsd/state.h | 3 +++ 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 29f7339dc220..caec82e77081 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2577,6 +2577,8 @@ nfsd4_get_dir_delegation(struct svc_rqst *rqstp, =20 gdd->gddrnf_status =3D GDD4_OK; memcpy(&gdd->gddr_stateid, &dd->dl_stid.sc_stateid, sizeof(gdd->gddr_stat= eid)); + gdd->gddr_child_attributes[0] =3D dd->dl_child_attrs[0]; + gdd->gddr_child_attributes[1] =3D dd->dl_child_attrs[1]; nfs4_put_stid(&dd->dl_stid); return nfs_ok; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index aa99783ce901..0e6e008c121e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -9930,6 +9930,21 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp,= struct dentry *dentry, return status; } =20 +#define GDD_WORD0_CHILD_ATTRS (FATTR4_WORD0_TYPE | \ + FATTR4_WORD0_CHANGE | \ + FATTR4_WORD0_SIZE | \ + FATTR4_WORD0_FILEID | \ + FATTR4_WORD0_FILEHANDLE) + +#define GDD_WORD1_CHILD_ATTRS (FATTR4_WORD1_MODE | \ + FATTR4_WORD1_NUMLINKS | \ + FATTR4_WORD1_RAWDEV | \ + FATTR4_WORD1_SPACE_USED | \ + FATTR4_WORD1_TIME_ACCESS | \ + FATTR4_WORD1_TIME_METADATA | \ + FATTR4_WORD1_TIME_MODIFY | \ + FATTR4_WORD1_TIME_CREATE) + /** * nfsd_get_dir_deleg - attempt to get a directory delegation * @cstate: compound state @@ -9998,6 +10013,9 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *csta= te, dp->dl_stid.sc_export =3D exp_get(cstate->current_fh.fh_export); =20 + dp->dl_child_attrs[0] =3D gdd->gdda_child_attributes[0] & GDD_WORD0_CHILD= _ATTRS; + dp->dl_child_attrs[1] =3D gdd->gdda_child_attributes[1] & GDD_WORD1_CHILD= _ATTRS; + /* * NB: gddr_notification[0] represents the notifications that * will be granted to the client diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 15ccd54ffdb6..1e3c360c06cd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4271,18 +4271,15 @@ nfsd4_setup_notify_entry4(struct notify_entry4 *ne,= struct xdr_stream *xdr, =20 args.change_attr =3D nfsd4_change_attribute(&args.stat); =20 - attrmask[0] =3D FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE | - FATTR4_WORD0_SIZE | FATTR4_WORD0_FILEID; - attrmask[1] =3D FATTR4_WORD1_MODE | FATTR4_WORD1_NUMLINKS | FATTR4_WORD1_= RAWDEV | - FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | - FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY; + attrmask[0] =3D dp->dl_child_attrs[0]; + attrmask[1] =3D dp->dl_child_attrs[1]; attrmask[2] =3D 0; =20 - if (setup_notify_fhandle(dentry, fi, nf, &args)) - attrmask[0] |=3D FATTR4_WORD0_FILEHANDLE; + if (!setup_notify_fhandle(dentry, fi, nf, &args)) + attrmask[0] &=3D ~FATTR4_WORD0_FILEHANDLE; =20 - if (args.stat.result_mask & STATX_BTIME) - attrmask[1] |=3D FATTR4_WORD1_TIME_CREATE; + if (!(args.stat.result_mask & STATX_BTIME)) + attrmask[1] &=3D ~FATTR4_WORD1_TIME_CREATE; =20 ne->ne_attrs.attrmask.count =3D 2; ne->ne_attrs.attr_vals.data =3D (u8 *)xdr->p; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index d912e3d04dd7..0763893bfd48 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 */ + uint32_t dl_child_attrs[2]; }; =20 static inline bool deleg_is_read(u32 dl_type) --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BA96B4DC558; Thu, 11 Jun 2026 17:51:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200269; cv=none; b=h6fOHNxMqj00Bqx9x95DWMl2WyH9qQiFaJajDez+lphV69/DKQbKRE5fLNNhksCLIDACetRMQoEATUQ5YsQTDXW8Ogtw+hiR16rw5XAZw5wvGm15p8aPivTXMFujvD9E1MhAyKU4e/EfAiQNObCbU+aq/+Y2D4QNXx8LlMEJhTE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200269; c=relaxed/simple; bh=yyOVIL3d4lD3gyL9fmIarwsvzMRIwadlBHUUC6PtrTc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dtDeDwIu8UpDZR8/iWpud0bF48yC6/Y+Kj+PeHBwbBR1Puj5+yXjWiT0UQ2BmEoQf1cCwevuhCQqy4mnev6J6ONxW6VUK/zmtwneUrKnGLXm9HYpQB8QlB8SrT4FkQ0iG+H1JoSRvoGjuDLt4i8VduYm5y6yu+YzsNImP/OAJ7I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZNBKPzWu; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZNBKPzWu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B37801F00893; Thu, 11 Jun 2026 17:51:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200268; bh=i9Q1gDiXGeAiPGNYLXuCsxEZwVYuTaLAvt0x9c5vOJg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=ZNBKPzWuZKKSn0bHYf9dCXwjeSj/pA/vjsf2eqOOhKiuU1FKYMz9zLM1mgQmwfm/o l152hh4tIVQFehfuwfSFthGYWBJy0bdWdAs4IvU7xPbVW5WFZqyDIkL4g9SNsSBjbK iwn/oHK8tTsbGWecCp+MNmV00WXuz1VtAcnBk2Scj0FaKf60nC+Y1sjnid3ZfATyuE Wcs+llYKHIK81LLJ2f7z72178G7Jbd1eMYt4ptA2Npl64FB2OYVIrvTgkg7LCz+PTA RXoXSafZ0J/6IlEaeAZ7bgRw2ZyoYHg3N/e/2UXOxh2ATtwkkIlyoOiNNmQLVXtM6w 8DguiAeGTwPFA== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:25 -0400 Subject: [PATCH v6 19/20] nfsd: track requested dir attributes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-19-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3620; i=jlayton@kernel.org; h=from:subject:message-id; bh=yyOVIL3d4lD3gyL9fmIarwsvzMRIwadlBHUUC6PtrTc=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVliER5AbCQzyAurF5kq8TXPJIk3TZua0M2t ZZLDYB5Ot2JAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1ZQAKCRAADmhBGVaC Fc8jEACnsnIxuGIx/FKzW5l8UCFfiT/MUzWbzmxwoTGptlzJaeAQEFkXw5Q+SSN02uNAlXy1I7y SWzADgcxjtejR4ewrOr6XZ336Lou+GWQiYdLz9cVgfgPUgUcIObrCmGaAu5ZQbRSm3gopimhCiO 8p8BfGvQpsb4LEuIBHhpKZJqJLixazCffUxPb8wYaX18s4ZjVoGT6KUJZGBqRpwYoXR5U2u9Uby YyIQyguY1P8ZppE2dN/dXI65XyP161V6ySEiQI4RnUb0oj4Tj1d+lByk8XHZAJdWtDEmR5YG4eP AjXjlQJJUD61HiOfHOWjpmqSQmY+ouN6ADUANmHzoEYzjEq9AiWo/XGfK644fcbNVEe+RpqNm5x tzWkzWoaWrOEKOY+L66wFkw9VWCNdC2DSXqIGw4G9FDH5K3krhaSN75rADV4bt3LG7rH5YxbaDv Y4JR5vmYP+9pw+FXtukVzXav+3wBqXxsYiEwFd0by08XD9pF/s9zuPc9n52lD/Kk0zigUjc3oG2 e24Vg0bG1oVBzzOs2Y/ynQKcViTENkkAqA8txUgnxrPFaD0rOzljRE2vOFePa0qNmZtifgtxYD6 WNONdixyTTDjpqKgMggRK4QvZc2javL5Yj+gldbpB7V/bOnW0aKXvTHeVDInNNDYDiZiTXcDMco N7WQq8jIz1F01PA== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 Track the union of requested and supported dir attributes in the delegation. In a later patch this will be used to ensure that we only encode the attributes in that union when sending add/remove/rename updates. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4proc.c | 9 ++++++--- fs/nfsd/nfs4state.c | 20 ++++++++++++++++---- fs/nfsd/state.h | 2 ++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index caec82e77081..9e86f5907f06 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2530,9 +2530,10 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_co= mpound_state *cstate, return status =3D=3D nfserr_same ? nfs_ok : status; } =20 -#define SUPPORTED_NOTIFY_MASK (BIT(NOTIFY4_REMOVE_ENTRY) | \ - BIT(NOTIFY4_ADD_ENTRY) | \ - BIT(NOTIFY4_RENAME_ENTRY) | \ +#define SUPPORTED_NOTIFY_MASK (BIT(NOTIFY4_CHANGE_DIR_ATTRS) | \ + BIT(NOTIFY4_REMOVE_ENTRY) | \ + BIT(NOTIFY4_ADD_ENTRY) | \ + BIT(NOTIFY4_RENAME_ENTRY) | \ BIT(NOTIFY4_GFLAG_EXTEND)) =20 static __be32 @@ -2579,6 +2580,8 @@ nfsd4_get_dir_delegation(struct svc_rqst *rqstp, memcpy(&gdd->gddr_stateid, &dd->dl_stid.sc_stateid, sizeof(gdd->gddr_stat= eid)); gdd->gddr_child_attributes[0] =3D dd->dl_child_attrs[0]; gdd->gddr_child_attributes[1] =3D dd->dl_child_attrs[1]; + gdd->gddr_dir_attributes[0] =3D dd->dl_dir_attrs[0]; + gdd->gddr_dir_attributes[1] =3D dd->dl_dir_attrs[1]; nfs4_put_stid(&dd->dl_stid); return nfs_ok; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0e6e008c121e..12627afb604f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -9945,6 +9945,15 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp,= struct dentry *dentry, FATTR4_WORD1_TIME_MODIFY | \ FATTR4_WORD1_TIME_CREATE) =20 +#define GDD_WORD0_DIR_ATTRS (FATTR4_WORD0_CHANGE | \ + FATTR4_WORD0_SIZE) + +#define GDD_WORD1_DIR_ATTRS (FATTR4_WORD1_NUMLINKS | \ + FATTR4_WORD1_SPACE_USED | \ + FATTR4_WORD1_TIME_ACCESS | \ + FATTR4_WORD1_TIME_METADATA | \ + FATTR4_WORD1_TIME_MODIFY) + /** * nfsd_get_dir_deleg - attempt to get a directory delegation * @cstate: compound state @@ -10013,14 +10022,17 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *c= state, dp->dl_stid.sc_export =3D exp_get(cstate->current_fh.fh_export); =20 - dp->dl_child_attrs[0] =3D gdd->gdda_child_attributes[0] & GDD_WORD0_CHILD= _ATTRS; - dp->dl_child_attrs[1] =3D gdd->gdda_child_attributes[1] & GDD_WORD1_CHILD= _ATTRS; - /* * NB: gddr_notification[0] represents the notifications that * will be granted to the client */ - fl =3D nfs4_alloc_init_lease(dp, gdd->gddr_notification[0]); + dp->dl_notify_mask =3D gdd->gddr_notification[0]; + dp->dl_child_attrs[0] =3D gdd->gdda_child_attributes[0] & GDD_WORD0_CHILD= _ATTRS; + dp->dl_child_attrs[1] =3D gdd->gdda_child_attributes[1] & GDD_WORD1_CHILD= _ATTRS; + dp->dl_dir_attrs[0] =3D gdd->gdda_dir_attributes[0] & GDD_WORD0_DIR_ATTRS; + dp->dl_dir_attrs[1] =3D gdd->gdda_dir_attributes[1] & GDD_WORD1_DIR_ATTRS; + + fl =3D nfs4_alloc_init_lease(dp, dp->dl_notify_mask); if (!fl) goto out_put_stid; =20 diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 0763893bfd48..17be4011740d 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -299,7 +299,9 @@ struct nfs4_delegation { struct timespec64 dl_ctime; =20 /* For dir delegations */ + uint32_t dl_notify_mask; uint32_t dl_child_attrs[2]; + uint32_t dl_dir_attrs[2]; }; =20 static inline bool deleg_is_read(u32 dl_type) --=20 2.54.0 From nobody Sun Jun 14 04:58:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9DE4D4DC54E; Thu, 11 Jun 2026 17:51:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200271; cv=none; b=gP8Z2AOm3ck6CMcsWgNaf8C6Mwf2R7bwdXWA3Y4Aa3+7lLnHQ03wOiwzRS/XHdbkd+5/19pMQpV693L7aGdgQf9imeg60ocf/KIXu8IsmaOBSR1OYSda3SaqAjeMUehUqRVX6Dj5KS4Wawvb3idvZ0I8E0wUALeF1BxQawA28oQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781200271; c=relaxed/simple; bh=emL5fNfICAJlgEqAE5bmz/85UIAGj+PBG4gXo7Pb4Sk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ad3KobUAQ+HI7MsfhxldeuNQY/Hsd9+1/bWO9i/sDGXwNL9MtIQR98hzmgojqoWlsU2L4smX/4Pwt1qMLQ27jLPqsrgOf6sTORYhUQ8hmzhRX6BR8+K+EHHUKH8Sqlt4SO5rqzfICqdq6U3Fw9cNDM0LfXfWKSJqVTdJaLlEyYA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=J9OHsFEj; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="J9OHsFEj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9A3C41F00898; Thu, 11 Jun 2026 17:51:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1781200270; bh=JMxPicfLnHJXDlOPHPdm8WveFf4HMrxmBXlH9ncp8MU=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=J9OHsFEjDn/gCJFj01MeIEhSxS5B5gFSXq3Zty7jjs1TlwxPyAf/loXTT0LcCTBOj xlp7845Bbe3YQHGoS7Y2Fu5B9fyiq2qlzHlBk1LUE16rf/nEOr14gOnzG8Yv22A2nl IaPinJRCnmJfuDWtxWKjfY6eA3Hab9gTx5QTaUPwDfH78ZpqxsezCjPCXntDN/mW1a hGDOMNskrQjgwCNSsFWHh6bR6jkRfjSfBoAwAt9PtNuRXKt0CQnu43oqY0XG9UQ8Cr 53OgzhAJSy2Mq5hTKQASQwLa6L/H6+WMGSzh8eUNY9hzwZU6lShT2VMpEr2uZxcsWR ffDjogM1FJElw== From: Jeff Layton Date: Thu, 11 Jun 2026 13:50:26 -0400 Subject: [PATCH v6 20/20] nfsd: add support to CB_NOTIFY for dir attribute changes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260611-dir-deleg-v6-20-4c45080e5f3f@kernel.org> References: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> In-Reply-To: <20260611-dir-deleg-v6-0-4c45080e5f3f@kernel.org> To: NeilBrown , Olga Kornievskaia , Dai Ngo , Tom Talpey , Trond Myklebust , Anna Schumaker , Jonathan Corbet , Shuah Khan , Chuck Lever Cc: Steven Rostedt , Alexander Aring , Amir Goldstein , Jan Kara , Alexander Viro , Christian Brauner , Calum Mackay , linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nfs@vger.kernel.org, Jeff Layton X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=7638; i=jlayton@kernel.org; h=from:subject:message-id; bh=emL5fNfICAJlgEqAE5bmz/85UIAGj+PBG4gXo7Pb4Sk=; b=owEBbQKS/ZANAwAKAQAOaEEZVoIVAcsmYgBqKvVlr2Wdi1g87CWBPN5/thsL4z7Y563JLfIez mUORE9D3MCJAjMEAAEKAB0WIQRLwNeyRHGyoYTq9dMADmhBGVaCFQUCair1ZQAKCRAADmhBGVaC FTcJEACD8OUU9Hs6Dc2tDOeOiSofHrJKi68BhrxohMHDZkJDNJUMye8/fZtqH2g2G/LFzCXxwfS oyF071K7pprczky59mdkV5+IxadPLsMKu99pI+vZIRx8IokgjWnztQ14DCZmL0L1RQEqJOCy8cC VdgdPXXNDn4zlm1Ju7x35j13oaiCUuqi+TZ3Bk1UOwnccCd6P2gzLpQQGf6x7yfN9763GPgnCH8 IT9mxh3sP4VXz5gLEv4puYFcr5kzZ8RPehpQXuK8ZLMAgX6TXf5cbMWnZGRztjLXaqyiO+B7nxO eckHtFa91C34Chm24fO0NfbfZJEQHOh1/tyQEwaa/3YrY3neAqORphbn2IfTJN8plziQXu6NhN4 twLZh/fqWMLJA5ToN6QojcWpjLmxYExB7A4+bprzZEa+Z9dMx4rQSZdWSadJMxR5ZUsRplnHl/f jETNgOGhDxsvM434Z0w0cnN3b1adIESCsNVTqKU0JrCCwC8M7w76CRnOFE/H1k6P4DfegS9yium r5xs8CPjmIV+ndsrTSy2ivLSGHxgaOY7O5sLt/lXnC45Ob6NDpuVgIluLP88FubkFZ3Pzc5bhzo kx3U8pa2YSgvOFP8VpbwcKwGE8DZKiG7daSgLExscrN/a6YPMTv8XEqdEGHjeBEKM+R2N0ofsUU 0SqTQb0C4tdczmA== X-Developer-Key: i=jlayton@kernel.org; a=openpgp; fpr=4BC0D7B24471B2A184EAF5D3000E684119568215 If the client requested dir attribute change notifications, send those alongside any set of add/remove/rename events. Note that the server will still recall the delegation on a SETATTR, so these are only sent for changes to child dirents. The child filehandle returned in these notifications is composed by setup_notify_fhandle() without going through fh_compose(), so it does not get a MAC appended. On exports configured with NFSEXP_SIGN_FH the client would then get back an unsigned filehandle that fh_verify() rejects as stale. Pass the delegation's export down to setup_notify_fhandle() and append the MAC with fh_append_mac() when the export requires signed filehandles; if signing fails, drop the filehandle attribute rather than handing out an unusable one. Signed-off-by: Jeff Layton --- fs/nfsd/nfs4state.c | 25 ++++++++++++++++-- fs/nfsd/nfs4xdr.c | 73 +++++++++++++++++++++++++++++++++++++++++++++----= ---- fs/nfsd/xdr4.h | 2 ++ 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 12627afb604f..e394278fb92e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3503,10 +3503,15 @@ nfsd4_cb_notify_prepare(struct nfsd4_callback *cb) struct nfsd_notify_event *events[NOTIFY4_EVENT_QUEUE_SIZE]; struct xdr_buf xdr =3D { .buflen =3D PAGE_SIZE * NOTIFY4_PAGE_ARRAY_SIZE, .pages =3D ncn->ncn_pages }; + int limit =3D NOTIFY4_EVENT_QUEUE_SIZE; struct xdr_stream stream; struct nfsd_file *nf; - int count, i; bool error =3D false; + int count, i; + + /* Save a slot for dir attr update if requested */ + if (dp->dl_notify_mask & BIT(NOTIFY4_CHANGE_DIR_ATTRS)) + --limit; =20 xdr_init_encode_pages(&stream, &xdr); =20 @@ -3520,7 +3525,7 @@ nfsd4_cb_notify_prepare(struct nfsd4_callback *cb) } =20 /* we can't keep up! */ - if (count > NOTIFY4_EVENT_QUEUE_SIZE) { + if (count > limit) { spin_unlock(&ncn->ncn_lock); goto out_recall; } @@ -3567,6 +3572,22 @@ nfsd4_cb_notify_prepare(struct nfsd4_callback *cb) nfsd_notify_event_put(nne); } if (!error) { + if (dp->dl_notify_mask & BIT(NOTIFY4_CHANGE_DIR_ATTRS)) { + u32 *maskp =3D (u32 *)xdr_reserve_space(&stream, sizeof(*maskp)); + + if (maskp) { + u8 *p =3D nfsd4_encode_dir_attr_change(&stream, dp, nf); + + if (p) { + *maskp =3D BIT(NOTIFY4_CHANGE_DIR_ATTRS); + ncn->ncn_nf[count].notify_mask.count =3D 1; + ncn->ncn_nf[count].notify_mask.element =3D maskp; + ncn->ncn_nf[count].notify_vals.data =3D p; + ncn->ncn_nf[count].notify_vals.len =3D (u8 *)stream.p - p; + ++count; + } + } + } ncn->ncn_nf_cnt =3D count; nfsd_file_put(nf); return true; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 1e3c360c06cd..7dd8476028d6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4199,7 +4199,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xd= r_stream *xdr, =20 static bool setup_notify_fhandle(struct dentry *dentry, struct nfs4_file *fi, - struct nfsd_file *nf, struct nfsd4_fattr_args *args) + struct nfsd_file *nf, struct svc_export *exp, + struct nfsd4_fattr_args *args) { int fileid_type, fsid_len, maxsize, flags =3D 0; struct knfsd_fh *fhp =3D &args->fhandle; @@ -4227,6 +4228,17 @@ setup_notify_fhandle(struct dentry *dentry, struct n= fs4_file *fi, =20 fhp->fh_fileid_type =3D fileid_type; fhp->fh_size +=3D maxsize * 4; + + /* + * fh_compose() appends a MAC to filehandles on signed exports; this + * hand-rolled filehandle must do the same or the client will get back + * an unsigned filehandle that fh_verify() later rejects as stale. + * If we can't sign it, don't hand it out at all. + */ + if (exp && (exp->ex_flags & NFSEXP_SIGN_FH)) + if (!fh_append_mac(fhp, NFS4_FHSIZE, exp->cd->net)) + return false; + return true; } =20 @@ -4240,11 +4252,11 @@ nfsd4_setup_notify_entry4(struct notify_entry4 *ne,= struct xdr_stream *xdr, struct nfsd_file *nf, char *name, u32 namelen) { struct nfs4_file *fi =3D dp->dl_stid.sc_file; - struct path path =3D { .mnt =3D nf->nf_file->f_path.mnt, - .dentry =3D dentry }; + struct path path =3D nf->nf_file->f_path; struct nfsd4_fattr_args args =3D { }; uint32_t *attrmask; __be32 status; + bool parent; int ret; =20 /* Reserve space for attrmask */ @@ -4256,6 +4268,9 @@ nfsd4_setup_notify_entry4(struct notify_entry4 *ne, s= truct xdr_stream *xdr, ne->ne_file.len =3D namelen; ne->ne_attrs.attrmask.element =3D attrmask; =20 + parent =3D (dentry =3D=3D path.dentry); + path.dentry =3D dentry; + /* FIXME: d_find_alias for inode ? */ if (!path.dentry || !d_inode(path.dentry)) goto noattrs; @@ -4271,15 +4286,21 @@ nfsd4_setup_notify_entry4(struct notify_entry4 *ne,= struct xdr_stream *xdr, =20 args.change_attr =3D nfsd4_change_attribute(&args.stat); =20 - attrmask[0] =3D dp->dl_child_attrs[0]; - attrmask[1] =3D dp->dl_child_attrs[1]; - attrmask[2] =3D 0; + if (parent) { + attrmask[0] =3D dp->dl_dir_attrs[0]; + attrmask[1] =3D dp->dl_dir_attrs[1]; + } else { + attrmask[0] =3D dp->dl_child_attrs[0]; + attrmask[1] =3D dp->dl_child_attrs[1]; =20 - if (!setup_notify_fhandle(dentry, fi, nf, &args)) - attrmask[0] &=3D ~FATTR4_WORD0_FILEHANDLE; + if (!setup_notify_fhandle(dentry, fi, nf, + dp->dl_stid.sc_export, &args)) + attrmask[0] &=3D ~FATTR4_WORD0_FILEHANDLE; =20 - if (!(args.stat.result_mask & STATX_BTIME)) - attrmask[1] &=3D ~FATTR4_WORD1_TIME_CREATE; + if (!(args.stat.result_mask & STATX_BTIME)) + attrmask[1] &=3D ~FATTR4_WORD1_TIME_CREATE; + } + attrmask[2] =3D 0; =20 ne->ne_attrs.attrmask.count =3D 2; ne->ne_attrs.attr_vals.data =3D (u8 *)xdr->p; @@ -4392,6 +4413,38 @@ u8 *nfsd4_encode_notify_event(struct xdr_stream *xdr= , struct nfsd_notify_event * return NULL; } =20 +/** + * nfsd4_encode_dir_attr_change + * @xdr: stream to which to encode the fattr4 + * @dp: delegation where the event occurred + * @nf: nfsd_file opened on the directory + * + * Encode a dir attr change event. + */ +u8 *nfsd4_encode_dir_attr_change(struct xdr_stream *xdr, struct nfs4_deleg= ation *dp, + struct nfsd_file *nf) +{ + struct dentry *dentry =3D nf->nf_file->f_path.dentry; + struct notify_attr4 na =3D { }; + bool ret; + u8 *p =3D NULL; + + if (!(dp->dl_notify_mask & BIT(NOTIFY4_CHANGE_DIR_ATTRS))) + return NULL; + + /* RFC 8881 s10.4.3: ne_file must be a zero-length string for dir attrs */ + ret =3D nfsd4_setup_notify_entry4(&na.na_changed_entry, xdr, + dentry, dp, nf, "", 0); + + /* Don't bother with the event if we're not encoding attrs */ + if (ret && na.na_changed_entry.ne_attrs.attr_vals.len) { + p =3D (u8 *)xdr->p; + if (!xdrgen_encode_notify_attr4(xdr, &na)) + p =3D NULL; + } + return p; +} + static void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p, int bytes) { diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 62ac790428be..805c7122eb93 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -973,6 +973,8 @@ __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words, u8 *nfsd4_encode_notify_event(struct xdr_stream *xdr, struct nfsd_notify_e= vent *nne, struct nfs4_delegation *dd, struct nfsd_file *nf, u32 *notify_mask); +u8 *nfsd4_encode_dir_attr_change(struct xdr_stream *xdr, struct nfs4_deleg= ation *dp, + struct nfsd_file *nf); extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *, union nfsd4_op_u *u); extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, --=20 2.54.0