* [PATCH v2 00/42] Clarify module API boundaries
@ 2026-01-23 18:52 Chuck Lever
2026-01-23 18:52 ` [PATCH v2 01/42] lockd: Simplify cast_status() in svcproc.c Chuck Lever
` (42 more replies)
0 siblings, 43 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The first thirteen patches in this series refactor the lockd code
base to clearly separate its public API from internal implementation
details. The remainder are presented for context, but demonstrate
the intended purpose of the clean-up in the first thirteen.
The lockd subsystem currently exposes internal implementation headers
through include/linux/lockd/, creating implicit API contracts that
complicate maintenance. External consumers such as NFSD and the NFS
client have developed dependencies on internal structures like struct
nlm_host, and wire protocol constants leak into high-level module
interfaces.
These patches work to establish clean architectural boundaries. The
public API in include/linux/lockd/ is reduced to bind.h and nlm.h,
which define the contract between lockd and its consumers. Private
implementation details including XDR definitions, share management,
and host structures are relocated to fs/lockd/ where they belong.
Layering violations are corrected: the NFS client now uses accessor
helpers instead of dereferencing internal structures, and nlm_fopen()
returns errno values instead of wire protocol codes.
These changes enable subsequent work to modernize the NLMv4 XDR
layer using xdrgen without risk of breaking external consumers.
This work appears in the remaining patches in this series, which
are presented here only to provide context for the API adjustments.
No need to review those closely just yet.
The series is based on the public nfsd-testing branch.
---
Changes since v1:
- Refine the pre-requisite header adjustments
- Reduce stack consumption by moving large structures to wrappers
- Additional extensive clean up
Chuck Lever (42):
lockd: Simplify cast_status() in svcproc.c
lockd: Introduce nlm__int__deadlock
lockd: Have nlm_fopen() return errno values
lockd: Relocate nlmsvc_unlock API declarations
NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt
lockd: Move xdr4.h from include/linux/lockd/ to fs/lockd/
lockd: Move share.h from include/linux/lockd/ to fs/lockd/
lockd: Relocate include/linux/lockd/lockd.h
lockd: Remove lockd/debug.h
lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/
lockd: Make linux/lockd/nlm.h an internal header
lockd: Move nlm4svc_set_file_lock_range()
lockd: Relocate svc_version definitions to XDR layer
Documentation: Add the RPC language description of NLM version 4
lockd: Use xdrgen XDR functions for the NLMv4 NULL procedure
lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure
lockd: Use xdrgen XDR functions for the NLMv4 LOCK procedure
lockd: Use xdrgen XDR functions for the NLMv4 CANCEL procedure
lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK procedure
lockd: Use xdrgen XDR functions for the NLMv4 GRANTED procedure
lockd: Refactor nlm4svc_callback()
lockd: Use xdrgen XDR functions for the NLMv4 TEST_MSG procedure
lockd: Use xdrgen XDR functions for the NLMv4 LOCK_MSG procedure
lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_MSG procedure
lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_MSG procedure
lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_MSG procedure
lockd: Use xdrgen XDR functions for the NLMv4 TEST_RES procedure
lockd: Use xdrgen XDR functions for the NLMv4 LOCK_RES procedure
lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_RES procedure
lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_RES procedure
lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_RES procedure
lockd: Use xdrgen XDR functions for the NLMv4 SM_NOTIFY procedure
lockd: Convert server-side undefined procedures to xdrgen
lockd: Hoist file_lock init out of nlm4svc_decode_shareargs()
lockd: Prepare share helpers for xdrgen conversion
lockd: Use xdrgen XDR functions for the NLMv4 SHARE procedure
lockd: Use xdrgen XDR functions for the NLMv4 UNSHARE procedure
lockd: Use xdrgen XDR functions for the NLMv4 NM_LOCK procedure
lockd: Use xdrgen XDR functions for the NLMv4 FREE_ALL procedure
lockd: Add LOCKD_SHARE_SVID constant for DOS sharing mode
lockd: Remove C macros that are no longer used
lockd: Remove dead code from fs/lockd/xdr4.c
Documentation/sunrpc/xdr/nlm4.x | 211 ++++
fs/lockd/Makefile | 30 +-
fs/lockd/clnt4xdr.c | 5 +-
fs/lockd/clntlock.c | 2 +-
fs/lockd/clntproc.c | 2 +-
fs/lockd/clntxdr.c | 3 +-
fs/lockd/host.c | 2 +-
{include/linux => fs}/lockd/lockd.h | 99 +-
fs/lockd/mon.c | 2 +-
{include/linux => fs}/lockd/nlm.h | 8 +-
fs/lockd/nlm4xdr_gen.c | 724 +++++++++++
fs/lockd/nlm4xdr_gen.h | 32 +
{include/linux => fs}/lockd/share.h | 19 +-
fs/lockd/svc.c | 50 +-
fs/lockd/svc4proc.c | 1783 ++++++++++++++++++---------
fs/lockd/svclock.c | 12 +-
fs/lockd/svcproc.c | 99 +-
fs/lockd/svcshare.c | 40 +-
fs/lockd/svcsubs.c | 32 +-
fs/lockd/trace.h | 3 +-
fs/lockd/xdr.c | 6 +-
{include/linux => fs}/lockd/xdr.h | 15 +-
fs/lockd/xdr4.c | 347 ------
fs/nfs/sysfs.c | 10 +-
fs/nfsd/lockd.c | 51 +-
fs/nfsd/nfsctl.c | 2 +-
include/linux/lockd/bind.h | 23 +-
include/linux/lockd/debug.h | 40 -
include/linux/lockd/xdr4.h | 43 -
include/linux/sunrpc/xdrgen/nlm4.h | 233 ++++
30 files changed, 2750 insertions(+), 1178 deletions(-)
create mode 100644 Documentation/sunrpc/xdr/nlm4.x
rename {include/linux => fs}/lockd/lockd.h (84%)
rename {include/linux => fs}/lockd/nlm.h (91%)
create mode 100644 fs/lockd/nlm4xdr_gen.c
create mode 100644 fs/lockd/nlm4xdr_gen.h
rename {include/linux => fs}/lockd/share.h (58%)
rename {include/linux => fs}/lockd/xdr.h (91%)
delete mode 100644 fs/lockd/xdr4.c
delete mode 100644 include/linux/lockd/debug.h
delete mode 100644 include/linux/lockd/xdr4.h
create mode 100644 include/linux/sunrpc/xdrgen/nlm4.h
--
2.52.0
^ permalink raw reply [flat|nested] 53+ messages in thread
* [PATCH v2 01/42] lockd: Simplify cast_status() in svcproc.c
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 02/42] lockd: Introduce nlm__int__deadlock Chuck Lever
` (41 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Clean up: The svcproc.c file handles only NLM v1 and v3 requests.
NLMv4 requests are routed to a separate procedure table in
svc4proc.c, so rqstp->rq_vers can never be 4 in this context.
Remove the unused vers parameter and the dead "vers != 4" check from
cast_to_nlm(). This eliminates the need for the macro wrapper.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svcproc.c | 40 +++++++++++++++++++---------------------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 5817ef272332..95c6bf7ab757 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -17,32 +17,30 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT
#ifdef CONFIG_LOCKD_V4
-static __be32
-cast_to_nlm(__be32 status, u32 vers)
+static inline __be32 cast_status(__be32 status)
{
- /* Note: status is assumed to be in network byte order !!! */
- if (vers != 4){
- switch (status) {
- case nlm_granted:
- case nlm_lck_denied:
- case nlm_lck_denied_nolocks:
- case nlm_lck_blocked:
- case nlm_lck_denied_grace_period:
- case nlm_drop_reply:
- break;
- case nlm4_deadlock:
- status = nlm_lck_denied;
- break;
- default:
- status = nlm_lck_denied_nolocks;
- }
+ switch (status) {
+ case nlm_granted:
+ case nlm_lck_denied:
+ case nlm_lck_denied_nolocks:
+ case nlm_lck_blocked:
+ case nlm_lck_denied_grace_period:
+ case nlm_drop_reply:
+ break;
+ case nlm4_deadlock:
+ status = nlm_lck_denied;
+ break;
+ default:
+ status = nlm_lck_denied_nolocks;
}
- return (status);
+ return status;
}
-#define cast_status(status) (cast_to_nlm(status, rqstp->rq_vers))
#else
-#define cast_status(status) (status)
+static inline __be32 cast_status(__be32 status)
+{
+ return status;
+}
#endif
/*
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 02/42] lockd: Introduce nlm__int__deadlock
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
2026-01-23 18:52 ` [PATCH v2 01/42] lockd: Simplify cast_status() in svcproc.c Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-26 12:34 ` Jeff Layton
2026-01-23 18:52 ` [PATCH v2 03/42] lockd: Have nlm_fopen() return errno values Chuck Lever
` (40 subsequent siblings)
42 siblings, 1 reply; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The use of CONFIG_LOCKD_V4 in combination with a later cast_status()
in the NLMv3 code is difficult to reason about. Instead, replace the
use of nlm_deadlock with an implementation-defined status value that
version-specific code translates appropriately.
The new approach establishes a translation boundary: generic lockd
code returns nlm__int__deadlock when posix_lock_file() yields
-EDEADLK. Version-specific handlers (svc4proc.c for NLMv4,
svcproc.c for NLMv3) translate this internal status to the
appropriate wire protocol value. NLMv4 maps to nlm4_deadlock;
NLMv3 maps to nlm_lck_denied (since NLMv3 lacks a deadlock-specific
status code).
Later this modification will also remove the need to include NLMv4
headers in NLMv3 and generic code.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 10 ++++++++--
fs/lockd/svclock.c | 8 +-------
fs/lockd/svcproc.c | 4 +++-
include/linux/lockd/lockd.h | 7 +++++++
include/linux/lockd/xdr.h | 2 --
5 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 4b6f18d97734..061686b36b38 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -146,10 +146,16 @@ __nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp)
resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
argp->block, &argp->cookie,
argp->reclaim);
- if (resp->status == nlm_drop_reply)
+ switch (resp->status) {
+ case nlm_drop_reply:
rc = rpc_drop_reply;
- else
+ break;
+ case nlm__int__deadlock:
+ resp->status = nlm4_deadlock;
+ fallthrough;
+ default:
dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
+ }
nlmsvc_release_lockowner(&argp->lock);
nlmsvc_release_host(host);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 712df1e025d8..e80e3b4ee689 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -33,12 +33,6 @@
#define NLMDBG_FACILITY NLMDBG_SVCLOCK
-#ifdef CONFIG_LOCKD_V4
-#define nlm_deadlock nlm4_deadlock
-#else
-#define nlm_deadlock nlm_lck_denied
-#endif
-
static void nlmsvc_release_block(struct nlm_block *block);
static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
static void nlmsvc_remove_block(struct nlm_block *block);
@@ -589,7 +583,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
goto out;
case -EDEADLK:
nlmsvc_remove_block(block);
- ret = nlm_deadlock;
+ ret = nlm__int__deadlock;
goto out;
default: /* includes ENOLCK */
nlmsvc_remove_block(block);
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 95c6bf7ab757..3e890534c3dc 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -27,7 +27,7 @@ static inline __be32 cast_status(__be32 status)
case nlm_lck_denied_grace_period:
case nlm_drop_reply:
break;
- case nlm4_deadlock:
+ case nlm__int__deadlock:
status = nlm_lck_denied;
break;
default:
@@ -39,6 +39,8 @@ static inline __be32 cast_status(__be32 status)
#else
static inline __be32 cast_status(__be32 status)
{
+ if (status == nlm__int__deadlock)
+ status = nlm_lck_denied;
return status;
}
#endif
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 330e38776bb2..36a744f212ca 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -38,6 +38,13 @@
*/
#define LOCKD_DFLT_TIMEO 10
+/*
+ * Internal-use status codes, not to be placed on the wire.
+ * Version handlers translate these to appropriate wire values.
+ */
+#define nlm_drop_reply cpu_to_be32(30000)
+#define nlm__int__deadlock cpu_to_be32(30001)
+
/*
* Lockd host handle (used both by the client and server personality).
*/
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index 17d53165d9f2..292e4e38d17d 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -33,8 +33,6 @@ struct svc_rqst;
#define nlm_lck_blocked cpu_to_be32(NLM_LCK_BLOCKED)
#define nlm_lck_denied_grace_period cpu_to_be32(NLM_LCK_DENIED_GRACE_PERIOD)
-#define nlm_drop_reply cpu_to_be32(30000)
-
/* Lock info passed via NLM */
struct nlm_lock {
char * caller;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 03/42] lockd: Have nlm_fopen() return errno values
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
2026-01-23 18:52 ` [PATCH v2 01/42] lockd: Simplify cast_status() in svcproc.c Chuck Lever
2026-01-23 18:52 ` [PATCH v2 02/42] lockd: Introduce nlm__int__deadlock Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 04/42] lockd: Relocate nlmsvc_unlock API declarations Chuck Lever
` (39 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The nlm_fopen() function is part of the API between nfsd and lockd.
Currently its return value is an on-the-wire NLM status code. But
that forces NFSD to include NLM wire protocol definitions despite
having no other dependency on the NLM wire protocol.
In addition, a CONFIG_LOCKD_V4 Kconfig symbol appears in the middle
of NFSD source code.
Refactor: Let's not use on-the-wire values as part of a high-level
API between two Linux kernel modules. That's what we have errno for,
right?
And, instead of simply moving the CONFIG_LOCKD_V4 check, we can get
rid of it entirely and let the decision of what actual NLM status
code goes on the wire to be left up to NLM version-specific code.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 13 +++++++---
fs/lockd/svcproc.c | 9 ++++++-
fs/lockd/svcsubs.c | 27 +++++++++++++++-----
fs/nfsd/lockd.c | 50 +++++++++++++++++++++----------------
include/linux/lockd/bind.h | 8 +++---
include/linux/lockd/lockd.h | 2 ++
6 files changed, 72 insertions(+), 37 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 061686b36b38..bcad4efdf4ab 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -73,9 +73,16 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
no_locks:
nlmsvc_release_host(host);
- if (error)
- return error;
- return nlm_lck_denied_nolocks;
+ switch (error) {
+ case nlm_granted:
+ return nlm_lck_denied_nolocks;
+ case nlm__int__stale_fh:
+ return nlm4_stale_fh;
+ case nlm__int__failed:
+ return nlm4_failed;
+ default:
+ return error;
+ }
}
/*
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 3e890534c3dc..557dfd9c2a9e 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -39,8 +39,15 @@ static inline __be32 cast_status(__be32 status)
#else
static inline __be32 cast_status(__be32 status)
{
- if (status == nlm__int__deadlock)
+ switch (status) {
+ case nlm__int__deadlock:
status = nlm_lck_denied;
+ break;
+ case nlm__int__stale_fh:
+ case nlm__int__failed:
+ status = nlm_lck_denied_nolocks;
+ break;
+ }
return status;
}
#endif
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 9103896164f6..e3ceb0745464 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -87,14 +87,29 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
struct nlm_file *file, int mode)
{
struct file **fp = &file->f_file[mode];
- __be32 nfserr;
+ __be32 nlmerr = nlm_granted;
+ int error;
if (*fp)
- return 0;
- nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode);
- if (nfserr)
- dprintk("lockd: open failed (error %d)\n", nfserr);
- return nfserr;
+ return nlmerr;
+
+ error = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode);
+ if (error) {
+ dprintk("lockd: open failed (errno %d)\n", error);
+ switch (error) {
+ case -EWOULDBLOCK:
+ nlmerr = nlm_drop_reply;
+ break;
+ case -ESTALE:
+ nlmerr = nlm__int__stale_fh;
+ break;
+ default:
+ nlmerr = nlm__int__failed;
+ break;
+ }
+ }
+
+ return nlmerr;
}
/*
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index c774ce9aa296..6fe1325815e0 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -14,19 +14,20 @@
#define NFSDDBG_FACILITY NFSDDBG_LOCKD
-#ifdef CONFIG_LOCKD_V4
-#define nlm_stale_fh nlm4_stale_fh
-#define nlm_failed nlm4_failed
-#else
-#define nlm_stale_fh nlm_lck_denied_nolocks
-#define nlm_failed nlm_lck_denied_nolocks
-#endif
-/*
- * Note: we hold the dentry use count while the file is open.
+/**
+ * nlm_fopen - Open an NFSD file
+ * @rqstp: NLM RPC procedure execution context
+ * @f: NFS file handle to be opened
+ * @filp: OUT: an opened struct file
+ * @flags: the POSIX open flags to use
+ *
+ * nlm_fopen() holds the dentry reference until nlm_fclose() releases it.
+ *
+ * Returns zero on success or a negative errno value if the file
+ * cannot be opened.
*/
-static __be32
-nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp,
- int mode)
+static int nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f,
+ struct file **filp, int flags)
{
__be32 nfserr;
int access;
@@ -47,18 +48,17 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp,
* if NFSEXP_NOAUTHNLM is set. Some older clients use AUTH_NULL
* for NLM requests.
*/
- access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ;
+ access = (flags == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ;
access |= NFSD_MAY_NLM | NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_BYPASS_GSS;
nfserr = nfsd_open(rqstp, &fh, S_IFREG, access, filp);
fh_put(&fh);
- /* We return nlm error codes as nlm doesn't know
- * about nfsd, but nfsd does know about nlm..
- */
+
switch (nfserr) {
case nfs_ok:
- return 0;
+ break;
case nfserr_jukebox:
- /* this error can indicate a presence of a conflicting
+ /*
+ * This error can indicate a presence of a conflicting
* delegation to an NLM lock request. Options are:
* (1) For now, drop this request and make the client
* retry. When delegation is returned, client's lock retry
@@ -66,19 +66,25 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp,
* (2) NLM4_DENIED as per "spec" signals to the client
* that the lock is unavailable now but client can retry.
* Linux client implementation does not. It treats
- * NLM4_DENIED same as NLM4_FAILED and errors the request.
+ * NLM4_DENIED same as NLM4_FAILED and fails the request.
* (3) For the future, treat this as blocked lock and try
* to callback when the delegation is returned but might
* not have a proper lock request to block on.
*/
- return nlm_drop_reply;
+ return -EWOULDBLOCK;
case nfserr_stale:
- return nlm_stale_fh;
+ return -ESTALE;
default:
- return nlm_failed;
+ return -ENOLCK;
}
+
+ return 0;
}
+/**
+ * nlm_fclose - Close an NFSD file
+ * @filp: a struct file that was opened by nlm_fopen()
+ */
static void
nlm_fclose(struct file *filp)
{
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index c53c81242e72..2f5dd9e943ee 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -26,11 +26,9 @@ struct rpc_clnt;
* This is the set of functions for lockd->nfsd communication
*/
struct nlmsvc_binding {
- __be32 (*fopen)(struct svc_rqst *,
- struct nfs_fh *,
- struct file **,
- int mode);
- void (*fclose)(struct file *);
+ int (*fopen)(struct svc_rqst *rqstp, struct nfs_fh *f,
+ struct file **filp, int flags);
+ void (*fclose)(struct file *filp);
};
extern const struct nlmsvc_binding *nlmsvc_ops;
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 36a744f212ca..7bf402e772b0 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -44,6 +44,8 @@
*/
#define nlm_drop_reply cpu_to_be32(30000)
#define nlm__int__deadlock cpu_to_be32(30001)
+#define nlm__int__stale_fh cpu_to_be32(30002)
+#define nlm__int__failed cpu_to_be32(30003)
/*
* Lockd host handle (used both by the client and server personality).
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 04/42] lockd: Relocate nlmsvc_unlock API declarations
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (2 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 03/42] lockd: Have nlm_fopen() return errno values Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt Chuck Lever
` (38 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The nlmsvc_unlock_all_by_sb() and nlmsvc_unlock_all_by_ip()
functions are part of lockd's external API, consumed by other
kernel subsystems. Their declarations currently reside in
linux/lockd/lockd.h alongside internal implementation details,
which blurs the boundary between lockd's public interface and
its private internals.
Moving these declarations to linux/lockd/bind.h groups them
with other external API functions and makes the separation
explicit. This clarifies which functions are intended for
external use and reduces the risk of internal implementation
details leaking into the public API surface.
Build-tested with allyesconfig; no functional changes.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfsd/lockd.c | 1 +
fs/nfsd/nfsctl.c | 2 +-
include/linux/lockd/bind.h | 7 +++++++
include/linux/lockd/lockd.h | 6 ------
4 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 6fe1325815e0..ca805b708a30 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -8,6 +8,7 @@
*/
#include <linux/file.h>
+#include <linux/fs.h>
#include <linux/lockd/bind.h>
#include "nfsd.h"
#include "vfs.h"
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 30caefb2522f..ed0588f72133 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -11,7 +11,7 @@
#include <linux/fs_context.h>
#include <linux/sunrpc/svcsock.h>
-#include <linux/lockd/lockd.h>
+#include <linux/lockd/bind.h>
#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/gss_api.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 2f5dd9e943ee..82eca0a13ccc 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -21,6 +21,7 @@
struct svc_rqst;
struct rpc_task;
struct rpc_clnt;
+struct super_block;
/*
* This is the set of functions for lockd->nfsd communication
@@ -80,4 +81,10 @@ extern int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, vo
extern int lockd_up(struct net *net, const struct cred *cred);
extern void lockd_down(struct net *net);
+/*
+ * Cluster failover support
+ */
+int nlmsvc_unlock_all_by_sb(struct super_block *sb);
+int nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr);
+
#endif /* LINUX_LOCKD_BIND_H */
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 7bf402e772b0..fe6a14fe959a 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -311,12 +311,6 @@ void nlmsvc_mark_resources(struct net *);
void nlmsvc_free_host_resources(struct nlm_host *);
void nlmsvc_invalidate_all(void);
-/*
- * Cluster failover support
- */
-int nlmsvc_unlock_all_by_sb(struct super_block *sb);
-int nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr);
-
static inline struct file *nlmsvc_file_file(const struct nlm_file *file)
{
return file->f_file[O_RDONLY] ?
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (3 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 04/42] lockd: Relocate nlmsvc_unlock API declarations Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 20:23 ` Jeff Layton
2026-01-23 18:52 ` [PATCH v2 06/42] lockd: Move xdr4.h from include/linux/lockd/ to fs/lockd/ Chuck Lever
` (37 subsequent siblings)
42 siblings, 1 reply; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The external API definitions for lockd reside in linux/lockd/bind.h.
Because "struct nlm_host" is an internal lockd structure, bind.h
does not include a definition of it. Dereferencing that structure
outside of lockd violates the layering boundary between NFS and
lockd.
The proper approach is to use the nlmclnt_rpc_clnt() helper function
already provided in lockd/bind.h, which retrieves the NLM host's
struct rpc_clnt without exposing internal lockd structures. This
maintains clean separation between the NFS client and lockd
internals.
Note that the nlm_host's h_rpcclnt field can be NULL during
initialization (host.c:141) or after cleanup (host.c:629). Add a
NULL check before calling shutdown_client() to prevent a potential
NULL pointer dereference in the sysfs shutdown path.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfs/sysfs.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c
index ea6e6168092b..186b29de0129 100644
--- a/fs/nfs/sysfs.c
+++ b/fs/nfs/sysfs.c
@@ -12,7 +12,7 @@
#include <linux/string.h>
#include <linux/nfs_fs.h>
#include <linux/rcupdate.h>
-#include <linux/lockd/lockd.h>
+#include <linux/lockd/bind.h>
#include "internal.h"
#include "nfs4_fs.h"
@@ -284,8 +284,12 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
if (!IS_ERR(server->client_acl))
shutdown_client(server->client_acl);
- if (server->nlm_host)
- shutdown_client(server->nlm_host->h_rpcclnt);
+ if (server->nlm_host) {
+ struct rpc_clnt *nlm_clnt = nlmclnt_rpc_clnt(server->nlm_host);
+
+ if (nlm_clnt)
+ shutdown_client(nlm_clnt);
+ }
out:
shutdown_nfs_client(server->nfs_client);
return count;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 06/42] lockd: Move xdr4.h from include/linux/lockd/ to fs/lockd/
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (4 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 07/42] lockd: Move share.h " Chuck Lever
` (36 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The xdr4.h header declares NLMv4-specific XDR encoder/decoder
functions and error codes that are used exclusively within the
lockd subsystem. Moving it from include/linux/lockd/ to fs/lockd/
clarifies the intended scope of these declarations and prevents
external code from depending on lockd-internal interfaces.
This change reduces the public API surface of the lockd module
and makes it easier to refactor NLMv4 internals without risk of
breaking out-of-tree consumers. The header's contents are
implementation details of the NLMv4 wire protocol handling, not
a contract with other kernel subsystems.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/clnt4xdr.c | 2 ++
fs/lockd/svc4proc.c | 2 ++
fs/lockd/xdr4.c | 1 +
{include/linux => fs}/lockd/xdr4.h | 15 +++------------
include/linux/lockd/bind.h | 3 ---
include/linux/lockd/lockd.h | 7 ++++---
6 files changed, 12 insertions(+), 18 deletions(-)
rename {include/linux => fs}/lockd/xdr4.h (84%)
diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c
index 527458db4525..23896073c7e5 100644
--- a/fs/lockd/clnt4xdr.c
+++ b/fs/lockd/clnt4xdr.c
@@ -17,6 +17,8 @@
#include <uapi/linux/nfs3.h>
+#include "xdr4.h"
+
#define NLMDBG_FACILITY NLMDBG_XDR
#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index bcad4efdf4ab..eb485bc6c7dd 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -14,6 +14,8 @@
#include <linux/lockd/share.h>
#include <linux/sunrpc/svc_xprt.h>
+#include "xdr4.h"
+
#define NLMDBG_FACILITY NLMDBG_CLIENT
/*
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index e343c820301f..5b1e15977697 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -19,6 +19,7 @@
#include <linux/lockd/lockd.h>
#include "svcxdr.h"
+#include "xdr4.h"
static inline s64
loff_t_to_s64(loff_t offset)
diff --git a/include/linux/lockd/xdr4.h b/fs/lockd/xdr4.h
similarity index 84%
rename from include/linux/lockd/xdr4.h
rename to fs/lockd/xdr4.h
index 72831e35dca3..7be318c0512b 100644
--- a/include/linux/lockd/xdr4.h
+++ b/fs/lockd/xdr4.h
@@ -1,19 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * linux/include/linux/lockd/xdr4.h
- *
* XDR types for the NLM protocol
*
* Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
*/
-#ifndef LOCKD_XDR4_H
-#define LOCKD_XDR4_H
-
-#include <linux/fs.h>
-#include <linux/nfs.h>
-#include <linux/sunrpc/xdr.h>
-#include <linux/lockd/xdr.h>
+#ifndef _LOCKD_XDR4_H
+#define _LOCKD_XDR4_H
/* error codes new to NLMv4 */
#define nlm4_deadlock cpu_to_be32(NLM_DEADLCK)
@@ -38,6 +31,4 @@ bool nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-extern const struct rpc_version nlm_version4;
-
-#endif /* LOCKD_XDR4_H */
+#endif /* _LOCKD_XDR4_H */
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 82eca0a13ccc..a7f765e397a0 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -13,9 +13,6 @@
#include <linux/lockd/nlm.h>
/* need xdr-encoded error codes too, so... */
#include <linux/lockd/xdr.h>
-#ifdef CONFIG_LOCKD_V4
-#include <linux/lockd/xdr4.h>
-#endif
/* Dummy declarations */
struct svc_rqst;
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index fe6a14fe959a..6852bbc8f51a 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -22,9 +22,6 @@
#include <linux/utsname.h>
#include <linux/lockd/bind.h>
#include <linux/lockd/xdr.h>
-#ifdef CONFIG_LOCKD_V4
-#include <linux/lockd/xdr4.h>
-#endif
#include <linux/lockd/debug.h>
#include <linux/sunrpc/svc.h>
@@ -235,6 +232,10 @@ int nlmclnt_reclaim(struct nlm_host *, struct file_lock *,
struct nlm_rqst *);
void nlmclnt_next_cookie(struct nlm_cookie *);
+#ifdef CONFIG_LOCKD_V4
+extern const struct rpc_version nlm_version4;
+#endif
+
/*
* Host cache
*/
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 07/42] lockd: Move share.h from include/linux/lockd/ to fs/lockd/
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (5 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 06/42] lockd: Move xdr4.h from include/linux/lockd/ to fs/lockd/ Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 08/42] lockd: Relocate include/linux/lockd/lockd.h Chuck Lever
` (35 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The share.h header defines struct nlm_share and declares the DOS
share management functions used by the NLM server to implement
NLM_SHARE and NLM_UNSHARE operations. These interfaces are used
exclusively within the lockd subsystem. A git grep search confirms
no external code references them.
Relocating this header from include/linux/lockd/ to fs/lockd/
narrows the public API surface of the lockd module. Out-of-tree
code cannot depend on these internal interfaces after this change.
Future refactoring of the share management implementation thus
requires no consideration of external consumers.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
{include/linux => fs}/lockd/share.h | 8 +++-----
fs/lockd/svc4proc.c | 2 +-
fs/lockd/svcproc.c | 3 ++-
fs/lockd/svcshare.c | 3 ++-
fs/lockd/svcsubs.c | 3 ++-
include/linux/lockd/lockd.h | 2 ++
6 files changed, 12 insertions(+), 9 deletions(-)
rename {include/linux => fs}/lockd/share.h (85%)
diff --git a/include/linux/lockd/share.h b/fs/lockd/share.h
similarity index 85%
rename from include/linux/lockd/share.h
rename to fs/lockd/share.h
index 1f18a9faf645..d8f4ebd9c278 100644
--- a/include/linux/lockd/share.h
+++ b/fs/lockd/share.h
@@ -1,14 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * linux/include/linux/lockd/share.h
- *
* DOS share management for lockd.
*
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
-#ifndef LINUX_LOCKD_SHARE_H
-#define LINUX_LOCKD_SHARE_H
+#ifndef _LOCKD_SHARE_H
+#define _LOCKD_SHARE_H
/*
* DOS share for a specific file
@@ -29,4 +27,4 @@ __be32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *,
nlm_host_match_fn_t);
-#endif /* LINUX_LOCKD_SHARE_H */
+#endif /* _LOCKD_SHARE_H */
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index eb485bc6c7dd..0be5e5ce9de1 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -11,9 +11,9 @@
#include <linux/types.h>
#include <linux/time.h>
#include <linux/lockd/lockd.h>
-#include <linux/lockd/share.h>
#include <linux/sunrpc/svc_xprt.h>
+#include "share.h"
#include "xdr4.h"
#define NLMDBG_FACILITY NLMDBG_CLIENT
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 557dfd9c2a9e..c06b592756ee 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -11,9 +11,10 @@
#include <linux/types.h>
#include <linux/time.h>
#include <linux/lockd/lockd.h>
-#include <linux/lockd/share.h>
#include <linux/sunrpc/svc_xprt.h>
+#include "share.h"
+
#define NLMDBG_FACILITY NLMDBG_CLIENT
#ifdef CONFIG_LOCKD_V4
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 88c81ce1148d..8e06840834c6 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -15,7 +15,8 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
-#include <linux/lockd/share.h>
+
+#include "share.h"
static inline int
nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh)
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index e3ceb0745464..827861dd788f 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -16,11 +16,12 @@
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/addr.h>
#include <linux/lockd/lockd.h>
-#include <linux/lockd/share.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <uapi/linux/nfs2.h>
+#include "share.h"
+
#define NLMDBG_FACILITY NLMDBG_SVCSUBS
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 6852bbc8f51a..1dee8ddab108 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -155,6 +155,8 @@ struct nlm_rqst {
void * a_callback_data; /* sent to nlmclnt_operations callbacks */
};
+struct nlm_share;
+
/*
* This struct describes a file held open by lockd on behalf of
* an NFS client.
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 08/42] lockd: Relocate include/linux/lockd/lockd.h
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (6 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 07/42] lockd: Move share.h " Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 09/42] lockd: Remove lockd/debug.h Chuck Lever
` (34 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Headers placed in include/linux/ form part of the kernel's
internal API and signal to subsystem maintainers that other
parts of the kernel may depend on them. By moving lockd.h into
fs/lockd/, lockd becomes a more self-contained module whose
internal interfaces are clearly distinguished from its public
contract with the rest of the kernel. This relocation addresses
a long-standing XXX comment in the header itself that
acknowledged the file's misplacement. Future changes to lockd
internals can now proceed with confidence that external
consumers are not inadvertently coupled to implementation
details.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/clnt4xdr.c | 3 ++-
fs/lockd/clntlock.c | 2 +-
fs/lockd/clntproc.c | 2 +-
fs/lockd/clntxdr.c | 3 ++-
fs/lockd/host.c | 2 +-
{include/linux => fs}/lockd/lockd.h | 12 +++---------
fs/lockd/mon.c | 2 +-
fs/lockd/svc.c | 2 +-
fs/lockd/svc4proc.c | 2 +-
fs/lockd/svclock.c | 3 ++-
fs/lockd/svcproc.c | 2 +-
fs/lockd/svcshare.c | 2 +-
fs/lockd/svcsubs.c | 2 +-
fs/lockd/trace.h | 3 ++-
fs/lockd/xdr.c | 3 +--
fs/lockd/xdr4.c | 2 +-
16 files changed, 22 insertions(+), 25 deletions(-)
rename {include/linux => fs}/lockd/lockd.h (98%)
diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c
index 23896073c7e5..61ee5fa6dfa4 100644
--- a/fs/lockd/clnt4xdr.c
+++ b/fs/lockd/clnt4xdr.c
@@ -13,7 +13,8 @@
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
-#include <linux/lockd/lockd.h>
+
+#include "lockd.h"
#include <uapi/linux/nfs3.h>
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index a7e0519ec024..8a38d1b193fc 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -15,9 +15,9 @@
#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svc_xprt.h>
-#include <linux/lockd/lockd.h>
#include <linux/kthread.h>
+#include "lockd.h"
#include "trace.h"
#define NLMDBG_FACILITY NLMDBG_CLIENT
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index cebcc283b7ce..9be003bbf5ad 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -18,8 +18,8 @@
#include <linux/freezer.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
-#include <linux/lockd/lockd.h>
+#include "lockd.h"
#include "trace.h"
#define NLMDBG_FACILITY NLMDBG_CLIENT
diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c
index 6ea3448d2d31..65555f5224b1 100644
--- a/fs/lockd/clntxdr.c
+++ b/fs/lockd/clntxdr.c
@@ -15,7 +15,8 @@
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
-#include <linux/lockd/lockd.h>
+
+#include "lockd.h"
#include <uapi/linux/nfs2.h>
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 5e6877c37f73..4a6f596f7c73 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -16,13 +16,13 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/svc.h>
-#include <linux/lockd/lockd.h>
#include <linux/mutex.h>
#include <linux/sunrpc/svc_xprt.h>
#include <net/ipv6.h>
+#include "lockd.h"
#include "netns.h"
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
diff --git a/include/linux/lockd/lockd.h b/fs/lockd/lockd.h
similarity index 98%
rename from include/linux/lockd/lockd.h
rename to fs/lockd/lockd.h
index 1dee8ddab108..43813444091a 100644
--- a/include/linux/lockd/lockd.h
+++ b/fs/lockd/lockd.h
@@ -1,16 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * linux/include/linux/lockd/lockd.h
- *
- * General-purpose lockd include file.
- *
* Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
*/
-#ifndef LINUX_LOCKD_LOCKD_H
-#define LINUX_LOCKD_LOCKD_H
-
-/* XXX: a lot of this should really be under fs/lockd. */
+#ifndef _LOCKD_LOCKD_H
+#define _LOCKD_LOCKD_H
#include <linux/exportfs.h>
#include <linux/in.h>
@@ -398,4 +392,4 @@ static inline int nlm_compare_locks(const struct file_lock *fl1,
extern const struct lock_manager_operations nlmsvc_lock_operations;
-#endif /* LINUX_LOCKD_LOCKD_H */
+#endif /* _LOCKD_LOCKD_H */
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index b8fc732e1c67..3d3ee88ca4dc 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -16,10 +16,10 @@
#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/xprtsock.h>
#include <linux/sunrpc/svc.h>
-#include <linux/lockd/lockd.h>
#include <linux/unaligned.h>
+#include "lockd.h"
#include "netns.h"
#define NLMDBG_FACILITY NLMDBG_MONITOR
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index dcd80c4e74c9..9dd7f8e11544 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -36,9 +36,9 @@
#include <net/ip.h>
#include <net/addrconf.h>
#include <net/ipv6.h>
-#include <linux/lockd/lockd.h>
#include <linux/nfs.h>
+#include "lockd.h"
#include "netns.h"
#include "procfs.h"
#include "netlink.h"
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 0be5e5ce9de1..c934f832fd04 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -10,9 +10,9 @@
#include <linux/types.h>
#include <linux/time.h>
-#include <linux/lockd/lockd.h>
#include <linux/sunrpc/svc_xprt.h>
+#include "lockd.h"
#include "share.h"
#include "xdr4.h"
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index e80e3b4ee689..cd9e11781494 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -29,7 +29,8 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/lockd/nlm.h>
-#include <linux/lockd/lockd.h>
+
+#include "lockd.h"
#define NLMDBG_FACILITY NLMDBG_SVCLOCK
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index c06b592756ee..fdab66ff0fe8 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -10,9 +10,9 @@
#include <linux/types.h>
#include <linux/time.h>
-#include <linux/lockd/lockd.h>
#include <linux/sunrpc/svc_xprt.h>
+#include "lockd.h"
#include "share.h"
#define NLMDBG_FACILITY NLMDBG_CLIENT
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 8e06840834c6..8675ac80ab16 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -14,8 +14,8 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
-#include <linux/lockd/lockd.h>
+#include "lockd.h"
#include "share.h"
static inline int
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 827861dd788f..98a6f46c7bd3 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -15,11 +15,11 @@
#include <linux/mutex.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/addr.h>
-#include <linux/lockd/lockd.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <uapi/linux/nfs2.h>
+#include "lockd.h"
#include "share.h"
#define NLMDBG_FACILITY NLMDBG_SVCSUBS
diff --git a/fs/lockd/trace.h b/fs/lockd/trace.h
index 7461b13b6e74..7214d7e96a42 100644
--- a/fs/lockd/trace.h
+++ b/fs/lockd/trace.h
@@ -8,7 +8,8 @@
#include <linux/tracepoint.h>
#include <linux/crc32.h>
#include <linux/nfs.h>
-#include <linux/lockd/lockd.h>
+
+#include "lockd.h"
#ifdef CONFIG_LOCKD_V4
#define NLM_STATUS_LIST \
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index adfcce2bf11b..5aac49d1875a 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -15,13 +15,12 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/stats.h>
-#include <linux/lockd/lockd.h>
#include <uapi/linux/nfs2.h>
+#include "lockd.h"
#include "svcxdr.h"
-
static inline loff_t
s32_to_loff_t(__s32 offset)
{
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 5b1e15977697..f57d4881d5f1 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -16,8 +16,8 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/stats.h>
-#include <linux/lockd/lockd.h>
+#include "lockd.h"
#include "svcxdr.h"
#include "xdr4.h"
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 09/42] lockd: Remove lockd/debug.h
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (7 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 08/42] lockd: Relocate include/linux/lockd/lockd.h Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/ Chuck Lever
` (33 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The lockd include structure has unnecessary indirection. The header
include/linux/lockd/debug.h is consumed only by fs/lockd/lockd.h,
creating an extra compilation dependency and making the code harder
to navigate.
Fold the debug.h definitions directly into lockd.h and remove the
now-redundant header. This reduces the include tree depth and makes
the debug-related definitions easier to find when working on lockd
internals.
Build-tested with lockd built as module and built-in.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/lockd.h | 24 +++++++++++++++++++++-
include/linux/lockd/debug.h | 40 -------------------------------------
2 files changed, 23 insertions(+), 41 deletions(-)
delete mode 100644 include/linux/lockd/debug.h
diff --git a/fs/lockd/lockd.h b/fs/lockd/lockd.h
index 43813444091a..3ddbf8772b59 100644
--- a/fs/lockd/lockd.h
+++ b/fs/lockd/lockd.h
@@ -16,9 +16,31 @@
#include <linux/utsname.h>
#include <linux/lockd/bind.h>
#include <linux/lockd/xdr.h>
-#include <linux/lockd/debug.h>
+#include <linux/sunrpc/debug.h>
#include <linux/sunrpc/svc.h>
+/*
+ * Enable lockd debugging.
+ * Requires CONFIG_SUNRPC_DEBUG.
+ */
+#undef ifdebug
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
+# define ifdebug(flag) if (unlikely(nlm_debug & NLMDBG_##flag))
+#else
+# define ifdebug(flag) if (0)
+#endif
+
+#define NLMDBG_SVC 0x0001
+#define NLMDBG_CLIENT 0x0002
+#define NLMDBG_CLNTLOCK 0x0004
+#define NLMDBG_SVCLOCK 0x0008
+#define NLMDBG_MONITOR 0x0010
+#define NLMDBG_CLNTSUBS 0x0020
+#define NLMDBG_SVCSUBS 0x0040
+#define NLMDBG_HOSTCACHE 0x0080
+#define NLMDBG_XDR 0x0100
+#define NLMDBG_ALL 0x7fff
+
/*
* Version string
*/
diff --git a/include/linux/lockd/debug.h b/include/linux/lockd/debug.h
deleted file mode 100644
index eede2ab5246f..000000000000
--- a/include/linux/lockd/debug.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/include/linux/lockd/debug.h
- *
- * Debugging stuff.
- *
- * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef LINUX_LOCKD_DEBUG_H
-#define LINUX_LOCKD_DEBUG_H
-
-#include <linux/sunrpc/debug.h>
-
-/*
- * Enable lockd debugging.
- * Requires RPC_DEBUG.
- */
-#undef ifdebug
-#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
-# define ifdebug(flag) if (unlikely(nlm_debug & NLMDBG_##flag))
-#else
-# define ifdebug(flag) if (0)
-#endif
-
-/*
- * Debug flags
- */
-#define NLMDBG_SVC 0x0001
-#define NLMDBG_CLIENT 0x0002
-#define NLMDBG_CLNTLOCK 0x0004
-#define NLMDBG_SVCLOCK 0x0008
-#define NLMDBG_MONITOR 0x0010
-#define NLMDBG_CLNTSUBS 0x0020
-#define NLMDBG_SVCSUBS 0x0040
-#define NLMDBG_HOSTCACHE 0x0080
-#define NLMDBG_XDR 0x0100
-#define NLMDBG_ALL 0x7fff
-
-#endif /* LINUX_LOCKD_DEBUG_H */
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (8 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 09/42] lockd: Remove lockd/debug.h Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-24 1:20 ` kernel test robot
2026-01-24 2:57 ` kernel test robot
2026-01-23 18:52 ` [PATCH v2 11/42] lockd: Make linux/lockd/nlm.h an internal header Chuck Lever
` (32 subsequent siblings)
42 siblings, 2 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The lockd subsystem unnecessarily exposes internal NLM XDR type
definitions through the global include path. These definitions are
not used by any code outside fs/lockd/, making them inappropriate
for include/linux/lockd/.
Moving xdr.h to fs/lockd/ narrows the API surface and clarifies
that these types are internal implementation details. The comment
in linux/lockd/bind.h stating xdr.h was needed for "xdr-encoded
error codes" is stale: no lockd API consumers use those codes. A
forward declaration for struct nfs_fh is needed because its
definition was previously pulled in transitively through xdr.h.
Built and tested with lockd client/server operations. No functional
change.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/lockd.h | 2 +-
{include/linux => fs}/lockd/xdr.h | 8 +++-----
include/linux/lockd/bind.h | 3 +--
3 files changed, 5 insertions(+), 8 deletions(-)
rename {include/linux => fs}/lockd/xdr.h (96%)
diff --git a/fs/lockd/lockd.h b/fs/lockd/lockd.h
index 3ddbf8772b59..892c54198f1e 100644
--- a/fs/lockd/lockd.h
+++ b/fs/lockd/lockd.h
@@ -15,7 +15,7 @@
#include <linux/refcount.h>
#include <linux/utsname.h>
#include <linux/lockd/bind.h>
-#include <linux/lockd/xdr.h>
+#include "xdr.h"
#include <linux/sunrpc/debug.h>
#include <linux/sunrpc/svc.h>
diff --git a/include/linux/lockd/xdr.h b/fs/lockd/xdr.h
similarity index 96%
rename from include/linux/lockd/xdr.h
rename to fs/lockd/xdr.h
index 292e4e38d17d..af821ecf2a4e 100644
--- a/include/linux/lockd/xdr.h
+++ b/fs/lockd/xdr.h
@@ -1,14 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * linux/include/linux/lockd/xdr.h
- *
* XDR types for the NLM protocol
*
* Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
*/
-#ifndef LOCKD_XDR_H
-#define LOCKD_XDR_H
+#ifndef _LOCKD_XDR_H
+#define _LOCKD_XDR_H
#include <linux/fs.h>
#include <linux/filelock.h>
@@ -110,4 +108,4 @@ bool nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-#endif /* LOCKD_XDR_H */
+#endif /* _LOCKD_XDR_H */
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index a7f765e397a0..a65472139ff8 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -11,10 +11,9 @@
#define LINUX_LOCKD_BIND_H
#include <linux/lockd/nlm.h>
-/* need xdr-encoded error codes too, so... */
-#include <linux/lockd/xdr.h>
/* Dummy declarations */
+struct nfs_fh;
struct svc_rqst;
struct rpc_task;
struct rpc_clnt;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 11/42] lockd: Make linux/lockd/nlm.h an internal header
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (9 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/ Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 12/42] lockd: Move nlm4svc_set_file_lock_range() Chuck Lever
` (31 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The NLM protocol constants and status codes in nlm.h are needed
only by lockd's internal implementation. NFS client code and
NFSD interact with lockd through the stable API in bind.h and
have no direct use for protocol-level definitions.
Exposing these definitions globally via bind.h creates unnecessary
coupling between lockd internals and its consumers. Moving nlm.h
from include/linux/lockd/ to fs/lockd/ clarifies the API boundary:
bind.h provides the lockd service interface, while nlm.h remains
available only to code within fs/lockd/ that implements the
protocol.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/lockd.h | 1 +
{include/linux => fs}/lockd/nlm.h | 8 +++-----
fs/lockd/svclock.c | 1 -
include/linux/lockd/bind.h | 2 --
4 files changed, 4 insertions(+), 8 deletions(-)
rename {include/linux => fs}/lockd/nlm.h (91%)
diff --git a/fs/lockd/lockd.h b/fs/lockd/lockd.h
index 892c54198f1e..3f44820974cd 100644
--- a/fs/lockd/lockd.h
+++ b/fs/lockd/lockd.h
@@ -14,6 +14,7 @@
#include <linux/kref.h>
#include <linux/refcount.h>
#include <linux/utsname.h>
+#include "nlm.h"
#include <linux/lockd/bind.h>
#include "xdr.h"
#include <linux/sunrpc/debug.h>
diff --git a/include/linux/lockd/nlm.h b/fs/lockd/nlm.h
similarity index 91%
rename from include/linux/lockd/nlm.h
rename to fs/lockd/nlm.h
index 6e343ef760dc..47be65d0111f 100644
--- a/include/linux/lockd/nlm.h
+++ b/fs/lockd/nlm.h
@@ -1,14 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * linux/include/linux/lockd/nlm.h
- *
* Declarations for the Network Lock Manager protocol.
*
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
-#ifndef LINUX_LOCKD_NLM_H
-#define LINUX_LOCKD_NLM_H
+#ifndef _LOCKD_NLM_H
+#define _LOCKD_NLM_H
/* Maximum file offset in file_lock.fl_end */
@@ -55,4 +53,4 @@ enum {
#define NLMPROC_NM_LOCK 22
#define NLMPROC_FREE_ALL 23
-#endif /* LINUX_LOCKD_NLM_H */
+#endif /* _LOCKD_NLM_H */
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index cd9e11781494..6b3be2ff9c1c 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -28,7 +28,6 @@
#include <linux/sched.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc_xprt.h>
-#include <linux/lockd/nlm.h>
#include "lockd.h"
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index a65472139ff8..e6f1a4cdb685 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -10,8 +10,6 @@
#ifndef LINUX_LOCKD_BIND_H
#define LINUX_LOCKD_BIND_H
-#include <linux/lockd/nlm.h>
-
/* Dummy declarations */
struct nfs_fh;
struct svc_rqst;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 12/42] lockd: Move nlm4svc_set_file_lock_range()
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (10 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 11/42] lockd: Make linux/lockd/nlm.h an internal header Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 13/42] lockd: Relocate svc_version definitions to XDR layer Chuck Lever
` (30 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Refactor: nlm4svc_set_file_lock_range() is used by both the
client-side and server-side code. Remove the "svc" from the
name and relocate the function to a generic header.
This clean up partly enables the removal of '#include "xdr4.h"'
from fs/lockd/clnt4xdr.c.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/clnt4xdr.c | 2 +-
fs/lockd/lockd.h | 23 +++++++++++++++++++++++
fs/lockd/xdr4.c | 13 +------------
fs/lockd/xdr4.h | 1 -
4 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c
index 61ee5fa6dfa4..c09e67765cac 100644
--- a/fs/lockd/clnt4xdr.c
+++ b/fs/lockd/clnt4xdr.c
@@ -287,7 +287,7 @@ static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result)
fl->c.flc_type = exclusive != 0 ? F_WRLCK : F_RDLCK;
p = xdr_decode_hyper(p, &l_offset);
xdr_decode_hyper(p, &l_len);
- nlm4svc_set_file_lock_range(fl, l_offset, l_len);
+ lockd_set_file_lock_range4(fl, l_offset, l_len);
error = 0;
out:
return error;
diff --git a/fs/lockd/lockd.h b/fs/lockd/lockd.h
index 3f44820974cd..c889475a74e0 100644
--- a/fs/lockd/lockd.h
+++ b/fs/lockd/lockd.h
@@ -413,6 +413,29 @@ static inline int nlm_compare_locks(const struct file_lock *fl1,
&&(fl1->c.flc_type == fl2->c.flc_type || fl2->c.flc_type == F_UNLCK);
}
+/**
+ * lockd_set_file_lock_range4 - set the byte range of a file_lock
+ * @fl: file_lock whose length fields are to be initialized
+ * @off: starting offset of the lock, in bytes
+ * @len: length of the byte range, in bytes, or zero
+ *
+ * NLMv4 uses a (start, length) representation for lock byte ranges,
+ * while the kernel's file_lock uses (start, end). A length of zero
+ * means "lock to end of file." This function handles the conversion
+ * and also treats arithmetic overflow as "lock to end of file."
+ */
+static inline void
+lockd_set_file_lock_range4(struct file_lock *fl, u64 off, u64 len)
+{
+ s64 end = off + len - 1;
+
+ fl->fl_start = off;
+ if (len == 0 || end < 0)
+ fl->fl_end = OFFSET_MAX;
+ else
+ fl->fl_end = end;
+}
+
extern const struct lock_manager_operations nlmsvc_lock_operations;
#endif /* _LOCKD_LOCKD_H */
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index f57d4881d5f1..dbbb2dfcb81b 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -34,17 +34,6 @@ loff_t_to_s64(loff_t offset)
return res;
}
-void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len)
-{
- s64 end = off + len - 1;
-
- fl->fl_start = off;
- if (len == 0 || end < 0)
- fl->fl_end = OFFSET_MAX;
- else
- fl->fl_end = end;
-}
-
/*
* NLM file handles are defined by specification to be a variable-length
* XDR opaque no longer than 1024 bytes. However, this implementation
@@ -91,7 +80,7 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
locks_init_lock(fl);
fl->c.flc_type = F_RDLCK;
- nlm4svc_set_file_lock_range(fl, lock->lock_start, lock->lock_len);
+ lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len);
return true;
}
diff --git a/fs/lockd/xdr4.h b/fs/lockd/xdr4.h
index 7be318c0512b..4ddf51a2e0ea 100644
--- a/fs/lockd/xdr4.h
+++ b/fs/lockd/xdr4.h
@@ -15,7 +15,6 @@
#define nlm4_fbig cpu_to_be32(NLM_FBIG)
#define nlm4_failed cpu_to_be32(NLM_FAILED)
-void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len);
bool nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 13/42] lockd: Relocate svc_version definitions to XDR layer
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (11 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 12/42] lockd: Move nlm4svc_set_file_lock_range() Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 14/42] Documentation: Add the RPC language description of NLM version 4 Chuck Lever
` (29 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Public RPC server interfaces become cluttered when internal
XDR implementation details leak into them. The procedure count,
maximum XDR buffer size, and per-CPU call counters serve no
purpose outside the code that encodes and decodes NLM protocol
messages. Exposing these values through global headers creates
unnecessary coupling between the RPC dispatch logic and the
XDR layer.
Relocating the svc_version structure definitions confines this
implementation information to the files where XDR encoding and
decoding occur. In svc.c, the buffer size computation now reads
vs_xdrsize from the version structures rather than relying on a
preprocessor constant. This calculation occurs at service
initialization, after the linker has resolved the version
structure definitions. The dispatch function becomes non-static
because both the version structures and the dispatcher reside in
different translation units.
The NLMSVC_XDRSIZE macro is removed from xdr.h because buffer
size is now computed from the union of XDR argument and result
structures, matching the pattern used in other RPC services.
Version 1 and 3 share the same procedure table but maintain
separate counter arrays. Version 4 remains separate due to its
distinct procedure definitions.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/lockd.h | 6 ++++--
fs/lockd/svc.c | 48 +++++++++++----------------------------------
fs/lockd/svc4proc.c | 23 +++++++++++++++++++++-
fs/lockd/svcproc.c | 38 ++++++++++++++++++++++++++++++++++-
fs/lockd/xdr.h | 5 -----
5 files changed, 74 insertions(+), 46 deletions(-)
diff --git a/fs/lockd/lockd.h b/fs/lockd/lockd.h
index c889475a74e0..17db7b3ad2c7 100644
--- a/fs/lockd/lockd.h
+++ b/fs/lockd/lockd.h
@@ -221,9 +221,10 @@ struct nlm_block {
* Global variables
*/
extern const struct rpc_program nlm_program;
-extern const struct svc_procedure nlmsvc_procedures[24];
+extern const struct svc_version nlmsvc_version1;
+extern const struct svc_version nlmsvc_version3;
#ifdef CONFIG_LOCKD_V4
-extern const struct svc_procedure nlmsvc_procedures4[24];
+extern const struct svc_version nlmsvc_version4;
#endif
extern int nlmsvc_grace_period;
extern unsigned long nlm_timeout;
@@ -318,6 +319,7 @@ void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
void nlmsvc_grant_reply(struct nlm_cookie *, __be32);
void nlmsvc_release_call(struct nlm_rqst *);
void nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t);
+int nlmsvc_dispatch(struct svc_rqst *rqstp);
/*
* File handling for the server personality
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 9dd7f8e11544..490551369ef2 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -44,7 +44,6 @@
#include "netlink.h"
#define NLMDBG_FACILITY NLMDBG_SVC
-#define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE)
static struct svc_program nlmsvc_program;
@@ -319,6 +318,7 @@ static struct notifier_block lockd_inet6addr_notifier = {
static int lockd_get(void)
{
struct svc_serv *serv;
+ unsigned int bufsize;
int error;
if (nlmsvc_serv) {
@@ -334,7 +334,15 @@ static int lockd_get(void)
printk(KERN_WARNING
"lockd_up: no pid, %d users??\n", nlmsvc_users);
- serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, lockd);
+#ifdef CONFIG_LOCKD_V4
+ bufsize = 1024 + max3(nlmsvc_version1.vs_xdrsize,
+ nlmsvc_version3.vs_xdrsize,
+ nlmsvc_version4.vs_xdrsize);
+#else
+ bufsize = 1024 + max(nlmsvc_version1.vs_xdrsize,
+ nlmsvc_version3.vs_xdrsize);
+#endif
+ serv = svc_create(&nlmsvc_program, bufsize, lockd);
if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n");
return -ENOMEM;
@@ -640,7 +648,7 @@ module_exit(exit_nlm);
* %0: Processing complete; do not send a Reply
* %1: Processing complete; send Reply in rqstp->rq_res
*/
-static int nlmsvc_dispatch(struct svc_rqst *rqstp)
+int nlmsvc_dispatch(struct svc_rqst *rqstp)
{
const struct svc_procedure *procp = rqstp->rq_procinfo;
__be32 *statp = rqstp->rq_accept_statp;
@@ -671,40 +679,6 @@ static int nlmsvc_dispatch(struct svc_rqst *rqstp)
/*
* Define NLM program and procedures
*/
-static DEFINE_PER_CPU_ALIGNED(unsigned long, nlmsvc_version1_count[17]);
-static const struct svc_version nlmsvc_version1 = {
- .vs_vers = 1,
- .vs_nproc = 17,
- .vs_proc = nlmsvc_procedures,
- .vs_count = nlmsvc_version1_count,
- .vs_dispatch = nlmsvc_dispatch,
- .vs_xdrsize = NLMSVC_XDRSIZE,
-};
-
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nlmsvc_version3_count[ARRAY_SIZE(nlmsvc_procedures)]);
-static const struct svc_version nlmsvc_version3 = {
- .vs_vers = 3,
- .vs_nproc = ARRAY_SIZE(nlmsvc_procedures),
- .vs_proc = nlmsvc_procedures,
- .vs_count = nlmsvc_version3_count,
- .vs_dispatch = nlmsvc_dispatch,
- .vs_xdrsize = NLMSVC_XDRSIZE,
-};
-
-#ifdef CONFIG_LOCKD_V4
-static DEFINE_PER_CPU_ALIGNED(unsigned long,
- nlmsvc_version4_count[ARRAY_SIZE(nlmsvc_procedures4)]);
-static const struct svc_version nlmsvc_version4 = {
- .vs_vers = 4,
- .vs_nproc = ARRAY_SIZE(nlmsvc_procedures4),
- .vs_proc = nlmsvc_procedures4,
- .vs_count = nlmsvc_version4_count,
- .vs_dispatch = nlmsvc_dispatch,
- .vs_xdrsize = NLMSVC_XDRSIZE,
-};
-#endif
-
static const struct svc_version *nlmsvc_version[] = {
[1] = &nlmsvc_version1,
[3] = &nlmsvc_version3,
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index c934f832fd04..0f31fec178c8 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -519,7 +519,7 @@ struct nlm_void { int dummy; };
#define St 1 /* status */
#define Rg 4 /* range (offset + length) */
-const struct svc_procedure nlmsvc_procedures4[24] = {
+static const struct svc_procedure nlm4svc_procedures[24] = {
[NLMPROC_NULL] = {
.pc_func = nlm4svc_proc_null,
.pc_decode = nlm4svc_decode_void,
@@ -761,3 +761,24 @@ const struct svc_procedure nlmsvc_procedures4[24] = {
.pc_name = "FREE_ALL",
},
};
+
+/*
+ * Storage requirements for XDR arguments and results
+ */
+union nlm4svc_xdrstore {
+ struct nlm_args args;
+ struct nlm_res res;
+ struct nlm_reboot reboot;
+};
+
+static DEFINE_PER_CPU_ALIGNED(unsigned long,
+ nlm4svc_call_counters[ARRAY_SIZE(nlm4svc_procedures)]);
+
+const struct svc_version nlmsvc_version4 = {
+ .vs_vers = 4,
+ .vs_nproc = ARRAY_SIZE(nlm4svc_procedures),
+ .vs_proc = nlm4svc_procedures,
+ .vs_count = nlm4svc_call_counters,
+ .vs_dispatch = nlmsvc_dispatch,
+ .vs_xdrsize = sizeof(union nlm4svc_xdrstore),
+};
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index fdab66ff0fe8..fe689f76aeae 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -544,7 +544,7 @@ struct nlm_void { int dummy; };
#define No (1+1024/4) /* Net Obj */
#define Rg 2 /* range - offset + size */
-const struct svc_procedure nlmsvc_procedures[24] = {
+static const struct svc_procedure nlmsvc_procedures[24] = {
[NLMPROC_NULL] = {
.pc_func = nlmsvc_proc_null,
.pc_decode = nlmsvc_decode_void,
@@ -786,3 +786,39 @@ const struct svc_procedure nlmsvc_procedures[24] = {
.pc_name = "FREE_ALL",
},
};
+
+/*
+ * Storage requirements for XDR arguments and results
+ */
+union nlmsvc_xdrstore {
+ struct nlm_args args;
+ struct nlm_res res;
+ struct nlm_reboot reboot;
+};
+
+/*
+ * NLMv1 defines only procedures 1 - 15. Linux lockd also implements
+ * procedures 0 (NULL) and 16 (SM_NOTIFY).
+ */
+static DEFINE_PER_CPU_ALIGNED(unsigned long, nlm1svc_call_counters[17]);
+
+const struct svc_version nlmsvc_version1 = {
+ .vs_vers = 1,
+ .vs_nproc = 17,
+ .vs_proc = nlmsvc_procedures,
+ .vs_count = nlm1svc_call_counters,
+ .vs_dispatch = nlmsvc_dispatch,
+ .vs_xdrsize = sizeof(union nlmsvc_xdrstore),
+};
+
+static DEFINE_PER_CPU_ALIGNED(unsigned long,
+ nlm3svc_call_counters[ARRAY_SIZE(nlmsvc_procedures)]);
+
+const struct svc_version nlmsvc_version3 = {
+ .vs_vers = 3,
+ .vs_nproc = ARRAY_SIZE(nlmsvc_procedures),
+ .vs_proc = nlmsvc_procedures,
+ .vs_count = nlm3svc_call_counters,
+ .vs_dispatch = nlmsvc_dispatch,
+ .vs_xdrsize = sizeof(union nlmsvc_xdrstore),
+};
diff --git a/fs/lockd/xdr.h b/fs/lockd/xdr.h
index af821ecf2a4e..3c60817c4349 100644
--- a/fs/lockd/xdr.h
+++ b/fs/lockd/xdr.h
@@ -88,11 +88,6 @@ struct nlm_reboot {
struct nsm_private priv;
};
-/*
- * Contents of statd callback when monitored host rebooted
- */
-#define NLMSVC_XDRSIZE sizeof(struct nlm_args)
-
bool nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
bool nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 14/42] Documentation: Add the RPC language description of NLM version 4
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (12 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 13/42] lockd: Relocate svc_version definitions to XDR layer Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 15/42] lockd: Use xdrgen XDR functions for the NLMv4 NULL procedure Chuck Lever
` (28 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
In order to generate source code to encode and decode NLMv4 protocol
elements, include a copy of the RPC language description of NLMv4
for xdrgen to process. The language description is an amalgam of
RFC 1813 and the Open Group's XNFS specification:
https://pubs.opengroup.org/onlinepubs/9629799/chap10.htm
The C code committed here was generated from the new nlm4.x file
using tools/net/sunrpc/xdrgen/xdrgen.
The goals of replacing hand-written XDR functions with ones that
are tool-generated are to improve memory safety and make XDR
encoding and decoding less brittle to maintain.
The xdrgen utility derives both the type definitions and the
encode/decode functions directly from protocol specifications,
using names and symbols familiar to anyone who knows those specs.
Unlike hand-written code that can inadvertently diverge from the
specification, xdrgen guarantees that the generated code matches
the specification exactly.
We would eventually like xdrgen to generate Rust code as well,
making the conversion of the kernel's NFS stacks to use Rust just
a little easier for us.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
Documentation/sunrpc/xdr/nlm4.x | 211 +++++++++
fs/lockd/Makefile | 30 +-
fs/lockd/nlm4xdr_gen.c | 724 +++++++++++++++++++++++++++++
fs/lockd/nlm4xdr_gen.h | 32 ++
include/linux/sunrpc/xdrgen/nlm4.h | 233 ++++++++++
5 files changed, 1229 insertions(+), 1 deletion(-)
create mode 100644 Documentation/sunrpc/xdr/nlm4.x
create mode 100644 fs/lockd/nlm4xdr_gen.c
create mode 100644 fs/lockd/nlm4xdr_gen.h
create mode 100644 include/linux/sunrpc/xdrgen/nlm4.h
diff --git a/Documentation/sunrpc/xdr/nlm4.x b/Documentation/sunrpc/xdr/nlm4.x
new file mode 100644
index 000000000000..0c44a80ef674
--- /dev/null
+++ b/Documentation/sunrpc/xdr/nlm4.x
@@ -0,0 +1,211 @@
+/*
+ * This file was extracted by hand from
+ * https://www.rfc-editor.org/rfc/rfc1813.html .
+ *
+ * Note that RFC 1813 is Informational. Its official date of
+ * publication (June 1995) is before the IETF required its RFCs to
+ * carry an explicit copyright or other IP ownership notices.
+ *
+ * Note also that RFC 1813 does not specify the whole NLM4 protocol.
+ * In particular, the argument and result types are not present in
+ * that document, and had to be reverse-engineered.
+ */
+
+/*
+ * The NLMv4 protocol
+ */
+
+pragma header nlm4;
+
+/*
+ * The following definitions are missing in RFC 1813,
+ * but can be found in the OpenNetworking Network Lock
+ * Manager protocol:
+ *
+ * https://pubs.opengroup.org/onlinepubs/9629799/chap10.htm
+ */
+
+const LM_MAXSTRLEN = 1024;
+
+const LM_MAXNAMELEN = 1025;
+
+const MAXNETOBJ_SZ = 1024;
+
+typedef opaque netobj<MAXNETOBJ_SZ>;
+
+enum fsh4_mode {
+ fsm_DN = 0, /* deny none */
+ fsm_DR = 1, /* deny read */
+ fsm_DW = 2, /* deny write */
+ fsm_DRW = 3 /* deny read/write */
+};
+
+enum fsh4_access {
+ fsa_NONE = 0, /* for completeness */
+ fsa_R = 1, /* read-only */
+ fsa_W = 2, /* write-only */
+ fsa_RW = 3 /* read/write */
+};
+
+/*
+ * The following definitions come from the OpenNetworking
+ * Network Status Monitor protocol:
+ *
+ * https://pubs.opengroup.org/onlinepubs/9629799/chap11.htm
+ */
+
+const SM_MAXSTRLEN = 1024;
+
+/*
+ * The NLM protocol as extracted from:
+ * https://tools.ietf.org/html/rfc1813 Appendix II
+ */
+
+typedef unsigned hyper uint64;
+
+typedef hyper int64;
+
+typedef unsigned long uint32;
+
+typedef long int32;
+
+enum nlm4_stats {
+ NLM4_GRANTED = 0,
+ NLM4_DENIED = 1,
+ NLM4_DENIED_NOLOCKS = 2,
+ NLM4_BLOCKED = 3,
+ NLM4_DENIED_GRACE_PERIOD = 4,
+ NLM4_DEADLCK = 5,
+ NLM4_ROFS = 6,
+ NLM4_STALE_FH = 7,
+ NLM4_FBIG = 8,
+ NLM4_FAILED = 9
+};
+
+pragma big_endian nlm4_stats;
+
+struct nlm4_holder {
+ bool exclusive;
+ int32 svid;
+ netobj oh;
+ uint64 l_offset;
+ uint64 l_len;
+};
+
+union nlm4_testrply switch (nlm4_stats stat) {
+ case NLM4_DENIED:
+ nlm4_holder holder;
+ default:
+ void;
+};
+
+struct nlm4_stat {
+ nlm4_stats stat;
+};
+
+struct nlm4_res {
+ netobj cookie;
+ nlm4_stat stat;
+};
+
+struct nlm4_testres {
+ netobj cookie;
+ nlm4_testrply stat;
+};
+
+struct nlm4_lock {
+ string caller_name<LM_MAXSTRLEN>;
+ netobj fh;
+ netobj oh;
+ int32 svid;
+ uint64 l_offset;
+ uint64 l_len;
+};
+
+struct nlm4_lockargs {
+ netobj cookie;
+ bool block;
+ bool exclusive;
+ nlm4_lock alock;
+ bool reclaim;
+ int32 state;
+};
+
+struct nlm4_cancargs {
+ netobj cookie;
+ bool block;
+ bool exclusive;
+ nlm4_lock alock;
+};
+
+struct nlm4_testargs {
+ netobj cookie;
+ bool exclusive;
+ nlm4_lock alock;
+};
+
+struct nlm4_unlockargs {
+ netobj cookie;
+ nlm4_lock alock;
+};
+
+struct nlm4_share {
+ string caller_name<LM_MAXSTRLEN>;
+ netobj fh;
+ netobj oh;
+ fsh4_mode mode;
+ fsh4_access access;
+};
+
+struct nlm4_shareargs {
+ netobj cookie;
+ nlm4_share share;
+ bool reclaim;
+};
+
+struct nlm4_shareres {
+ netobj cookie;
+ nlm4_stats stat;
+ int32 sequence;
+};
+
+struct nlm4_notify {
+ string name<LM_MAXNAMELEN>;
+ int32 state;
+};
+
+/*
+ * Argument for the Linux-private SM_NOTIFY procedure
+ */
+const SM_PRIV_SIZE = 16;
+
+struct nlm4_notifyargs {
+ nlm4_notify notify;
+ opaque private[SM_PRIV_SIZE];
+};
+
+program NLM4_PROG {
+ version NLM4_VERS {
+ void NLMPROC4_NULL(void) = 0;
+ nlm4_testres NLMPROC4_TEST(nlm4_testargs) = 1;
+ nlm4_res NLMPROC4_LOCK(nlm4_lockargs) = 2;
+ nlm4_res NLMPROC4_CANCEL(nlm4_cancargs) = 3;
+ nlm4_res NLMPROC4_UNLOCK(nlm4_unlockargs) = 4;
+ nlm4_res NLMPROC4_GRANTED(nlm4_testargs) = 5;
+ void NLMPROC4_TEST_MSG(nlm4_testargs) = 6;
+ void NLMPROC4_LOCK_MSG(nlm4_lockargs) = 7;
+ void NLMPROC4_CANCEL_MSG(nlm4_cancargs) = 8;
+ void NLMPROC4_UNLOCK_MSG(nlm4_unlockargs) = 9;
+ void NLMPROC4_GRANTED_MSG(nlm4_testargs) = 10;
+ void NLMPROC4_TEST_RES(nlm4_testres) = 11;
+ void NLMPROC4_LOCK_RES(nlm4_res) = 12;
+ void NLMPROC4_CANCEL_RES(nlm4_res) = 13;
+ void NLMPROC4_UNLOCK_RES(nlm4_res) = 14;
+ void NLMPROC4_GRANTED_RES(nlm4_res) = 15;
+ void NLMPROC4_SM_NOTIFY(nlm4_notifyargs) = 16;
+ nlm4_shareres NLMPROC4_SHARE(nlm4_shareargs) = 20;
+ nlm4_shareres NLMPROC4_UNSHARE(nlm4_shareargs) = 21;
+ nlm4_res NLMPROC4_NM_LOCK(nlm4_lockargs) = 22;
+ void NLMPROC4_FREE_ALL(nlm4_notify) = 23;
+ } = 4;
+} = 100021;
diff --git a/fs/lockd/Makefile b/fs/lockd/Makefile
index 51bbe22d21e3..8e9d18a4348c 100644
--- a/fs/lockd/Makefile
+++ b/fs/lockd/Makefile
@@ -9,5 +9,33 @@ obj-$(CONFIG_LOCKD) += lockd.o
lockd-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o netlink.o
-lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o
+lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o nlm4xdr_gen.o
lockd-$(CONFIG_PROC_FS) += procfs.o
+
+#
+# XDR code generation (requires Python and additional packages)
+#
+# The generated *xdr_gen.{h,c} files are checked into git. Normal kernel
+# builds do not require the xdrgen tool or its Python dependencies.
+#
+# Developers modifying .x files in Documentation/sunrpc/xdr/ should run
+# "make xdrgen" to regenerate the affected files.
+#
+.PHONY: xdrgen
+
+XDRGEN = ../../tools/net/sunrpc/xdrgen/xdrgen
+
+XDRGEN_DEFINITIONS = ../../include/linux/sunrpc/xdrgen/nlm4.h
+XDRGEN_DECLARATIONS = nlm4xdr_gen.h
+XDRGEN_SOURCE = nlm4xdr_gen.c
+
+xdrgen: $(XDRGEN_DEFINITIONS) $(XDRGEN_DECLARATIONS) $(XDRGEN_SOURCE)
+
+../../include/linux/sunrpc/xdrgen/nlm4.h: ../../Documentation/sunrpc/xdr/nlm4.x
+ $(XDRGEN) definitions $< > $@
+
+nlm4xdr_gen.h: ../../Documentation/sunrpc/xdr/nlm4.x
+ $(XDRGEN) declarations $< > $@
+
+nlm4xdr_gen.c: ../../Documentation/sunrpc/xdr/nlm4.x
+ $(XDRGEN) source --peer server $< > $@
diff --git a/fs/lockd/nlm4xdr_gen.c b/fs/lockd/nlm4xdr_gen.c
new file mode 100644
index 000000000000..1c8c221db456
--- /dev/null
+++ b/fs/lockd/nlm4xdr_gen.c
@@ -0,0 +1,724 @@
+// SPDX-License-Identifier: GPL-2.0
+// Generated by xdrgen. Manual edits will be lost.
+// XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x
+// XDR specification modification time: Thu Dec 25 13:10:19 2025
+
+#include <linux/sunrpc/svc.h>
+
+#include "nlm4xdr_gen.h"
+
+static bool __maybe_unused
+xdrgen_decode_netobj(struct xdr_stream *xdr, netobj *ptr)
+{
+ return xdrgen_decode_opaque(xdr, ptr, MAXNETOBJ_SZ);
+}
+
+static bool __maybe_unused
+xdrgen_decode_fsh4_mode(struct xdr_stream *xdr, fsh4_mode *ptr)
+{
+ u32 val;
+
+ if (xdr_stream_decode_u32(xdr, &val) < 0)
+ return false;
+ *ptr = val;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_fsh4_access(struct xdr_stream *xdr, fsh4_access *ptr)
+{
+ u32 val;
+
+ if (xdr_stream_decode_u32(xdr, &val) < 0)
+ return false;
+ *ptr = val;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_uint64(struct xdr_stream *xdr, uint64 *ptr)
+{
+ return xdrgen_decode_unsigned_hyper(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_int64(struct xdr_stream *xdr, int64 *ptr)
+{
+ return xdrgen_decode_hyper(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_uint32(struct xdr_stream *xdr, uint32 *ptr)
+{
+ return xdrgen_decode_unsigned_long(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_int32(struct xdr_stream *xdr, int32 *ptr)
+{
+ return xdrgen_decode_long(xdr, ptr);
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_stats(struct xdr_stream *xdr, nlm4_stats *ptr)
+{
+ return xdr_stream_decode_be32(xdr, ptr) == 0;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_holder(struct xdr_stream *xdr, struct nlm4_holder *ptr)
+{
+ if (!xdrgen_decode_bool(xdr, &ptr->exclusive))
+ return false;
+ if (!xdrgen_decode_int32(xdr, &ptr->svid))
+ return false;
+ if (!xdrgen_decode_netobj(xdr, &ptr->oh))
+ return false;
+ if (!xdrgen_decode_uint64(xdr, &ptr->l_offset))
+ return false;
+ if (!xdrgen_decode_uint64(xdr, &ptr->l_len))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_testrply(struct xdr_stream *xdr, struct nlm4_testrply *ptr)
+{
+ if (!xdrgen_decode_nlm4_stats(xdr, &ptr->stat))
+ return false;
+ switch (ptr->stat) {
+ case __constant_cpu_to_be32(NLM4_DENIED):
+ if (!xdrgen_decode_nlm4_holder(xdr, &ptr->u.holder))
+ return false;
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_stat(struct xdr_stream *xdr, struct nlm4_stat *ptr)
+{
+ if (!xdrgen_decode_nlm4_stats(xdr, &ptr->stat))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_res(struct xdr_stream *xdr, struct nlm4_res *ptr)
+{
+ if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
+ return false;
+ if (!xdrgen_decode_nlm4_stat(xdr, &ptr->stat))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_testres(struct xdr_stream *xdr, struct nlm4_testres *ptr)
+{
+ if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
+ return false;
+ if (!xdrgen_decode_nlm4_testrply(xdr, &ptr->stat))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_lock(struct xdr_stream *xdr, struct nlm4_lock *ptr)
+{
+ if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXSTRLEN))
+ return false;
+ if (!xdrgen_decode_netobj(xdr, &ptr->fh))
+ return false;
+ if (!xdrgen_decode_netobj(xdr, &ptr->oh))
+ return false;
+ if (!xdrgen_decode_int32(xdr, &ptr->svid))
+ return false;
+ if (!xdrgen_decode_uint64(xdr, &ptr->l_offset))
+ return false;
+ if (!xdrgen_decode_uint64(xdr, &ptr->l_len))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_lockargs(struct xdr_stream *xdr, struct nlm4_lockargs *ptr)
+{
+ if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
+ return false;
+ if (!xdrgen_decode_bool(xdr, &ptr->block))
+ return false;
+ if (!xdrgen_decode_bool(xdr, &ptr->exclusive))
+ return false;
+ if (!xdrgen_decode_nlm4_lock(xdr, &ptr->alock))
+ return false;
+ if (!xdrgen_decode_bool(xdr, &ptr->reclaim))
+ return false;
+ if (!xdrgen_decode_int32(xdr, &ptr->state))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_cancargs(struct xdr_stream *xdr, struct nlm4_cancargs *ptr)
+{
+ if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
+ return false;
+ if (!xdrgen_decode_bool(xdr, &ptr->block))
+ return false;
+ if (!xdrgen_decode_bool(xdr, &ptr->exclusive))
+ return false;
+ if (!xdrgen_decode_nlm4_lock(xdr, &ptr->alock))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_testargs(struct xdr_stream *xdr, struct nlm4_testargs *ptr)
+{
+ if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
+ return false;
+ if (!xdrgen_decode_bool(xdr, &ptr->exclusive))
+ return false;
+ if (!xdrgen_decode_nlm4_lock(xdr, &ptr->alock))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_unlockargs(struct xdr_stream *xdr, struct nlm4_unlockargs *ptr)
+{
+ if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
+ return false;
+ if (!xdrgen_decode_nlm4_lock(xdr, &ptr->alock))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_share(struct xdr_stream *xdr, struct nlm4_share *ptr)
+{
+ if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXSTRLEN))
+ return false;
+ if (!xdrgen_decode_netobj(xdr, &ptr->fh))
+ return false;
+ if (!xdrgen_decode_netobj(xdr, &ptr->oh))
+ return false;
+ if (!xdrgen_decode_fsh4_mode(xdr, &ptr->mode))
+ return false;
+ if (!xdrgen_decode_fsh4_access(xdr, &ptr->access))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_shareargs(struct xdr_stream *xdr, struct nlm4_shareargs *ptr)
+{
+ if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
+ return false;
+ if (!xdrgen_decode_nlm4_share(xdr, &ptr->share))
+ return false;
+ if (!xdrgen_decode_bool(xdr, &ptr->reclaim))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_shareres(struct xdr_stream *xdr, struct nlm4_shareres *ptr)
+{
+ if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
+ return false;
+ if (!xdrgen_decode_nlm4_stats(xdr, &ptr->stat))
+ return false;
+ if (!xdrgen_decode_int32(xdr, &ptr->sequence))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_notify(struct xdr_stream *xdr, struct nlm4_notify *ptr)
+{
+ if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXNAMELEN))
+ return false;
+ if (!xdrgen_decode_int32(xdr, &ptr->state))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_decode_nlm4_notifyargs(struct xdr_stream *xdr, struct nlm4_notifyargs *ptr)
+{
+ if (!xdrgen_decode_nlm4_notify(xdr, &ptr->notify))
+ return false;
+ if (xdr_stream_decode_opaque_fixed(xdr, ptr->private, SM_PRIV_SIZE) < 0)
+ return false;
+ return true;
+}
+
+/**
+ * nlm4_svc_decode_void - Decode a void argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ return xdrgen_decode_void(xdr);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_testargs - Decode a nlm4_testargs argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_testargs *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_testargs(xdr, argp);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_lockargs - Decode a nlm4_lockargs argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_lockargs *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_lockargs(xdr, argp);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_cancargs - Decode a nlm4_cancargs argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_cancargs *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_cancargs(xdr, argp);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_unlockargs - Decode a nlm4_unlockargs argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_unlockargs *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_unlockargs(xdr, argp);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_testres - Decode a nlm4_testres argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_testres *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_testres(xdr, argp);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_res - Decode a nlm4_res argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_res *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_res(xdr, argp);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_notifyargs - Decode a nlm4_notifyargs argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_notifyargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_notifyargs *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_notifyargs(xdr, argp);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_shareargs - Decode a nlm4_shareargs argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_shareargs *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_shareargs(xdr, argp);
+}
+
+/**
+ * nlm4_svc_decode_nlm4_notify - Decode a nlm4_notify argument
+ * @rqstp: RPC transaction context
+ * @xdr: source XDR data stream
+ *
+ * Return values:
+ * %true: procedure arguments decoded successfully
+ * %false: decode failed
+ */
+bool nlm4_svc_decode_nlm4_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_notify *argp = rqstp->rq_argp;
+
+ return xdrgen_decode_nlm4_notify(xdr, argp);
+}
+
+static bool __maybe_unused
+xdrgen_encode_netobj(struct xdr_stream *xdr, const netobj value)
+{
+ return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0;
+}
+
+static bool __maybe_unused
+xdrgen_encode_fsh4_mode(struct xdr_stream *xdr, fsh4_mode value)
+{
+ return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
+}
+
+static bool __maybe_unused
+xdrgen_encode_fsh4_access(struct xdr_stream *xdr, fsh4_access value)
+{
+ return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
+}
+
+static bool __maybe_unused
+xdrgen_encode_uint64(struct xdr_stream *xdr, const uint64 value)
+{
+ return xdrgen_encode_unsigned_hyper(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_int64(struct xdr_stream *xdr, const int64 value)
+{
+ return xdrgen_encode_hyper(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_uint32(struct xdr_stream *xdr, const uint32 value)
+{
+ return xdrgen_encode_unsigned_long(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_int32(struct xdr_stream *xdr, const int32 value)
+{
+ return xdrgen_encode_long(xdr, value);
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_stats(struct xdr_stream *xdr, nlm4_stats value)
+{
+ return xdr_stream_encode_be32(xdr, value) == XDR_UNIT;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_holder(struct xdr_stream *xdr, const struct nlm4_holder *value)
+{
+ if (!xdrgen_encode_bool(xdr, value->exclusive))
+ return false;
+ if (!xdrgen_encode_int32(xdr, value->svid))
+ return false;
+ if (!xdrgen_encode_netobj(xdr, value->oh))
+ return false;
+ if (!xdrgen_encode_uint64(xdr, value->l_offset))
+ return false;
+ if (!xdrgen_encode_uint64(xdr, value->l_len))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_testrply(struct xdr_stream *xdr, const struct nlm4_testrply *ptr)
+{
+ if (!xdrgen_encode_nlm4_stats(xdr, ptr->stat))
+ return false;
+ switch (ptr->stat) {
+ case __constant_cpu_to_be32(NLM4_DENIED):
+ if (!xdrgen_encode_nlm4_holder(xdr, &ptr->u.holder))
+ return false;
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_stat(struct xdr_stream *xdr, const struct nlm4_stat *value)
+{
+ if (!xdrgen_encode_nlm4_stats(xdr, value->stat))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_res(struct xdr_stream *xdr, const struct nlm4_res *value)
+{
+ if (!xdrgen_encode_netobj(xdr, value->cookie))
+ return false;
+ if (!xdrgen_encode_nlm4_stat(xdr, &value->stat))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_testres(struct xdr_stream *xdr, const struct nlm4_testres *value)
+{
+ if (!xdrgen_encode_netobj(xdr, value->cookie))
+ return false;
+ if (!xdrgen_encode_nlm4_testrply(xdr, &value->stat))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_lock(struct xdr_stream *xdr, const struct nlm4_lock *value)
+{
+ if (value->caller_name.len > LM_MAXSTRLEN)
+ return false;
+ if (xdr_stream_encode_opaque(xdr, value->caller_name.data, value->caller_name.len) < 0)
+ return false;
+ if (!xdrgen_encode_netobj(xdr, value->fh))
+ return false;
+ if (!xdrgen_encode_netobj(xdr, value->oh))
+ return false;
+ if (!xdrgen_encode_int32(xdr, value->svid))
+ return false;
+ if (!xdrgen_encode_uint64(xdr, value->l_offset))
+ return false;
+ if (!xdrgen_encode_uint64(xdr, value->l_len))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_lockargs(struct xdr_stream *xdr, const struct nlm4_lockargs *value)
+{
+ if (!xdrgen_encode_netobj(xdr, value->cookie))
+ return false;
+ if (!xdrgen_encode_bool(xdr, value->block))
+ return false;
+ if (!xdrgen_encode_bool(xdr, value->exclusive))
+ return false;
+ if (!xdrgen_encode_nlm4_lock(xdr, &value->alock))
+ return false;
+ if (!xdrgen_encode_bool(xdr, value->reclaim))
+ return false;
+ if (!xdrgen_encode_int32(xdr, value->state))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_cancargs(struct xdr_stream *xdr, const struct nlm4_cancargs *value)
+{
+ if (!xdrgen_encode_netobj(xdr, value->cookie))
+ return false;
+ if (!xdrgen_encode_bool(xdr, value->block))
+ return false;
+ if (!xdrgen_encode_bool(xdr, value->exclusive))
+ return false;
+ if (!xdrgen_encode_nlm4_lock(xdr, &value->alock))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_testargs(struct xdr_stream *xdr, const struct nlm4_testargs *value)
+{
+ if (!xdrgen_encode_netobj(xdr, value->cookie))
+ return false;
+ if (!xdrgen_encode_bool(xdr, value->exclusive))
+ return false;
+ if (!xdrgen_encode_nlm4_lock(xdr, &value->alock))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_unlockargs(struct xdr_stream *xdr, const struct nlm4_unlockargs *value)
+{
+ if (!xdrgen_encode_netobj(xdr, value->cookie))
+ return false;
+ if (!xdrgen_encode_nlm4_lock(xdr, &value->alock))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_share(struct xdr_stream *xdr, const struct nlm4_share *value)
+{
+ if (value->caller_name.len > LM_MAXSTRLEN)
+ return false;
+ if (xdr_stream_encode_opaque(xdr, value->caller_name.data, value->caller_name.len) < 0)
+ return false;
+ if (!xdrgen_encode_netobj(xdr, value->fh))
+ return false;
+ if (!xdrgen_encode_netobj(xdr, value->oh))
+ return false;
+ if (!xdrgen_encode_fsh4_mode(xdr, value->mode))
+ return false;
+ if (!xdrgen_encode_fsh4_access(xdr, value->access))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_shareargs(struct xdr_stream *xdr, const struct nlm4_shareargs *value)
+{
+ if (!xdrgen_encode_netobj(xdr, value->cookie))
+ return false;
+ if (!xdrgen_encode_nlm4_share(xdr, &value->share))
+ return false;
+ if (!xdrgen_encode_bool(xdr, value->reclaim))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_shareres(struct xdr_stream *xdr, const struct nlm4_shareres *value)
+{
+ if (!xdrgen_encode_netobj(xdr, value->cookie))
+ return false;
+ if (!xdrgen_encode_nlm4_stats(xdr, value->stat))
+ return false;
+ if (!xdrgen_encode_int32(xdr, value->sequence))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_notify(struct xdr_stream *xdr, const struct nlm4_notify *value)
+{
+ if (value->name.len > LM_MAXNAMELEN)
+ return false;
+ if (xdr_stream_encode_opaque(xdr, value->name.data, value->name.len) < 0)
+ return false;
+ if (!xdrgen_encode_int32(xdr, value->state))
+ return false;
+ return true;
+}
+
+static bool __maybe_unused
+xdrgen_encode_nlm4_notifyargs(struct xdr_stream *xdr, const struct nlm4_notifyargs *value)
+{
+ if (!xdrgen_encode_nlm4_notify(xdr, &value->notify))
+ return false;
+ if (xdr_stream_encode_opaque_fixed(xdr, value->private, SM_PRIV_SIZE) < 0)
+ return false;
+ return true;
+}
+
+/**
+ * nlm4_svc_encode_void - Encode a void result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ * %true: procedure results encoded successfully
+ * %false: encode failed
+ */
+bool nlm4_svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ return xdrgen_encode_void(xdr);
+}
+
+/**
+ * nlm4_svc_encode_nlm4_testres - Encode a nlm4_testres result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ * %true: procedure results encoded successfully
+ * %false: encode failed
+ */
+bool nlm4_svc_encode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_testres *resp = rqstp->rq_resp;
+
+ return xdrgen_encode_nlm4_testres(xdr, resp);
+}
+
+/**
+ * nlm4_svc_encode_nlm4_res - Encode a nlm4_res result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ * %true: procedure results encoded successfully
+ * %false: encode failed
+ */
+bool nlm4_svc_encode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_res *resp = rqstp->rq_resp;
+
+ return xdrgen_encode_nlm4_res(xdr, resp);
+}
+
+/**
+ * nlm4_svc_encode_nlm4_shareres - Encode a nlm4_shareres result
+ * @rqstp: RPC transaction context
+ * @xdr: target XDR data stream
+ *
+ * Return values:
+ * %true: procedure results encoded successfully
+ * %false: encode failed
+ */
+bool nlm4_svc_encode_nlm4_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
+{
+ struct nlm4_shareres *resp = rqstp->rq_resp;
+
+ return xdrgen_encode_nlm4_shareres(xdr, resp);
+}
diff --git a/fs/lockd/nlm4xdr_gen.h b/fs/lockd/nlm4xdr_gen.h
new file mode 100644
index 000000000000..b6008b296a3e
--- /dev/null
+++ b/fs/lockd/nlm4xdr_gen.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Generated by xdrgen. Manual edits will be lost. */
+/* XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x */
+/* XDR specification modification time: Thu Dec 25 13:10:19 2025 */
+
+#ifndef _LINUX_XDRGEN_NLM4_DECL_H
+#define _LINUX_XDRGEN_NLM4_DECL_H
+
+#include <linux/types.h>
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/xdrgen/_defs.h>
+#include <linux/sunrpc/xdrgen/_builtins.h>
+#include <linux/sunrpc/xdrgen/nlm4.h>
+
+bool nlm4_svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_notifyargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_decode_nlm4_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+
+bool nlm4_svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_encode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_encode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+bool nlm4_svc_encode_nlm4_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
+
+#endif /* _LINUX_XDRGEN_NLM4_DECL_H */
diff --git a/include/linux/sunrpc/xdrgen/nlm4.h b/include/linux/sunrpc/xdrgen/nlm4.h
new file mode 100644
index 000000000000..e95e8f105624
--- /dev/null
+++ b/include/linux/sunrpc/xdrgen/nlm4.h
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Generated by xdrgen. Manual edits will be lost. */
+/* XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x */
+/* XDR specification modification time: Thu Dec 25 13:10:19 2025 */
+
+#ifndef _LINUX_XDRGEN_NLM4_DEF_H
+#define _LINUX_XDRGEN_NLM4_DEF_H
+
+#include <linux/types.h>
+#include <linux/sunrpc/xdrgen/_defs.h>
+
+enum { LM_MAXSTRLEN = 1024 };
+
+enum { LM_MAXNAMELEN = 1025 };
+
+enum { MAXNETOBJ_SZ = 1024 };
+
+typedef opaque netobj;
+
+enum fsh4_mode {
+ fsm_DN = 0,
+ fsm_DR = 1,
+ fsm_DW = 2,
+ fsm_DRW = 3,
+};
+
+typedef enum fsh4_mode fsh4_mode;
+
+enum fsh4_access {
+ fsa_NONE = 0,
+ fsa_R = 1,
+ fsa_W = 2,
+ fsa_RW = 3,
+};
+
+typedef enum fsh4_access fsh4_access;
+
+enum { SM_MAXSTRLEN = 1024 };
+
+typedef u64 uint64;
+
+typedef s64 int64;
+
+typedef u32 uint32;
+
+typedef s32 int32;
+
+enum nlm4_stats {
+ NLM4_GRANTED = 0,
+ NLM4_DENIED = 1,
+ NLM4_DENIED_NOLOCKS = 2,
+ NLM4_BLOCKED = 3,
+ NLM4_DENIED_GRACE_PERIOD = 4,
+ NLM4_DEADLCK = 5,
+ NLM4_ROFS = 6,
+ NLM4_STALE_FH = 7,
+ NLM4_FBIG = 8,
+ NLM4_FAILED = 9,
+};
+
+typedef __be32 nlm4_stats;
+
+struct nlm4_holder {
+ bool exclusive;
+ int32 svid;
+ netobj oh;
+ uint64 l_offset;
+ uint64 l_len;
+};
+
+struct nlm4_testrply {
+ nlm4_stats stat;
+ union {
+ struct nlm4_holder holder;
+ } u;
+};
+
+struct nlm4_stat {
+ nlm4_stats stat;
+};
+
+struct nlm4_res {
+ netobj cookie;
+ struct nlm4_stat stat;
+};
+
+struct nlm4_testres {
+ netobj cookie;
+ struct nlm4_testrply stat;
+};
+
+struct nlm4_lock {
+ string caller_name;
+ netobj fh;
+ netobj oh;
+ int32 svid;
+ uint64 l_offset;
+ uint64 l_len;
+};
+
+struct nlm4_lockargs {
+ netobj cookie;
+ bool block;
+ bool exclusive;
+ struct nlm4_lock alock;
+ bool reclaim;
+ int32 state;
+};
+
+struct nlm4_cancargs {
+ netobj cookie;
+ bool block;
+ bool exclusive;
+ struct nlm4_lock alock;
+};
+
+struct nlm4_testargs {
+ netobj cookie;
+ bool exclusive;
+ struct nlm4_lock alock;
+};
+
+struct nlm4_unlockargs {
+ netobj cookie;
+ struct nlm4_lock alock;
+};
+
+struct nlm4_share {
+ string caller_name;
+ netobj fh;
+ netobj oh;
+ fsh4_mode mode;
+ fsh4_access access;
+};
+
+struct nlm4_shareargs {
+ netobj cookie;
+ struct nlm4_share share;
+ bool reclaim;
+};
+
+struct nlm4_shareres {
+ netobj cookie;
+ nlm4_stats stat;
+ int32 sequence;
+};
+
+struct nlm4_notify {
+ string name;
+ int32 state;
+};
+
+enum { SM_PRIV_SIZE = 16 };
+
+struct nlm4_notifyargs {
+ struct nlm4_notify notify;
+ u8 private[SM_PRIV_SIZE];
+};
+
+enum {
+ NLMPROC4_NULL = 0,
+ NLMPROC4_TEST = 1,
+ NLMPROC4_LOCK = 2,
+ NLMPROC4_CANCEL = 3,
+ NLMPROC4_UNLOCK = 4,
+ NLMPROC4_GRANTED = 5,
+ NLMPROC4_TEST_MSG = 6,
+ NLMPROC4_LOCK_MSG = 7,
+ NLMPROC4_CANCEL_MSG = 8,
+ NLMPROC4_UNLOCK_MSG = 9,
+ NLMPROC4_GRANTED_MSG = 10,
+ NLMPROC4_TEST_RES = 11,
+ NLMPROC4_LOCK_RES = 12,
+ NLMPROC4_CANCEL_RES = 13,
+ NLMPROC4_UNLOCK_RES = 14,
+ NLMPROC4_GRANTED_RES = 15,
+ NLMPROC4_SM_NOTIFY = 16,
+ NLMPROC4_SHARE = 20,
+ NLMPROC4_UNSHARE = 21,
+ NLMPROC4_NM_LOCK = 22,
+ NLMPROC4_FREE_ALL = 23,
+};
+
+#ifndef NLM4_PROG
+#define NLM4_PROG (100021)
+#endif
+
+#define NLM4_netobj_sz (XDR_unsigned_int + XDR_QUADLEN(MAXNETOBJ_SZ))
+#define NLM4_fsh4_mode_sz (XDR_int)
+#define NLM4_fsh4_access_sz (XDR_int)
+#define NLM4_uint64_sz \
+ (XDR_unsigned_hyper)
+#define NLM4_int64_sz \
+ (XDR_hyper)
+#define NLM4_uint32_sz \
+ (XDR_unsigned_long)
+#define NLM4_int32_sz \
+ (XDR_long)
+#define NLM4_nlm4_stats_sz (XDR_int)
+#define NLM4_nlm4_holder_sz \
+ (XDR_bool + NLM4_int32_sz + NLM4_netobj_sz + NLM4_uint64_sz + NLM4_uint64_sz)
+#define NLM4_nlm4_testrply_sz \
+ (NLM4_nlm4_stats_sz + NLM4_nlm4_holder_sz)
+#define NLM4_nlm4_stat_sz \
+ (NLM4_nlm4_stats_sz)
+#define NLM4_nlm4_res_sz \
+ (NLM4_netobj_sz + NLM4_nlm4_stat_sz)
+#define NLM4_nlm4_testres_sz \
+ (NLM4_netobj_sz + NLM4_nlm4_testrply_sz)
+#define NLM4_nlm4_lock_sz \
+ (XDR_unsigned_int + XDR_QUADLEN(LM_MAXSTRLEN) + NLM4_netobj_sz + NLM4_netobj_sz + NLM4_int32_sz + NLM4_uint64_sz + NLM4_uint64_sz)
+#define NLM4_nlm4_lockargs_sz \
+ (NLM4_netobj_sz + XDR_bool + XDR_bool + NLM4_nlm4_lock_sz + XDR_bool + NLM4_int32_sz)
+#define NLM4_nlm4_cancargs_sz \
+ (NLM4_netobj_sz + XDR_bool + XDR_bool + NLM4_nlm4_lock_sz)
+#define NLM4_nlm4_testargs_sz \
+ (NLM4_netobj_sz + XDR_bool + NLM4_nlm4_lock_sz)
+#define NLM4_nlm4_unlockargs_sz \
+ (NLM4_netobj_sz + NLM4_nlm4_lock_sz)
+#define NLM4_nlm4_share_sz \
+ (XDR_unsigned_int + XDR_QUADLEN(LM_MAXSTRLEN) + NLM4_netobj_sz + NLM4_netobj_sz + NLM4_fsh4_mode_sz + NLM4_fsh4_access_sz)
+#define NLM4_nlm4_shareargs_sz \
+ (NLM4_netobj_sz + NLM4_nlm4_share_sz + XDR_bool)
+#define NLM4_nlm4_shareres_sz \
+ (NLM4_netobj_sz + NLM4_nlm4_stats_sz + NLM4_int32_sz)
+#define NLM4_nlm4_notify_sz \
+ (XDR_unsigned_int + XDR_QUADLEN(LM_MAXNAMELEN) + NLM4_int32_sz)
+#define NLM4_nlm4_notifyargs_sz \
+ (NLM4_nlm4_notify_sz + XDR_QUADLEN(SM_PRIV_SIZE))
+#define NLM4_MAX_ARGS_SZ \
+ (NLM4_nlm4_lockargs_sz)
+
+#endif /* _LINUX_XDRGEN_NLM4_DEF_H */
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 15/42] lockd: Use xdrgen XDR functions for the NLMv4 NULL procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (13 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 14/42] Documentation: Add the RPC language description of NLM version 4 Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 16/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure Chuck Lever
` (27 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Hand-written XDR encoders and decoders are difficult to maintain
and can inadvertently diverge from protocol specifications. By
migrating to xdrgen-generated code, we improve type safety and
ensure the implementation exactly matches the NLM version 4
protocol specification.
This patch begins the migration by converting the NULL procedure
to use nlm4_svc_decode_void and nlm4_svc_encode_void generated
from Documentation/sunrpc/xdr/nlm4.x. The NULL procedure is
straightforward as it has no arguments or results, making it an
ideal starting point for this series.
The pc_xdrressize field is set to XDR_void (zero) to reflect
that this procedure returns no XDR-encoded data. The argzero
field is also set to zero since xdrgen decoders reliably
initialize all decoded values.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 40 ++++++++++++++++++++++++++++------------
1 file changed, 28 insertions(+), 12 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 0f31fec178c8..28b2e35a1e8c 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -13,7 +13,17 @@
#include <linux/sunrpc/svc_xprt.h>
#include "lockd.h"
+
+/*
+ * xdr.h defines SM_MAXSTRLEN and SM_PRIV_SIZE as macros.
+ * nlm4xdr_gen.h defines them as enum constants. Undefine the
+ * macros to allow the xdrgen enum definitions to be used.
+ */
+#undef SM_MAXSTRLEN
+#undef SM_PRIV_SIZE
+
#include "share.h"
+#include "nlm4xdr_gen.h"
#include "xdr4.h"
#define NLMDBG_FACILITY NLMDBG_CLIENT
@@ -87,13 +97,19 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
}
}
-/*
- * NULL: Test for presence of service
+/**
+ * nlm4svc_proc_null - NULL: Test for presence of service
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully
+ *
+ * RPC synopsis:
+ * void NLMPROC4_NULL(void) = 0;
*/
static __be32
nlm4svc_proc_null(struct svc_rqst *rqstp)
{
- dprintk("lockd: NULL called\n");
return rpc_success;
}
@@ -520,15 +536,15 @@ struct nlm_void { int dummy; };
#define Rg 4 /* range (offset + length) */
static const struct svc_procedure nlm4svc_procedures[24] = {
- [NLMPROC_NULL] = {
- .pc_func = nlm4svc_proc_null,
- .pc_decode = nlm4svc_decode_void,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_void),
- .pc_argzero = sizeof(struct nlm_void),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "NULL",
+ [NLMPROC4_NULL] = {
+ .pc_func = nlm4svc_proc_null,
+ .pc_decode = nlm4_svc_decode_void,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = XDR_void,
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "NULL",
},
[NLMPROC_TEST] = {
.pc_func = nlm4svc_proc_test,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 16/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (14 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 15/42] lockd: Use xdrgen XDR functions for the NLMv4 NULL procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 17/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK procedure Chuck Lever
` (26 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The NLM TEST procedure requires host and file lookups to check
lock state, operations that will be common across multiple NLM
procedures being migrated to xdrgen. By introducing the helper
functions nlm4svc_lookup_host() and nlm4svc_lookup_file() now,
we establish reusable patterns for subsequent conversions in
this series.
This patch converts the TEST procedure to use xdrgen functions
nlm4_svc_decode_testargs and nlm4_svc_encode_testres generated
from the NLM version 4 protocol specification. The procedure
handler is rewritten to use xdrgen types through wrapper
structures that bridge between generated code and the legacy
nlm_lock representation still used by the core lockd logic.
TEST_MSG is to be converted in a subsequent patch.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments in the argp->xdrgen field,
making the early defensive memset unnecessary. Remaining argp
fields are cleared as needed.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 186 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 174 insertions(+), 12 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 28b2e35a1e8c..200544f0977f 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -28,6 +28,95 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT
+/*
+ * Wrapper structures combine xdrgen types with legacy nlm_lock.
+ * The xdrgen field must be first so the structure can be cast
+ * to its XDR type for the RPC dispatch layer.
+ */
+struct nlm4_testargs_wrapper {
+ struct nlm4_testargs xdrgen;
+ struct nlm_lock lock;
+};
+
+static_assert(offsetof(struct nlm4_testargs_wrapper, xdrgen) == 0);
+
+struct nlm4_testres_wrapper {
+ struct nlm4_testres xdrgen;
+ struct nlm_lock lock;
+};
+
+static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0);
+
+static struct nlm_host *
+nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
+{
+ struct nlm_host *host;
+
+ if (!nlmsvc_ops)
+ return NULL;
+ host = nlmsvc_lookup_host(rqstp, caller.data, caller.len);
+ if (!host)
+ return NULL;
+ if (monitored && nsm_monitor(host) < 0) {
+ nlmsvc_release_host(host);
+ return NULL;
+ }
+ return host;
+}
+
+static __be32
+nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
+ struct nlm_lock *lock, struct nlm_file **filp,
+ struct nlm4_lock *xdr_lock, unsigned char type)
+{
+ struct file_lock *fl = &lock->fl;
+ struct nlm_file *file = NULL;
+ __be32 error;
+
+ if (xdr_lock->fh.len > NFS_MAXFHSIZE)
+ return nlm_lck_denied_nolocks;
+ lock->fh.size = xdr_lock->fh.len;
+ memcpy(lock->fh.data, xdr_lock->fh.data, xdr_lock->fh.len);
+
+ lock->oh.len = xdr_lock->oh.len;
+ lock->oh.data = xdr_lock->oh.data;
+
+ lock->svid = xdr_lock->svid;
+ lock->lock_start = xdr_lock->l_offset;
+ lock->lock_len = xdr_lock->l_len;
+
+ if (lock->lock_start > OFFSET_MAX ||
+ (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start))))
+ return nlm4_fbig;
+
+ locks_init_lock(fl);
+ fl->c.flc_type = type;
+ lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len);
+
+ error = nlm_lookup_file(rqstp, &file, lock);
+ switch (error) {
+ case nlm_granted:
+ break;
+ case nlm__int__stale_fh:
+ return nlm4_stale_fh;
+ case nlm__int__failed:
+ return nlm4_failed;
+ default:
+ return error;
+ }
+ *filp = file;
+
+ fl->c.flc_flags = FL_POSIX;
+ fl->c.flc_file = file->f_file[lock_to_openmode(fl)];
+ fl->c.flc_pid = current->tgid;
+ fl->fl_lmops = &nlmsvc_lock_operations;
+ nlmsvc_locks_init_private(fl, host, (pid_t)lock->svid);
+ if (!fl->c.flc_owner)
+ return nlm_lck_denied_nolocks;
+
+ return nlm_granted;
+}
+
/*
* Obtain client and file from arguments
*/
@@ -145,10 +234,81 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
return rc;
}
-static __be32
-nlm4svc_proc_test(struct svc_rqst *rqstp)
+/**
+ * nlm4svc_proc_test - TEST: Check for conflicting lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_drop_reply: Do not send an RPC reply.
+ *
+ * RPC synopsis:
+ * nlm4_testres NLMPROC4_TEST(nlm4_testargs) = 1;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_GRANTED: The server would be able to grant the
+ * requested lock.
+ * %NLM4_DENIED: The requested lock conflicted with existing
+ * lock reservations for the file.
+ * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
+ * needed to process the request.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ *
+ * The Linux NLM server implementation also returns:
+ * %NLM4_STALE_FH: The request specified an invalid file handle.
+ * %NLM4_FBIG: The request specified a length or offset
+ * that exceeds the range supported by the
+ * server.
+ * %NLM4_FAILED: The request failed for an unspecified reason.
+ */
+static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp)
{
- return __nlm4svc_proc_test(rqstp, rqstp->rq_resp);
+ struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
+ unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
+ struct nlm4_testres_wrapper *resp = rqstp->rq_resp;
+ struct nlm_file *file = NULL;
+ struct nlm_host *host;
+
+ resp->xdrgen.cookie = argp->xdrgen.cookie;
+
+ resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
+ if (!host)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock,
+ type);
+ if (resp->xdrgen.stat.stat)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlmsvc_testlock(rqstp, file, host,
+ &argp->lock, &resp->lock);
+ nlmsvc_release_lockowner(&argp->lock);
+
+ if (resp->xdrgen.stat.stat == nlm_lck_denied) {
+ struct nlm_lock *conf = &resp->lock;
+ struct nlm4_holder *holder = &resp->xdrgen.stat.u.holder;
+
+ holder->exclusive = (conf->fl.c.flc_type != F_RDLCK);
+ holder->svid = conf->svid;
+ holder->oh.len = conf->oh.len;
+ holder->oh.data = conf->oh.data;
+ holder->l_offset = conf->fl.fl_start;
+ if (conf->fl.fl_end == OFFSET_MAX)
+ holder->l_len = 0;
+ else
+ holder->l_len = conf->fl.fl_end - conf->fl.fl_start + 1;
+ }
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->xdrgen.stat.stat == nlm_drop_reply ?
+ rpc_drop_reply : rpc_success;
}
static __be32
@@ -546,15 +706,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "NULL",
},
- [NLMPROC_TEST] = {
- .pc_func = nlm4svc_proc_test,
- .pc_decode = nlm4svc_decode_testargs,
- .pc_encode = nlm4svc_encode_testres,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St+2+No+Rg,
- .pc_name = "TEST",
+ [NLMPROC4_TEST] = {
+ .pc_func = nlm4svc_proc_test,
+ .pc_decode = nlm4_svc_decode_nlm4_testargs,
+ .pc_encode = nlm4_svc_encode_nlm4_testres,
+ .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_testres_wrapper),
+ .pc_xdrressize = NLM4_nlm4_testres_sz,
+ .pc_name = "TEST",
},
[NLMPROC_LOCK] = {
.pc_func = nlm4svc_proc_lock,
@@ -782,6 +942,8 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
* Storage requirements for XDR arguments and results
*/
union nlm4svc_xdrstore {
+ struct nlm4_testargs_wrapper testargs;
+ struct nlm4_testres_wrapper testres;
struct nlm_args args;
struct nlm_res res;
struct nlm_reboot reboot;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 17/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (15 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 16/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 18/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL procedure Chuck Lever
` (25 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Replace legacy XDR handling in the LOCK procedure with xdrgen-
generated functions nlm4_svc_decode_lockargs and
nlm4_svc_encode_res.
The new nlm4svc_do_lock() handler replaces __nlm4svc_proc_lock()
at the NLMPROC4_LOCK entry point. Wrapper structures bridge
xdrgen types to the legacy nlm_lock representation used by core
lockd. The nlm4svc_lookup_host() and nlm4svc_lookup_file()
helpers from the TEST conversion handle host and file lookup.
The pc_argzero field is set to zero: xdrgen-generated decoders
initialize all fields in argp->xdrgen, so a defensive memset is
unnecessary. The wrapper's cookie and lock fields are cleared
by nlm4svc_do_lock() before use.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 127 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 115 insertions(+), 12 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 200544f0977f..2da3ff76be5a 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -40,6 +40,14 @@ struct nlm4_testargs_wrapper {
static_assert(offsetof(struct nlm4_testargs_wrapper, xdrgen) == 0);
+struct nlm4_lockargs_wrapper {
+ struct nlm4_lockargs xdrgen;
+ struct nlm_cookie cookie;
+ struct nlm_lock lock;
+};
+
+static_assert(offsetof(struct nlm4_lockargs_wrapper, xdrgen) == 0);
+
struct nlm4_testres_wrapper {
struct nlm4_testres xdrgen;
struct nlm_lock lock;
@@ -47,6 +55,22 @@ struct nlm4_testres_wrapper {
static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0);
+struct nlm4_res_wrapper {
+ struct nlm4_res xdrgen;
+};
+
+static_assert(offsetof(struct nlm4_res_wrapper, xdrgen) == 0);
+
+static __be32
+nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object)
+{
+ if (object->len > NLM_MAXCOOKIELEN)
+ return nlm_lck_denied_nolocks;
+ cookie->len = object->len;
+ memcpy(cookie->data, object->data, object->len);
+ return nlm_granted;
+}
+
static struct nlm_host *
nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
{
@@ -348,10 +372,88 @@ __nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp)
return rc;
}
+static __be32
+nlm4svc_do_lock(struct svc_rqst *rqstp, bool monitored)
+{
+ struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
+ unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
+ struct nlm4_res_wrapper *resp = rqstp->rq_resp;
+ struct nlm_file *file = NULL;
+ struct nlm_host *host = NULL;
+
+ resp->xdrgen.cookie = argp->xdrgen.cookie;
+
+ resp->xdrgen.stat.stat = nlm4_netobj_to_cookie(&argp->cookie,
+ &argp->xdrgen.cookie);
+ if (resp->xdrgen.stat.stat)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name,
+ monitored);
+ if (!host)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock,
+ type);
+ if (resp->xdrgen.stat.stat)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlmsvc_lock(rqstp, file, host, &argp->lock,
+ argp->xdrgen.block, &argp->cookie,
+ argp->xdrgen.reclaim);
+ if (resp->xdrgen.stat.stat == nlm__int__deadlock)
+ resp->xdrgen.stat.stat = nlm4_deadlock;
+
+ nlmsvc_release_lockowner(&argp->lock);
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->xdrgen.stat.stat == nlm_drop_reply ?
+ rpc_drop_reply : rpc_success;
+}
+
+/**
+ * nlm4svc_proc_lock - LOCK: Establish a monitored lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_drop_reply: Do not send an RPC reply.
+ *
+ * RPC synopsis:
+ * nlm4_res NLMPROC4_LOCK(nlm4_lockargs) = 2;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_GRANTED: The requested lock was granted.
+ * %NLM4_DENIED: The requested lock conflicted with existing
+ * lock reservations for the file.
+ * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
+ * needed to process the request.
+ * %NLM4_BLOCKED: The blocking request cannot be granted
+ * immediately. The server will send an
+ * NLMPROC4_GRANTED callback to the client when
+ * the lock can be granted.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ *
+ * The Linux NLM server implementation also returns:
+ * %NLM4_DEADLCK: The request could not be granted and
+ * blocking would cause a deadlock.
+ * %NLM4_STALE_FH: The request specified an invalid file handle.
+ * %NLM4_FBIG: The request specified a length or offset
+ * that exceeds the range supported by the
+ * server.
+ * %NLM4_FAILED: The request failed for an unspecified reason.
+ */
static __be32
nlm4svc_proc_lock(struct svc_rqst *rqstp)
{
- return __nlm4svc_proc_lock(rqstp, rqstp->rq_resp);
+ return nlm4svc_do_lock(rqstp, true);
}
static __be32
@@ -618,7 +720,7 @@ nlm4svc_proc_nm_lock(struct svc_rqst *rqstp)
dprintk("lockd: NM_LOCK called\n");
argp->monitor = 0; /* just clean the monitor flag */
- return nlm4svc_proc_lock(rqstp);
+ return __nlm4svc_proc_lock(rqstp, rqstp->rq_resp);
}
/*
@@ -716,15 +818,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = NLM4_nlm4_testres_sz,
.pc_name = "TEST",
},
- [NLMPROC_LOCK] = {
- .pc_func = nlm4svc_proc_lock,
- .pc_decode = nlm4svc_decode_lockargs,
- .pc_encode = nlm4svc_encode_res,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St,
- .pc_name = "LOCK",
+ [NLMPROC4_LOCK] = {
+ .pc_func = nlm4svc_proc_lock,
+ .pc_decode = nlm4_svc_decode_nlm4_lockargs,
+ .pc_encode = nlm4_svc_encode_nlm4_res,
+ .pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_res_wrapper),
+ .pc_xdrressize = NLM4_nlm4_res_sz,
+ .pc_name = "LOCK",
},
[NLMPROC_CANCEL] = {
.pc_func = nlm4svc_proc_cancel,
@@ -943,9 +1045,10 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
*/
union nlm4svc_xdrstore {
struct nlm4_testargs_wrapper testargs;
+ struct nlm4_lockargs_wrapper lockargs;
struct nlm4_testres_wrapper testres;
+ struct nlm4_res_wrapper res;
struct nlm_args args;
- struct nlm_res res;
struct nlm_reboot reboot;
};
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 18/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (16 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 17/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 19/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK procedure Chuck Lever
` (24 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The NLM CANCEL procedure allows clients to cancel outstanding
blocked lock requests, completing the set of lock-related
operations that share common lookup patterns. This patch
continues the xdrgen migration by converting the CANCEL
procedure, leveraging the same nlm4svc_lookup_host() and
nlm4svc_lookup_file() helpers established in the TEST procedure
conversion to maintain consistency across the series.
This patch converts the CANCEL procedure to use xdrgen functions
nlm4_svc_decode_nlm4_cancargs and nlm4_svc_encode_nlm4_res
generated from the NLM version 4 protocol specification. The
procedure handler uses xdrgen types through a wrapper structure
that bridges between generated code and the legacy nlm_lock
representation still used by the core lockd logic.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments in the argp->xdrgen field,
making the early defensive memset unnecessary. Remaining argp
fields are cleared as needed.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 86 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 76 insertions(+), 10 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 2da3ff76be5a..1b70935df4d0 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -48,6 +48,13 @@ struct nlm4_lockargs_wrapper {
static_assert(offsetof(struct nlm4_lockargs_wrapper, xdrgen) == 0);
+struct nlm4_cancargs_wrapper {
+ struct nlm4_cancargs xdrgen;
+ struct nlm_lock lock;
+};
+
+static_assert(offsetof(struct nlm4_cancargs_wrapper, xdrgen) == 0);
+
struct nlm4_testres_wrapper {
struct nlm4_testres xdrgen;
struct nlm_lock lock;
@@ -487,10 +494,68 @@ __nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_res *resp)
return rpc_success;
}
+/**
+ * nlm4svc_proc_cancel - CANCEL: Cancel an outstanding blocked lock request
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully
+ * %rpc_drop_reply: Do not send an RPC reply
+ *
+ * RPC synopsis:
+ * nlm4_res NLMPROC4_CANCEL(nlm4_cancargs) = 3;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_LCK_GRANTED: The requested lock was canceled.
+ * %NLM4_LCK_DENIED: There was no lock to cancel.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ *
+ * The Linux NLM server implementation also returns:
+ * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
+ * %NLM4_STALE_FH: The request specified an invalid file handle.
+ * %NLM4_FBIG: The request specified a length or offset
+ * that exceeds the range supported by the
+ * server.
+ * %NLM4_FAILED: The request failed for an unspecified reason.
+ */
static __be32
nlm4svc_proc_cancel(struct svc_rqst *rqstp)
{
- return __nlm4svc_proc_cancel(rqstp, rqstp->rq_resp);
+ struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
+ unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
+ struct nlm4_res_wrapper *resp = rqstp->rq_resp;
+ struct net *net = SVC_NET(rqstp);
+ struct nlm_host *host = NULL;
+ struct nlm_file *file = NULL;
+
+ resp->xdrgen.cookie = argp->xdrgen.cookie;
+
+ resp->xdrgen.stat.stat = nlm_lck_denied_grace_period;
+ if (locks_in_grace(net))
+ goto out;
+
+ resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
+ if (!host)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock,
+ type);
+ if (resp->xdrgen.stat.stat)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlmsvc_cancel_blocked(net, file, &argp->lock);
+ nlmsvc_release_lockowner(&argp->lock);
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->xdrgen.stat.stat == nlm_drop_reply ?
+ rpc_drop_reply : rpc_success;
}
/*
@@ -828,15 +893,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = NLM4_nlm4_res_sz,
.pc_name = "LOCK",
},
- [NLMPROC_CANCEL] = {
- .pc_func = nlm4svc_proc_cancel,
- .pc_decode = nlm4svc_decode_cancargs,
- .pc_encode = nlm4svc_encode_res,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St,
- .pc_name = "CANCEL",
+ [NLMPROC4_CANCEL] = {
+ .pc_func = nlm4svc_proc_cancel,
+ .pc_decode = nlm4_svc_decode_nlm4_cancargs,
+ .pc_encode = nlm4_svc_encode_nlm4_res,
+ .pc_argsize = sizeof(struct nlm4_cancargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_res_wrapper),
+ .pc_xdrressize = NLM4_nlm4_res_sz,
+ .pc_name = "CANCEL",
},
[NLMPROC_UNLOCK] = {
.pc_func = nlm4svc_proc_unlock,
@@ -1046,6 +1111,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
union nlm4svc_xdrstore {
struct nlm4_testargs_wrapper testargs;
struct nlm4_lockargs_wrapper lockargs;
+ struct nlm4_cancargs_wrapper cancargs;
struct nlm4_testres_wrapper testres;
struct nlm4_res_wrapper res;
struct nlm_args args;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 19/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (17 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 18/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 20/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED procedure Chuck Lever
` (23 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
UNLOCK releases locks acquired via the LOCK procedure. Conversion
of TEST, LOCK, CANCEL, and UNLOCK provides the complete set of
lock lifecycle operations required by the NLM protocol, enabling
clients to test for conflicts, acquire locks, abort pending lock
requests, and release held locks.
The procedure handler converts arguments from the xdrgen-generated
nlm4_unlockargs structure to the legacy nlm_lock representation
through nlm4_unlockargs_wrapper. This maintains compatibility with
core lockd logic while using XDR decoders and encoders generated
from the NLMv4 protocol specification.
The original __nlm4svc_proc_unlock function is retained because
the asynchronous callback path invokes it directly, bypassing
the RPC dispatch mechanism.
The pc_argzero field is zero because nlm4_svc_decode_nlm4_unlockargs
initializes all fields in argp->xdrgen, eliminating the need for
early memset of the argument buffer. Remaining argp fields outside
the xdrgen structure are cleared explicitly where needed.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 84 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 74 insertions(+), 10 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 1b70935df4d0..f0f3e73eee75 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -55,6 +55,13 @@ struct nlm4_cancargs_wrapper {
static_assert(offsetof(struct nlm4_cancargs_wrapper, xdrgen) == 0);
+struct nlm4_unlockargs_wrapper {
+ struct nlm4_unlockargs xdrgen;
+ struct nlm_lock lock;
+};
+
+static_assert(offsetof(struct nlm4_unlockargs_wrapper, xdrgen) == 0);
+
struct nlm4_testres_wrapper {
struct nlm4_testres xdrgen;
struct nlm_lock lock;
@@ -592,10 +599,66 @@ __nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_res *resp)
return rpc_success;
}
+/**
+ * nlm4svc_proc_unlock - UNLOCK: Remove a lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_drop_reply: Do not send an RPC reply.
+ *
+ * RPC synopsis:
+ * nlm4_res NLMPROC4_UNLOCK(nlm4_unlockargs) = 4;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_GRANTED: The requested lock was released.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ *
+ * The Linux NLM server implementation also returns:
+ * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
+ * %NLM4_STALE_FH: The request specified an invalid file handle.
+ * %NLM4_FBIG: The request specified a length or offset
+ * that exceeds the range supported by the
+ * server.
+ * %NLM4_FAILED: The request failed for an unspecified reason.
+ */
static __be32
nlm4svc_proc_unlock(struct svc_rqst *rqstp)
{
- return __nlm4svc_proc_unlock(rqstp, rqstp->rq_resp);
+ struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm4_res_wrapper *resp = rqstp->rq_resp;
+ struct net *net = SVC_NET(rqstp);
+ struct nlm_host *host = NULL;
+ struct nlm_file *file = NULL;
+
+ resp->xdrgen.cookie = argp->xdrgen.cookie;
+
+ resp->xdrgen.stat.stat = nlm_lck_denied_grace_period;
+ if (locks_in_grace(net))
+ goto out;
+
+ resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
+ if (!host)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock,
+ F_UNLCK);
+ if (resp->xdrgen.stat.stat)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlmsvc_unlock(net, file, &argp->lock);
+ nlmsvc_release_lockowner(&argp->lock);
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->xdrgen.stat.stat == nlm_drop_reply ?
+ rpc_drop_reply : rpc_success;
}
/*
@@ -903,15 +966,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = NLM4_nlm4_res_sz,
.pc_name = "CANCEL",
},
- [NLMPROC_UNLOCK] = {
- .pc_func = nlm4svc_proc_unlock,
- .pc_decode = nlm4svc_decode_unlockargs,
- .pc_encode = nlm4svc_encode_res,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St,
- .pc_name = "UNLOCK",
+ [NLMPROC4_UNLOCK] = {
+ .pc_func = nlm4svc_proc_unlock,
+ .pc_decode = nlm4_svc_decode_nlm4_unlockargs,
+ .pc_encode = nlm4_svc_encode_nlm4_res,
+ .pc_argsize = sizeof(struct nlm4_unlockargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_res_wrapper),
+ .pc_xdrressize = NLM4_nlm4_res_sz,
+ .pc_name = "UNLOCK",
},
[NLMPROC_GRANTED] = {
.pc_func = nlm4svc_proc_granted,
@@ -1112,6 +1175,7 @@ union nlm4svc_xdrstore {
struct nlm4_testargs_wrapper testargs;
struct nlm4_lockargs_wrapper lockargs;
struct nlm4_cancargs_wrapper cancargs;
+ struct nlm4_unlockargs_wrapper unlockargs;
struct nlm4_testres_wrapper testres;
struct nlm4_res_wrapper res;
struct nlm_args args;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 20/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (18 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 19/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 21/42] lockd: Refactor nlm4svc_callback() Chuck Lever
` (22 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The NLM GRANTED procedure provides server-to-client notification
when a previously blocked lock request has been granted,
completing the asynchronous lock request flow. This patch
completes the xdrgen migration for basic NLMv4 procedures by
converting the GRANTED procedure, the final one in this
conversion series.
This patch converts the GRANTED procedure to use xdrgen
functions nlm4_svc_decode_nlm4_testargs and
nlm4_svc_encode_nlm4_res generated from the NLM version 4
protocol specification. The procedure handler uses xdrgen types
through a wrapper structure that bridges between generated code
and the legacy nlm_lock representation still used by the core
lockd logic.
A new helper function nlm4_lock_to_nlm_lock() is introduced to
convert xdrgen nlm4_lock structures to the legacy nlm_lock
format. This helper complements the existing
nlm4svc_lookup_host() and nlm4svc_lookup_file() functions used
throughout this series.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments in the argp->xdrgen field,
making the early defensive memset unnecessary. Remaining argp
fields are cleared as needed.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 66 ++++++++++++++++++++++++++++++++++++++-------
1 file changed, 56 insertions(+), 10 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index f0f3e73eee75..fb0ff4a04ced 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -85,6 +85,21 @@ nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object)
return nlm_granted;
}
+static __be32
+nlm4_lock_to_nlm_lock(struct nlm_lock *lock, struct nlm4_lock *alock)
+{
+ if (alock->fh.len > NFS_MAXFHSIZE)
+ return nlm_lck_denied;
+ lock->fh.size = alock->fh.len;
+ memcpy(lock->fh.data, alock->fh.data, alock->fh.len);
+ lock->oh.len = alock->oh.len;
+ lock->oh.data = alock->oh.data;
+ lock->svid = alock->svid;
+ locks_init_lock(&lock->fl);
+ lockd_set_file_lock_range4(&lock->fl, alock->l_offset, alock->l_len);
+ return nlm_granted;
+}
+
static struct nlm_host *
nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
{
@@ -678,10 +693,41 @@ __nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_res *resp)
return rpc_success;
}
+/**
+ * nlm4svc_proc_granted - GRANTED: Server grants a previously blocked lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ *
+ * RPC synopsis:
+ * nlm4_res NLMPROC4_GRANTED(nlm4_testargs) = 5;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_GRANTED: The requested lock was granted.
+ * %NLM4_DENIED: The server could not allocate the resources
+ * needed to process the request.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ */
static __be32
nlm4svc_proc_granted(struct svc_rqst *rqstp)
{
- return __nlm4svc_proc_granted(rqstp, rqstp->rq_resp);
+ struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm4_res_wrapper *resp = rqstp->rq_resp;
+
+ resp->xdrgen.cookie = argp->xdrgen.cookie;
+
+ resp->xdrgen.stat.stat = nlm4_lock_to_nlm_lock(&argp->lock,
+ &argp->xdrgen.alock);
+ if (resp->xdrgen.stat.stat)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
+
+out:
+ return rpc_success;
}
/*
@@ -976,15 +1022,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = NLM4_nlm4_res_sz,
.pc_name = "UNLOCK",
},
- [NLMPROC_GRANTED] = {
- .pc_func = nlm4svc_proc_granted,
- .pc_decode = nlm4svc_decode_testargs,
- .pc_encode = nlm4svc_encode_res,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St,
- .pc_name = "GRANTED",
+ [NLMPROC4_GRANTED] = {
+ .pc_func = nlm4svc_proc_granted,
+ .pc_decode = nlm4_svc_decode_nlm4_testargs,
+ .pc_encode = nlm4_svc_encode_nlm4_res,
+ .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_res_wrapper),
+ .pc_xdrressize = NLM4_nlm4_res_sz,
+ .pc_name = "GRANTED",
},
[NLMPROC_TEST_MSG] = {
.pc_func = nlm4svc_proc_test_msg,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 21/42] lockd: Refactor nlm4svc_callback()
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (19 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 20/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 22/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST_MSG procedure Chuck Lever
` (21 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The xdrgen-based XDR conversion requires each RPC procedure
to handle its own argument extraction, since xdrgen generates
distinct argument structures for each procedure rather than
using a single shared type.
This patch moves the host lookup logic from nlm4svc_callback()
into each of the five MSG procedure handlers (TEST_MSG,
LOCK_MSG, CANCEL_MSG, UNLOCK_MSG, and GRANTED_MSG). Each
handler now performs its own host lookup from rqstp->rq_argp
and passes the resulting host pointer to nlm4svc_callback(),
which is reduced to a simpler helper that only dispatches
the callback.
This refactoring enables the subsequent xdrgen conversion
patches by establishing the pattern where each procedure
handles its own argument extraction, while preserving
existing callback behavior unchanged.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 80 +++++++++++++++++++++++++++++++++++----------
1 file changed, 62 insertions(+), 18 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index fb0ff4a04ced..e3af1f4a56c4 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -748,24 +748,17 @@ static const struct rpc_call_ops nlm4svc_callback_ops = {
};
/*
- * `Async' versions of the above service routines. They aren't really,
- * because we send the callback before the reply proper. I hope this
- * doesn't break any clients.
+ * Dispatch an async callback RPC to a client with a pre-resolved host.
+ * Caller provides a reference to @host; this function takes ownership
+ * and releases it via nlmsvc_release_host() before returning.
*/
-static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc,
- __be32 (*func)(struct svc_rqst *, struct nlm_res *))
+static __be32
+nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc,
+ __be32 (*func)(struct svc_rqst *, struct nlm_res *))
{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
struct nlm_rqst *call;
__be32 stat;
- host = nlmsvc_lookup_host(rqstp,
- argp->lock.caller,
- argp->lock.len);
- if (host == NULL)
- return rpc_system_err;
-
call = nlm_alloc_call(host);
nlmsvc_release_host(host);
if (call == NULL)
@@ -783,34 +776,85 @@ static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc,
return rpc_success;
}
+/*
+ * 'Async' versions of the above service routines. They aren't really,
+ * because we send the callback before the reply proper. I hope this
+ * doesn't break any clients.
+ */
+
static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp)
{
+ struct nlm_args *argp = rqstp->rq_argp;
+ struct nlm_host *host;
+
dprintk("lockd: TEST_MSG called\n");
- return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, __nlm4svc_proc_test);
+
+ host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ if (!host)
+ return rpc_system_err;
+
+ return nlm4svc_callback(rqstp, host, NLMPROC_TEST_RES,
+ __nlm4svc_proc_test);
}
static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
{
+ struct nlm_args *argp = rqstp->rq_argp;
+ struct nlm_host *host;
+
dprintk("lockd: LOCK_MSG called\n");
- return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, __nlm4svc_proc_lock);
+
+ host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ if (!host)
+ return rpc_system_err;
+
+ return nlm4svc_callback(rqstp, host, NLMPROC_LOCK_RES,
+ __nlm4svc_proc_lock);
}
static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
{
+ struct nlm_args *argp = rqstp->rq_argp;
+ struct nlm_host *host;
+
dprintk("lockd: CANCEL_MSG called\n");
- return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, __nlm4svc_proc_cancel);
+
+ host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ if (!host)
+ return rpc_system_err;
+
+ return nlm4svc_callback(rqstp, host, NLMPROC_CANCEL_RES,
+ __nlm4svc_proc_cancel);
}
static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
{
+ struct nlm_args *argp = rqstp->rq_argp;
+ struct nlm_host *host;
+
dprintk("lockd: UNLOCK_MSG called\n");
- return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, __nlm4svc_proc_unlock);
+
+ host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ if (!host)
+ return rpc_system_err;
+
+ return nlm4svc_callback(rqstp, host, NLMPROC_UNLOCK_RES,
+ __nlm4svc_proc_unlock);
}
static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
{
+ struct nlm_args *argp = rqstp->rq_argp;
+ struct nlm_host *host;
+
dprintk("lockd: GRANTED_MSG called\n");
- return nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, __nlm4svc_proc_granted);
+
+ host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ if (!host)
+ return rpc_system_err;
+
+ return nlm4svc_callback(rqstp, host, NLMPROC_GRANTED_RES,
+ __nlm4svc_proc_granted);
}
/*
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 22/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST_MSG procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (20 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 21/42] lockd: Refactor nlm4svc_callback() Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 23/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK_MSG procedure Chuck Lever
` (20 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The TEST_MSG procedure is part of NLM's asynchronous lock request
flow, where clients send TEST_MSG to check lock availability
without blocking. This patch continues the xdrgen migration by
converting TEST_MSG to use generated XDR functions.
This patch converts the TEST_MSG procedure to use xdrgen
functions nlm4_svc_decode_nlm4_testargs and
nlm4_svc_encode_void generated from the NLM version 4 protocol
specification. The procedure handler uses xdrgen types through
the nlm4_testargs_wrapper structure that bridges between
generated code and the legacy nlm_lock representation.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments in the argp->xdrgen field,
making the early defensive memset unnecessary. Remaining argp
fields are cleared as needed.
The NLM async callback mechanism uses client-side functions
which continue to take legacy results like struct nlm_res,
preventing TEST and TEST_MSG from sharing code for now.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 113 +++++++++++++++++++++++---------------------
1 file changed, 60 insertions(+), 53 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index e3af1f4a56c4..c0e043fa0eba 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -255,38 +255,6 @@ nlm4svc_proc_null(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * TEST: Check for conflicting lock
- */
-static __be32
-__nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
- struct nlm_file *file;
- __be32 rc = rpc_success;
-
- dprintk("lockd: TEST4 called\n");
- resp->cookie = argp->cookie;
-
- /* Obtain client and file */
- if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
-
- /* Now check for conflicting locks */
- resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock,
- &resp->lock);
- if (resp->status == nlm_drop_reply)
- rc = rpc_drop_reply;
- else
- dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
-
- nlmsvc_release_lockowner(&argp->lock);
- nlmsvc_release_host(host);
- nlm_release_file(file);
- return rc;
-}
-
/**
* nlm4svc_proc_test - TEST: Check for conflicting lock
* @rqstp: RPC transaction context
@@ -776,25 +744,64 @@ nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc,
return rpc_success;
}
-/*
- * 'Async' versions of the above service routines. They aren't really,
- * because we send the callback before the reply proper. I hope this
- * doesn't break any clients.
- */
+static __be32
+__nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
+{
+ struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
+ unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
+ struct nlm_lockowner *owner;
+ struct nlm_file *file = NULL;
+ struct nlm_host *host = NULL;
+ resp->status = nlm_lck_denied_nolocks;
+ if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
+ goto out;
+
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
+ if (!host)
+ goto out;
+
+ resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock, type);
+ if (resp->status)
+ goto out;
+
+ owner = argp->lock.fl.c.flc_owner;
+ resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock,
+ &resp->lock);
+ nlmsvc_put_lockowner(owner);
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->status == nlm_drop_reply ? rpc_drop_reply : rpc_success;
+}
+
+/**
+ * nlm4svc_proc_test_msg - TEST_MSG: Check for conflicting lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_system_err: RPC execution failed.
+ *
+ * RPC synopsis:
+ * void NLMPROC4_TEST_MSG(nlm4_testargs) = 6;
+ *
+ * The response to this request is delivered via the TEST_RES procedure.
+ */
static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
+ struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm_host *host;
- dprintk("lockd: TEST_MSG called\n");
-
- host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
if (!host)
return rpc_system_err;
- return nlm4svc_callback(rqstp, host, NLMPROC_TEST_RES,
- __nlm4svc_proc_test);
+ return nlm4svc_callback(rqstp, host, NLMPROC4_TEST_RES,
+ __nlm4svc_proc_test_msg);
}
static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
@@ -1076,15 +1083,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = NLM4_nlm4_res_sz,
.pc_name = "GRANTED",
},
- [NLMPROC_TEST_MSG] = {
- .pc_func = nlm4svc_proc_test_msg,
- .pc_decode = nlm4svc_decode_testargs,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "TEST_MSG",
+ [NLMPROC4_TEST_MSG] = {
+ .pc_func = nlm4svc_proc_test_msg,
+ .pc_decode = nlm4_svc_decode_nlm4_testargs,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "TEST_MSG",
},
[NLMPROC_LOCK_MSG] = {
.pc_func = nlm4svc_proc_lock_msg,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 23/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK_MSG procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (21 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 22/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST_MSG procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 24/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_MSG procedure Chuck Lever
` (19 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The LOCK_MSG procedure is part of NLM's asynchronous lock
request flow, where clients send LOCK_MSG to request locks
that may block. This patch continues the xdrgen migration by
converting LOCK_MSG to use generated XDR functions.
This patch converts the LOCK_MSG procedure to use xdrgen
functions nlm4_svc_decode_nlm4_lockargs and
nlm4_svc_encode_void generated from the NLM version 4
protocol specification. The procedure handler uses xdrgen
types through the nlm4_lockargs_wrapper structure that
bridges between generated code and the legacy nlm_lock
representation.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments in the argp->xdrgen field,
making the early defensive memset unnecessary. Remaining
argp fields are cleared as needed.
The NLM async callback mechanism uses client-side functions
which continue to take legacy results like struct nlm_res,
preventing LOCK and LOCK_MSG from sharing code for now.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 76 +++++++++++++++++++++++++++++++++++----------
1 file changed, 60 insertions(+), 16 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index c0e043fa0eba..7ab458648637 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -804,19 +804,63 @@ static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp)
__nlm4svc_proc_test_msg);
}
+static __be32
+__nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
+{
+ struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
+ unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
+ struct nlm_file *file = NULL;
+ struct nlm_host *host = NULL;
+
+ resp->status = nlm_lck_denied_nolocks;
+ if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
+ goto out;
+
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true);
+ if (!host)
+ goto out;
+
+ resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock, type);
+ if (resp->status)
+ goto out;
+
+ resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
+ argp->xdrgen.block, &resp->cookie,
+ argp->xdrgen.reclaim);
+ nlmsvc_release_lockowner(&argp->lock);
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->status == nlm_drop_reply ? rpc_drop_reply : rpc_success;
+}
+
+/**
+ * nlm4svc_proc_lock_msg - LOCK_MSG: Establish a monitored lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_system_err: RPC execution failed.
+ *
+ * RPC synopsis:
+ * void NLMPROC4_LOCK_MSG(nlm4_lockargs) = 7;
+ *
+ * The response to this request is delivered via the LOCK_RES procedure.
+ */
static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
+ struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm_host *host;
- dprintk("lockd: LOCK_MSG called\n");
-
- host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true);
if (!host)
return rpc_system_err;
- return nlm4svc_callback(rqstp, host, NLMPROC_LOCK_RES,
- __nlm4svc_proc_lock);
+ return nlm4svc_callback(rqstp, host, NLMPROC4_LOCK_RES,
+ __nlm4svc_proc_lock_msg);
}
static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
@@ -1093,15 +1137,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "TEST_MSG",
},
- [NLMPROC_LOCK_MSG] = {
- .pc_func = nlm4svc_proc_lock_msg,
- .pc_decode = nlm4svc_decode_lockargs,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "LOCK_MSG",
+ [NLMPROC4_LOCK_MSG] = {
+ .pc_func = nlm4svc_proc_lock_msg,
+ .pc_decode = nlm4_svc_decode_nlm4_lockargs,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "LOCK_MSG",
},
[NLMPROC_CANCEL_MSG] = {
.pc_func = nlm4svc_proc_cancel_msg,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 24/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_MSG procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (22 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 23/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK_MSG procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 25/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_MSG procedure Chuck Lever
` (18 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The CANCEL_MSG procedure is part of NLM's asynchronous lock
request flow, where clients send CANCEL_MSG to cancel pending
lock requests. This patch continues the xdrgen migration by
converting CANCEL_MSG to use generated XDR functions.
This patch converts the CANCEL_MSG procedure to use xdrgen
functions nlm4_svc_decode_nlm4_cancargs and
nlm4_svc_encode_void generated from the NLM version 4 protocol
specification. The procedure handler uses xdrgen types through
the nlm4_cancargs_wrapper structure that bridges between
generated code and the legacy nlm_lock representation.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments in the argp->xdrgen field,
making the early defensive memset unnecessary. Remaining argp
fields are cleared as needed.
The NLM async callback mechanism uses client-side functions
which continue to take legacy results like struct nlm_res,
preventing CANCEL and CANCEL_MSG from sharing code for now.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 111 +++++++++++++++++++++++++-------------------
1 file changed, 64 insertions(+), 47 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 7ab458648637..4c983a04e9f1 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -453,37 +453,6 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp)
return nlm4svc_do_lock(rqstp, true);
}
-static __be32
-__nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_res *resp)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
- struct nlm_file *file;
-
- dprintk("lockd: CANCEL called\n");
-
- resp->cookie = argp->cookie;
-
- /* Don't accept requests during grace period */
- if (locks_in_grace(SVC_NET(rqstp))) {
- resp->status = nlm_lck_denied_grace_period;
- return rpc_success;
- }
-
- /* Obtain client and file */
- if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
-
- /* Try to cancel request. */
- resp->status = nlmsvc_cancel_blocked(SVC_NET(rqstp), file, &argp->lock);
-
- dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
- nlmsvc_release_lockowner(&argp->lock);
- nlmsvc_release_host(host);
- nlm_release_file(file);
- return rpc_success;
-}
-
/**
* nlm4svc_proc_cancel - CANCEL: Cancel an outstanding blocked lock request
* @rqstp: RPC transaction context
@@ -863,19 +832,67 @@ static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
__nlm4svc_proc_lock_msg);
}
+static __be32
+__nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
+{
+ struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
+ unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
+ struct net *net = SVC_NET(rqstp);
+ struct nlm_file *file = NULL;
+ struct nlm_host *host = NULL;
+
+ resp->status = nlm_lck_denied_nolocks;
+ if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
+ goto out;
+
+ resp->status = nlm_lck_denied_grace_period;
+ if (locks_in_grace(net))
+ goto out;
+
+ resp->status = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
+ if (!host)
+ goto out;
+
+ resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock, type);
+ if (resp->status)
+ goto out;
+
+ resp->status = nlmsvc_cancel_blocked(net, file, &argp->lock);
+ nlmsvc_release_lockowner(&argp->lock);
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->status == nlm_drop_reply ? rpc_drop_reply : rpc_success;
+}
+
+/**
+ * nlm4svc_proc_cancel_msg - CANCEL_MSG: Cancel an outstanding lock request
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_system_err: RPC execution failed.
+ *
+ * RPC synopsis:
+ * void NLMPROC4_CANCEL_MSG(nlm4_cancargs) = 8;
+ *
+ * The response to this request is delivered via the CANCEL_RES procedure.
+ */
static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
+ struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm_host *host;
- dprintk("lockd: CANCEL_MSG called\n");
-
- host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
if (!host)
return rpc_system_err;
- return nlm4svc_callback(rqstp, host, NLMPROC_CANCEL_RES,
- __nlm4svc_proc_cancel);
+ return nlm4svc_callback(rqstp, host, NLMPROC4_CANCEL_RES,
+ __nlm4svc_proc_cancel_msg);
}
static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
@@ -1147,15 +1164,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "LOCK_MSG",
},
- [NLMPROC_CANCEL_MSG] = {
- .pc_func = nlm4svc_proc_cancel_msg,
- .pc_decode = nlm4svc_decode_cancargs,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "CANCEL_MSG",
+ [NLMPROC4_CANCEL_MSG] = {
+ .pc_func = nlm4svc_proc_cancel_msg,
+ .pc_decode = nlm4_svc_decode_nlm4_cancargs,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_cancargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "CANCEL_MSG",
},
[NLMPROC_UNLOCK_MSG] = {
.pc_func = nlm4svc_proc_unlock_msg,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 25/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_MSG procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (23 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 24/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_MSG procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 26/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_MSG procedure Chuck Lever
` (17 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Convert the UNLOCK_MSG procedure to use xdrgen functions
nlm4_svc_decode_nlm4_unlockargs and nlm4_svc_encode_void.
The procedure handler uses the nlm4_unlockargs_wrapper
structure that bridges between xdrgen types and the legacy
nlm_lock representation.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments, making the early
defensive memset unnecessary.
The NLM async callback mechanism uses client-side functions
which continue to take legacy struct nlm_res, preventing
UNLOCK and UNLOCK_MSG from sharing code for now.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 113 ++++++++++++++++++++++++--------------------
1 file changed, 63 insertions(+), 50 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 4c983a04e9f1..dafc1ea70cd7 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -517,40 +517,6 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp)
rpc_drop_reply : rpc_success;
}
-/*
- * UNLOCK: release a lock
- */
-static __be32
-__nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_res *resp)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
- struct nlm_file *file;
-
- dprintk("lockd: UNLOCK called\n");
-
- resp->cookie = argp->cookie;
-
- /* Don't accept new lock requests during grace period */
- if (locks_in_grace(SVC_NET(rqstp))) {
- resp->status = nlm_lck_denied_grace_period;
- return rpc_success;
- }
-
- /* Obtain client and file */
- if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
-
- /* Now try to remove the lock */
- resp->status = nlmsvc_unlock(SVC_NET(rqstp), file, &argp->lock);
-
- dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
- nlmsvc_release_lockowner(&argp->lock);
- nlmsvc_release_host(host);
- nlm_release_file(file);
- return rpc_success;
-}
-
/**
* nlm4svc_proc_unlock - UNLOCK: Remove a lock
* @rqstp: RPC transaction context
@@ -895,19 +861,66 @@ static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
__nlm4svc_proc_cancel_msg);
}
+static __be32
+__nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
+{
+ struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
+ struct net *net = SVC_NET(rqstp);
+ struct nlm_file *file = NULL;
+ struct nlm_host *host = NULL;
+
+ resp->status = nlm_lck_denied_nolocks;
+ if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
+ goto out;
+
+ resp->status = nlm_lck_denied_grace_period;
+ if (locks_in_grace(net))
+ goto out;
+
+ resp->status = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
+ if (!host)
+ goto out;
+
+ resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock, F_UNLCK);
+ if (resp->status)
+ goto out;
+
+ resp->status = nlmsvc_unlock(net, file, &argp->lock);
+ nlmsvc_release_lockowner(&argp->lock);
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->status == nlm_drop_reply ? rpc_drop_reply : rpc_success;
+}
+
+/**
+ * nlm4svc_proc_unlock_msg - UNLOCK_MSG: Remove an existing lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_system_err: RPC execution failed.
+ *
+ * RPC synopsis:
+ * void NLMPROC4_UNLOCK_MSG(nlm4_unlockargs) = 9;
+ *
+ * The response to this request is delivered via the UNLOCK_RES procedure.
+ */
static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
+ struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm_host *host;
- dprintk("lockd: UNLOCK_MSG called\n");
-
- host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
if (!host)
return rpc_system_err;
- return nlm4svc_callback(rqstp, host, NLMPROC_UNLOCK_RES,
- __nlm4svc_proc_unlock);
+ return nlm4svc_callback(rqstp, host, NLMPROC4_UNLOCK_RES,
+ __nlm4svc_proc_unlock_msg);
}
static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
@@ -1174,15 +1187,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "CANCEL_MSG",
},
- [NLMPROC_UNLOCK_MSG] = {
- .pc_func = nlm4svc_proc_unlock_msg,
- .pc_decode = nlm4svc_decode_unlockargs,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "UNLOCK_MSG",
+ [NLMPROC4_UNLOCK_MSG] = {
+ .pc_func = nlm4svc_proc_unlock_msg,
+ .pc_decode = nlm4_svc_decode_nlm4_unlockargs,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_unlockargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "UNLOCK_MSG",
},
[NLMPROC_GRANTED_MSG] = {
.pc_func = nlm4svc_proc_granted_msg,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 26/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_MSG procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (24 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 25/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_MSG procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 27/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST_RES procedure Chuck Lever
` (16 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Convert the GRANTED_MSG procedure to use xdrgen functions
nlm4_svc_decode_nlm4_testargs and nlm4_svc_encode_void.
The procedure handler uses the nlm4_testargs_wrapper
structure that bridges between xdrgen types and the legacy
nlm_lock representation.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments, making the early
defensive memset unnecessary.
The NLM async callback mechanism uses client-side functions
which continue to take legacy struct nlm_res, preventing
GRANTED and GRANTED_MSG from sharing code for now.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 78 ++++++++++++++++++++++++++-------------------
1 file changed, 45 insertions(+), 33 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index dafc1ea70cd7..171ee5ff2289 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -579,23 +579,6 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp)
rpc_drop_reply : rpc_success;
}
-/*
- * GRANTED: A server calls us to tell that a process' lock request
- * was granted
- */
-static __be32
-__nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_res *resp)
-{
- struct nlm_args *argp = rqstp->rq_argp;
-
- resp->cookie = argp->cookie;
-
- dprintk("lockd: GRANTED called\n");
- resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
- dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
- return rpc_success;
-}
-
/**
* nlm4svc_proc_granted - GRANTED: Server grants a previously blocked lock
* @rqstp: RPC transaction context
@@ -923,19 +906,48 @@ static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
__nlm4svc_proc_unlock_msg);
}
+static __be32
+__nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
+{
+ struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
+
+ resp->status = nlm_lck_denied;
+ if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
+ goto out;
+
+ if (nlm4_lock_to_nlm_lock(&argp->lock, &argp->xdrgen.alock))
+ goto out;
+
+ resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
+
+out:
+ return rpc_success;
+}
+
+/**
+ * nlm4svc_proc_granted_msg - GRANTED_MSG: Blocked lock has been granted
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_system_err: RPC execution failed.
+ *
+ * RPC synopsis:
+ * void NLMPROC4_GRANTED_MSG(nlm4_testargs) = 10;
+ *
+ * The response to this request is delivered via the GRANTED_RES procedure.
+ */
static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
+ struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm_host *host;
- dprintk("lockd: GRANTED_MSG called\n");
-
- host = nlmsvc_lookup_host(rqstp, argp->lock.caller, argp->lock.len);
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
if (!host)
return rpc_system_err;
- return nlm4svc_callback(rqstp, host, NLMPROC_GRANTED_RES,
- __nlm4svc_proc_granted);
+ return nlm4svc_callback(rqstp, host, NLMPROC4_GRANTED_RES,
+ __nlm4svc_proc_granted_msg);
}
/*
@@ -1197,15 +1209,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "UNLOCK_MSG",
},
- [NLMPROC_GRANTED_MSG] = {
- .pc_func = nlm4svc_proc_granted_msg,
- .pc_decode = nlm4svc_decode_testargs,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "GRANTED_MSG",
+ [NLMPROC4_GRANTED_MSG] = {
+ .pc_func = nlm4svc_proc_granted_msg,
+ .pc_decode = nlm4_svc_decode_nlm4_testargs,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "GRANTED_MSG",
},
[NLMPROC_TEST_RES] = {
.pc_func = nlm4svc_proc_null,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 27/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST_RES procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (25 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 26/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_MSG procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 28/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK_RES procedure Chuck Lever
` (15 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Convert the TEST_RES procedure to use xdrgen functions
nlm4_svc_decode_nlm4_testres and nlm4_svc_encode_void.
TEST_RES is a callback procedure where the client sends
test lock results back to the server after an async TEST
request.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments, making the early
defensive memset unnecessary.
This change also corrects the pc_xdrressize field, which
previously contained a placeholder value.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 171ee5ff2289..60c5082cd447 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1219,15 +1219,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "GRANTED_MSG",
},
- [NLMPROC_TEST_RES] = {
- .pc_func = nlm4svc_proc_null,
- .pc_decode = nlm4svc_decode_void,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_res),
- .pc_argzero = sizeof(struct nlm_res),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "TEST_RES",
+ [NLMPROC4_TEST_RES] = {
+ .pc_func = nlm4svc_proc_null,
+ .pc_decode = nlm4_svc_decode_nlm4_testres,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_testres),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "TEST_RES",
},
[NLMPROC_LOCK_RES] = {
.pc_func = nlm4svc_proc_null,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 28/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK_RES procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (26 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 27/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST_RES procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 29/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_RES procedure Chuck Lever
` (14 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Convert the LOCK_RES procedure to use xdrgen functions
nlm4_svc_decode_nlm4_res and nlm4_svc_encode_void.
LOCK_RES is a callback procedure where the client sends
lock results back to the server after an async LOCK
request.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments, making the early
defensive memset unnecessary.
This change also corrects the pc_xdrressize field, which
previously contained a placeholder value.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 60c5082cd447..fce3defd1cb3 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1229,15 +1229,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "TEST_RES",
},
- [NLMPROC_LOCK_RES] = {
- .pc_func = nlm4svc_proc_null,
- .pc_decode = nlm4svc_decode_void,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_res),
- .pc_argzero = sizeof(struct nlm_res),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "LOCK_RES",
+ [NLMPROC4_LOCK_RES] = {
+ .pc_func = nlm4svc_proc_null,
+ .pc_decode = nlm4_svc_decode_nlm4_res,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_res),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "LOCK_RES",
},
[NLMPROC_CANCEL_RES] = {
.pc_func = nlm4svc_proc_null,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 29/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_RES procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (27 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 28/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK_RES procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 30/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_RES procedure Chuck Lever
` (13 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Convert the CANCEL_RES procedure to use xdrgen functions
nlm4_svc_decode_nlm4_res and nlm4_svc_encode_void.
CANCEL_RES is a callback procedure where the client sends
cancel results back to the server after an async CANCEL
request.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments, making the early
defensive memset unnecessary.
This change also corrects the pc_xdrressize field, which
previously contained a placeholder value.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index fce3defd1cb3..d4b624e1e318 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1239,15 +1239,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "LOCK_RES",
},
- [NLMPROC_CANCEL_RES] = {
- .pc_func = nlm4svc_proc_null,
- .pc_decode = nlm4svc_decode_void,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_res),
- .pc_argzero = sizeof(struct nlm_res),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "CANCEL_RES",
+ [NLMPROC4_CANCEL_RES] = {
+ .pc_func = nlm4svc_proc_null,
+ .pc_decode = nlm4_svc_decode_nlm4_res,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_res),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "CANCEL_RES",
},
[NLMPROC_UNLOCK_RES] = {
.pc_func = nlm4svc_proc_null,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 30/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_RES procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (28 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 29/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_RES procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 31/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_RES procedure Chuck Lever
` (12 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Update the NLMPROC4_UNLOCK_RES entry in nlm_procedures4 to invoke
xdrgen-generated XDR functions.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index d4b624e1e318..d7f4079d56f3 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1249,15 +1249,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "CANCEL_RES",
},
- [NLMPROC_UNLOCK_RES] = {
- .pc_func = nlm4svc_proc_null,
- .pc_decode = nlm4svc_decode_void,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_res),
- .pc_argzero = sizeof(struct nlm_res),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "UNLOCK_RES",
+ [NLMPROC4_UNLOCK_RES] = {
+ .pc_func = nlm4svc_proc_null,
+ .pc_decode = nlm4_svc_decode_nlm4_res,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_res),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "UNLOCK_RES",
},
[NLMPROC_GRANTED_RES] = {
.pc_func = nlm4svc_proc_granted_res,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 31/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_RES procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (29 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 30/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_RES procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 32/42] lockd: Use xdrgen XDR functions for the NLMv4 SM_NOTIFY procedure Chuck Lever
` (11 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Convert the GRANTED_RES procedure to use xdrgen functions
nlm4_svc_decode_nlm4_res and nlm4_svc_encode_void.
GRANTED_RES is a callback procedure where the client sends
granted lock results back to the server after an async
GRANTED request.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments, making the early
defensive memset unnecessary.
This change also corrects the pc_xdrressize field, which
previously contained a placeholder value.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 60 +++++++++++++++++++++++++--------------------
1 file changed, 34 insertions(+), 26 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index d7f4079d56f3..59d818bf1523 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -71,6 +71,7 @@ static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0);
struct nlm4_res_wrapper {
struct nlm4_res xdrgen;
+ struct nlm_cookie cookie;
};
static_assert(offsetof(struct nlm4_res_wrapper, xdrgen) == 0);
@@ -950,6 +951,30 @@ static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
__nlm4svc_proc_granted_msg);
}
+/**
+ * nlm4svc_proc_granted_res - GRANTED_RES: Lock Granted result
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ *
+ * RPC synopsis:
+ * void NLMPROC4_GRANTED_RES(nlm4_res) = 15;
+ */
+static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
+{
+ struct nlm4_res_wrapper *argp = rqstp->rq_argp;
+
+ if (!nlmsvc_ops)
+ return rpc_success;
+
+ if (nlm4_netobj_to_cookie(&argp->cookie, &argp->xdrgen.cookie))
+ return rpc_success;
+ nlmsvc_grant_reply(&argp->cookie, argp->xdrgen.stat.stat);
+
+ return rpc_success;
+}
+
/*
* SHARE: create a DOS share or alter existing share.
*/
@@ -1073,23 +1098,6 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * client sent a GRANTED_RES, let's remove the associated block
- */
-static __be32
-nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
-{
- struct nlm_res *argp = rqstp->rq_argp;
-
- if (!nlmsvc_ops)
- return rpc_success;
-
- dprintk("lockd: GRANTED_RES called\n");
-
- nlmsvc_grant_reply(&argp->cookie, argp->status);
- return rpc_success;
-}
-
static __be32
nlm4svc_proc_unused(struct svc_rqst *rqstp)
{
@@ -1259,15 +1267,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "UNLOCK_RES",
},
- [NLMPROC_GRANTED_RES] = {
- .pc_func = nlm4svc_proc_granted_res,
- .pc_decode = nlm4svc_decode_res,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_res),
- .pc_argzero = sizeof(struct nlm_res),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "GRANTED_RES",
+ [NLMPROC4_GRANTED_RES] = {
+ .pc_func = nlm4svc_proc_granted_res,
+ .pc_decode = nlm4_svc_decode_nlm4_res,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_res_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "GRANTED_RES",
},
[NLMPROC_NSM_NOTIFY] = {
.pc_func = nlm4svc_proc_sm_notify,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 32/42] lockd: Use xdrgen XDR functions for the NLMv4 SM_NOTIFY procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (30 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 31/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_RES procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 33/42] lockd: Convert server-side undefined procedures to xdrgen Chuck Lever
` (10 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Convert the SM_NOTIFY procedure to use xdrgen functions
nlm4_svc_decode_nlm4_notifyargs and nlm4_svc_encode_void.
SM_NOTIFY is a private callback from statd to notify lockd
when a remote host has rebooted.
This patch introduces struct nlm4_notifyargs_wrapper to
bridge between the xdrgen-generated nlm4_notifyargs and
the nlm_reboot structure expected by nlm_host_rebooted().
The wrapper contains both the xdrgen-decoded arguments
and a reboot field for the existing API.
The pc_argzero field is set to zero because xdrgen decoders
reliably initialize all arguments, making the early
defensive memset unnecessary.
This change also corrects the pc_xdrressize field, which
previously contained a placeholder value.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 86 +++++++++++++++++++++++++++++----------------
1 file changed, 55 insertions(+), 31 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 59d818bf1523..7e936bd00a50 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -62,6 +62,13 @@ struct nlm4_unlockargs_wrapper {
static_assert(offsetof(struct nlm4_unlockargs_wrapper, xdrgen) == 0);
+struct nlm4_notifyargs_wrapper {
+ struct nlm4_notifyargs xdrgen;
+ struct nlm_reboot reboot;
+};
+
+static_assert(offsetof(struct nlm4_notifyargs_wrapper, xdrgen) == 0);
+
struct nlm4_testres_wrapper {
struct nlm4_testres xdrgen;
struct nlm_lock lock;
@@ -975,6 +982,44 @@ static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
return rpc_success;
}
+/**
+ * nlm4svc_proc_sm_notify - SM_NOTIFY: Peer has rebooted
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_system_err: RPC execution failed.
+ *
+ * The SM_NOTIFY procedure is a private callback from Linux statd and is
+ * not part of the official NLM protocol.
+ *
+ * RPC synopsis:
+ * void NLMPROC4_SM_NOTIFY(nlm4_notifyargs) = 16;
+ */
+static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
+{
+ struct nlm4_notifyargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm_reboot *reboot = &argp->reboot;
+
+ if (!nlm_privileged_requester(rqstp)) {
+ char buf[RPC_MAX_ADDRBUFLEN];
+
+ pr_warn("lockd: rejected NSM callback from %s\n",
+ svc_print_addr(rqstp, buf, sizeof(buf)));
+ return rpc_system_err;
+ }
+
+ reboot->len = argp->xdrgen.notify.name.len;
+ reboot->mon = (char *)argp->xdrgen.notify.name.data;
+ reboot->state = argp->xdrgen.notify.state;
+ memcpy(&reboot->priv.data, argp->xdrgen.private,
+ sizeof(reboot->priv.data));
+
+ nlm_host_rebooted(SVC_NET(rqstp), reboot);
+
+ return rpc_success;
+}
+
/*
* SHARE: create a DOS share or alter existing share.
*/
@@ -1077,27 +1122,6 @@ nlm4svc_proc_free_all(struct svc_rqst *rqstp)
return rpc_success;
}
-/*
- * SM_NOTIFY: private callback from statd (not part of official NLM proto)
- */
-static __be32
-nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
-{
- struct nlm_reboot *argp = rqstp->rq_argp;
-
- dprintk("lockd: SM_NOTIFY called\n");
-
- if (!nlm_privileged_requester(rqstp)) {
- char buf[RPC_MAX_ADDRBUFLEN];
- printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
- svc_print_addr(rqstp, buf, sizeof(buf)));
- return rpc_system_err;
- }
-
- nlm_host_rebooted(SVC_NET(rqstp), argp);
- return rpc_success;
-}
-
static __be32
nlm4svc_proc_unused(struct svc_rqst *rqstp)
{
@@ -1277,15 +1301,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "GRANTED_RES",
},
- [NLMPROC_NSM_NOTIFY] = {
- .pc_func = nlm4svc_proc_sm_notify,
- .pc_decode = nlm4svc_decode_reboot,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_reboot),
- .pc_argzero = sizeof(struct nlm_reboot),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "SM_NOTIFY",
+ [NLMPROC4_SM_NOTIFY] = {
+ .pc_func = nlm4svc_proc_sm_notify,
+ .pc_decode = nlm4_svc_decode_nlm4_notifyargs,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_notifyargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "SM_NOTIFY",
},
[17] = {
.pc_func = nlm4svc_proc_unused,
@@ -1367,10 +1391,10 @@ union nlm4svc_xdrstore {
struct nlm4_lockargs_wrapper lockargs;
struct nlm4_cancargs_wrapper cancargs;
struct nlm4_unlockargs_wrapper unlockargs;
+ struct nlm4_notifyargs_wrapper notifyargs;
struct nlm4_testres_wrapper testres;
struct nlm4_res_wrapper res;
struct nlm_args args;
- struct nlm_reboot reboot;
};
static DEFINE_PER_CPU_ALIGNED(unsigned long,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 33/42] lockd: Convert server-side undefined procedures to xdrgen
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (31 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 32/42] lockd: Use xdrgen XDR functions for the NLMv4 SM_NOTIFY procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 34/42] lockd: Hoist file_lock init out of nlm4svc_decode_shareargs() Chuck Lever
` (9 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The NLMv4 protocol defines several procedure slots that are
not implemented. These undefined procedures need proper
handling to return rpc_proc_unavail to clients that
mistakenly invoke them.
This patch converts the three undefined procedure entries
(slots 17, 18, and 19) to use xdrgen functions
nlm4_svc_decode_void and nlm4_svc_encode_void. The
nlm4svc_proc_unused function is also moved earlier in the
file to follow the convention of placing procedure
implementations before the procedure table.
The pc_argsize, pc_ressize, and pc_argzero fields are now
correctly set to zero since no arguments or results are
processed. The pc_xdrressize field is updated to XDR_void
to accurately reflect the response size.
This conversion completes the migration of all NLMv4
server-side procedures to use xdrgen-generated XDR
functions, improving type safety and eliminating
hand-written XDR code.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 66 ++++++++++++++++++++++++---------------------
1 file changed, 36 insertions(+), 30 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 7e936bd00a50..d8a5f662ab39 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1020,6 +1020,18 @@ static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
return rpc_success;
}
+/**
+ * nlm4svc_proc_unused - stub for unused procedures
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_proc_unavail: Program can't support procedure.
+ */
+static __be32 nlm4svc_proc_unused(struct svc_rqst *rqstp)
+{
+ return rpc_proc_unavail;
+}
+
/*
* SHARE: create a DOS share or alter existing share.
*/
@@ -1122,12 +1134,6 @@ nlm4svc_proc_free_all(struct svc_rqst *rqstp)
return rpc_success;
}
-static __be32
-nlm4svc_proc_unused(struct svc_rqst *rqstp)
-{
- return rpc_proc_unavail;
-}
-
/*
* NLM Server procedures.
@@ -1312,34 +1318,34 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_name = "SM_NOTIFY",
},
[17] = {
- .pc_func = nlm4svc_proc_unused,
- .pc_decode = nlm4svc_decode_void,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_void),
- .pc_argzero = sizeof(struct nlm_void),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = 0,
- .pc_name = "UNUSED",
+ .pc_func = nlm4svc_proc_unused,
+ .pc_decode = nlm4_svc_decode_void,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = 0,
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "UNUSED",
},
[18] = {
- .pc_func = nlm4svc_proc_unused,
- .pc_decode = nlm4svc_decode_void,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_void),
- .pc_argzero = sizeof(struct nlm_void),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = 0,
- .pc_name = "UNUSED",
+ .pc_func = nlm4svc_proc_unused,
+ .pc_decode = nlm4_svc_decode_void,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = 0,
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "UNUSED",
},
[19] = {
- .pc_func = nlm4svc_proc_unused,
- .pc_decode = nlm4svc_decode_void,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_void),
- .pc_argzero = sizeof(struct nlm_void),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = 0,
- .pc_name = "UNUSED",
+ .pc_func = nlm4svc_proc_unused,
+ .pc_decode = nlm4_svc_decode_void,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = 0,
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "UNUSED",
},
[NLMPROC_SHARE] = {
.pc_func = nlm4svc_proc_share,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 34/42] lockd: Hoist file_lock init out of nlm4svc_decode_shareargs()
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (32 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 33/42] lockd: Convert server-side undefined procedures to xdrgen Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 35/42] lockd: Prepare share helpers for xdrgen conversion Chuck Lever
` (8 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The xdrgen-generated XDR decoders cannot initialize the
file_lock structure because it is an internal kernel type,
not part of the wire protocol. To prepare for converting
SHARE and UNSHARE procedures to use xdrgen, the file_lock
initialization must be moved from nlm4svc_decode_shareargs()
into the procedure handlers themselves.
This change removes one more dependency on the "struct
nlm_lock::fl" field in fs/lockd/xdr4.c, allowing the XDR
decoder to focus solely on unmarshalling wire data.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 16 ++++++++++++----
fs/lockd/xdr4.c | 3 ---
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index d8a5f662ab39..4667e4a1278f 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1040,6 +1040,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp)
{
struct nlm_args *argp = rqstp->rq_argp;
struct nlm_res *resp = rqstp->rq_resp;
+ struct nlm_lock *lock = &argp->lock;
struct nlm_host *host;
struct nlm_file *file;
@@ -1054,14 +1055,17 @@ nlm4svc_proc_share(struct svc_rqst *rqstp)
}
/* Obtain client and file */
- if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+ locks_init_lock(&lock->fl);
+ lock->svid = ~(u32)0;
+ resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file);
+ if (resp->status)
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to create the share */
resp->status = nlmsvc_share_file(host, file, argp);
dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
- nlmsvc_release_lockowner(&argp->lock);
+ nlmsvc_release_lockowner(lock);
nlmsvc_release_host(host);
nlm_release_file(file);
return rpc_success;
@@ -1075,6 +1079,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp)
{
struct nlm_args *argp = rqstp->rq_argp;
struct nlm_res *resp = rqstp->rq_resp;
+ struct nlm_lock *lock = &argp->lock;
struct nlm_host *host;
struct nlm_file *file;
@@ -1089,14 +1094,17 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp)
}
/* Obtain client and file */
- if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+ locks_init_lock(&lock->fl);
+ lock->svid = ~(u32)0;
+ resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file);
+ if (resp->status)
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to lock the file */
resp->status = nlmsvc_unshare_file(host, file, argp);
dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
- nlmsvc_release_lockowner(&argp->lock);
+ nlmsvc_release_lockowner(lock);
nlmsvc_release_host(host);
nlm_release_file(file);
return rpc_success;
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index dbbb2dfcb81b..308aac92a94e 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -257,9 +257,6 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
struct nlm_args *argp = rqstp->rq_argp;
struct nlm_lock *lock = &argp->lock;
- locks_init_lock(&lock->fl);
- lock->svid = ~(u32)0;
-
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
return false;
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 35/42] lockd: Prepare share helpers for xdrgen conversion
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (33 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 34/42] lockd: Hoist file_lock init out of nlm4svc_decode_shareargs() Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 36/42] lockd: Use xdrgen XDR functions for the NLMv4 SHARE procedure Chuck Lever
` (7 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
In order to convert the NLMv4 server-side XDR functions to use
xdrgen, the internal share helpers need to be decoupled from the
NLMv3-specific struct nlm_args. NLMv4 procedures will use
different argument structures once they are converted.
Refactor nlmsvc_share_file() and nlmsvc_unshare_file() to accept
individual arguments (oh, access, mode) instead of the common
struct nlm_args. This allows both protocol versions to call these
helpers without forcing a common argument structure.
While here, add kdoc comments to both functions and fix a comment
typo in the unshare path.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/share.h | 8 ++++----
fs/lockd/svc4proc.c | 7 ++++---
fs/lockd/svcproc.c | 7 +++++--
fs/lockd/svcshare.c | 35 +++++++++++++++++++++++------------
4 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/fs/lockd/share.h b/fs/lockd/share.h
index d8f4ebd9c278..a2867e30c593 100644
--- a/fs/lockd/share.h
+++ b/fs/lockd/share.h
@@ -20,10 +20,10 @@ struct nlm_share {
u32 s_mode; /* deny mode */
};
-__be32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *,
- struct nlm_args *);
-__be32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
- struct nlm_args *);
+__be32 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
+ struct xdr_netobj *oh, u32 access, u32 mode);
+__be32 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
+ struct xdr_netobj *oh);
void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *,
nlm_host_match_fn_t);
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 4667e4a1278f..53a64709dc36 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1062,7 +1062,8 @@ nlm4svc_proc_share(struct svc_rqst *rqstp)
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to create the share */
- resp->status = nlmsvc_share_file(host, file, argp);
+ resp->status = nlmsvc_share_file(host, file, &lock->oh,
+ argp->fsm_access, argp->fsm_mode);
dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
nlmsvc_release_lockowner(lock);
@@ -1100,8 +1101,8 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp)
if (resp->status)
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
- /* Now try to lock the file */
- resp->status = nlmsvc_unshare_file(host, file, argp);
+ /* Now try to unshare the file */
+ resp->status = nlmsvc_unshare_file(host, file, &lock->oh);
dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
nlmsvc_release_lockowner(lock);
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index fe689f76aeae..bf1e8c0dd337 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -413,7 +413,9 @@ nlmsvc_proc_share(struct svc_rqst *rqstp)
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to create the share */
- resp->status = cast_status(nlmsvc_share_file(host, file, argp));
+ resp->status = cast_status(nlmsvc_share_file(host, file, &argp->lock.oh,
+ argp->fsm_access,
+ argp->fsm_mode));
dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
nlmsvc_release_lockowner(&argp->lock);
@@ -448,7 +450,8 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp)
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to unshare the file */
- resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
+ resp->status = cast_status(nlmsvc_unshare_file(host, file,
+ &argp->lock.oh));
dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
nlmsvc_release_lockowner(&argp->lock);
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 8675ac80ab16..53f5655c128c 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -25,12 +25,21 @@ nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh)
&& !memcmp(share->s_owner.data, oh->data, oh->len);
}
+/**
+ * nlmsvc_share_file - create a share
+ * @host: Network client peer
+ * @file: File to be shared
+ * @oh: Share owner handle
+ * @access: Requested access mode
+ * @mode: Requested file sharing mode
+ *
+ * Returns an NLM status code.
+ */
__be32
nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
- struct nlm_args *argp)
+ struct xdr_netobj *oh, u32 access, u32 mode)
{
struct nlm_share *share;
- struct xdr_netobj *oh = &argp->lock.oh;
u8 *ohdata;
if (nlmsvc_file_cannot_lock(file))
@@ -39,13 +48,11 @@ nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
for (share = file->f_shares; share; share = share->s_next) {
if (share->s_host == host && nlm_cmp_owner(share, oh))
goto update;
- if ((argp->fsm_access & share->s_mode)
- || (argp->fsm_mode & share->s_access ))
+ if ((access & share->s_mode) || (mode & share->s_access))
return nlm_lck_denied;
}
- share = kmalloc(sizeof(*share) + oh->len,
- GFP_KERNEL);
+ share = kmalloc(sizeof(*share) + oh->len, GFP_KERNEL);
if (share == NULL)
return nlm_lck_denied_nolocks;
@@ -61,20 +68,24 @@ nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
file->f_shares = share;
update:
- share->s_access = argp->fsm_access;
- share->s_mode = argp->fsm_mode;
+ share->s_access = access;
+ share->s_mode = mode;
return nlm_granted;
}
-/*
- * Delete a share.
+/**
+ * nlmsvc_unshare_file - delete a share
+ * @host: Network client peer
+ * @file: File to be unshared
+ * @oh: Share owner handle
+ *
+ * Returns an NLM status code.
*/
__be32
nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
- struct nlm_args *argp)
+ struct xdr_netobj *oh)
{
struct nlm_share *share, **shpp;
- struct xdr_netobj *oh = &argp->lock.oh;
if (nlmsvc_file_cannot_lock(file))
return nlm_lck_denied_nolocks;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 36/42] lockd: Use xdrgen XDR functions for the NLMv4 SHARE procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (34 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 35/42] lockd: Prepare share helpers for xdrgen conversion Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 37/42] lockd: Use xdrgen XDR functions for the NLMv4 UNSHARE procedure Chuck Lever
` (6 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Now that the share helpers have been decoupled from the
NLMv3-specific struct nlm_args and file_lock initialization
has been hoisted into the procedure handler, the NLMv4 SHARE
procedure can be converted to use xdrgen-generated XDR
functions.
Replace the NLMPROC4_SHARE entry in the nlm_procedures4 array
with an entry that uses xdrgen-built XDR decoders and encoders.
The procedure handler is updated to use the new wrapper
structures (nlm4_shareargs_wrapper and nlm4_shareres_wrapper)
and access arguments through the argp->xdrgen hierarchy.
The .pc_argzero field is set to zero because xdrgen decoders
fully initialize all fields in argp->xdrgen, making the early
defensive memset unnecessary. The remaining argp fields that
fall outside the xdrgen structures are cleared explicitly as
needed.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 117 ++++++++++++++++++++++++++++++--------------
1 file changed, 81 insertions(+), 36 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 53a64709dc36..74a8821e2bce 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -74,6 +74,13 @@ struct nlm4_testres_wrapper {
struct nlm_lock lock;
};
+struct nlm4_shareargs_wrapper {
+ struct nlm4_shareargs xdrgen;
+ struct nlm_lock lock;
+};
+
+static_assert(offsetof(struct nlm4_shareargs_wrapper, xdrgen) == 0);
+
static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0);
struct nlm4_res_wrapper {
@@ -83,6 +90,12 @@ struct nlm4_res_wrapper {
static_assert(offsetof(struct nlm4_res_wrapper, xdrgen) == 0);
+struct nlm4_shareres_wrapper {
+ struct nlm4_shareres xdrgen;
+};
+
+static_assert(offsetof(struct nlm4_shareres_wrapper, xdrgen) == 0);
+
static __be32
nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object)
{
@@ -1032,44 +1045,74 @@ static __be32 nlm4svc_proc_unused(struct svc_rqst *rqstp)
return rpc_proc_unavail;
}
-/*
- * SHARE: create a DOS share or alter existing share.
+/**
+ * nlm4svc_proc_share - SHARE: Open a file using DOS file-sharing modes
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_drop_reply: Do not send an RPC reply.
+ *
+ * RPC synopsis:
+ * nlm4_shareres NLMPROC4_SHARE(nlm4_shareargs) = 20;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_GRANTED: The requested share lock was granted.
+ * %NLM4_DENIED: The requested lock conflicted with existing
+ * lock reservations for the file.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ *
+ * The Linux NLM server implementation also returns:
+ * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
+ * %NLM4_STALE_FH: The request specified an invalid file handle.
+ * %NLM4_FBIG: The request specified a length or offset
+ * that exceeds the range supported by the
+ * server.
+ * %NLM4_FAILED: The request failed for an unspecified reason.
*/
-static __be32
-nlm4svc_proc_share(struct svc_rqst *rqstp)
+static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_res *resp = rqstp->rq_resp;
+ struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm4_shareres_wrapper *resp = rqstp->rq_resp;
struct nlm_lock *lock = &argp->lock;
- struct nlm_host *host;
- struct nlm_file *file;
+ struct nlm_host *host = NULL;
+ struct nlm_file *file = NULL;
+ struct nlm4_lock xdr_lock = {
+ .fh = argp->xdrgen.share.fh,
+ .oh = argp->xdrgen.share.oh,
+ .svid = ~(u32)0,
+ };
- dprintk("lockd: SHARE called\n");
+ resp->xdrgen.cookie = argp->xdrgen.cookie;
- resp->cookie = argp->cookie;
+ resp->xdrgen.stat = nlm_lck_denied_grace_period;
+ if (locks_in_grace(SVC_NET(rqstp)) && !argp->xdrgen.reclaim)
+ goto out;
- /* Don't accept new lock requests during grace period */
- if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
- resp->status = nlm_lck_denied_grace_period;
- return rpc_success;
- }
+ resp->xdrgen.stat = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, true);
+ if (!host)
+ goto out;
- /* Obtain client and file */
- locks_init_lock(&lock->fl);
- lock->svid = ~(u32)0;
- resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file);
- if (resp->status)
- return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+ resp->xdrgen.stat = nlm4svc_lookup_file(rqstp, host, lock, &file,
+ &xdr_lock, F_RDLCK);
+ if (resp->xdrgen.stat)
+ goto out;
- /* Now try to create the share */
- resp->status = nlmsvc_share_file(host, file, &lock->oh,
- argp->fsm_access, argp->fsm_mode);
+ resp->xdrgen.stat = nlmsvc_share_file(host, file, &lock->oh,
+ argp->xdrgen.share.access,
+ argp->xdrgen.share.mode);
- dprintk("lockd: SHARE status %d\n", ntohl(resp->status));
nlmsvc_release_lockowner(lock);
+
+out:
+ if (file)
+ nlm_release_file(file);
nlmsvc_release_host(host);
- nlm_release_file(file);
- return rpc_success;
+ return resp->xdrgen.stat == nlm_drop_reply ?
+ rpc_drop_reply : rpc_success;
}
/*
@@ -1356,15 +1399,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = XDR_void,
.pc_name = "UNUSED",
},
- [NLMPROC_SHARE] = {
- .pc_func = nlm4svc_proc_share,
- .pc_decode = nlm4svc_decode_shareargs,
- .pc_encode = nlm4svc_encode_shareres,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St+1,
- .pc_name = "SHARE",
+ [NLMPROC4_SHARE] = {
+ .pc_func = nlm4svc_proc_share,
+ .pc_decode = nlm4_svc_decode_nlm4_shareargs,
+ .pc_encode = nlm4_svc_encode_nlm4_shareres,
+ .pc_argsize = sizeof(struct nlm4_shareargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_shareres_wrapper),
+ .pc_xdrressize = NLM4_nlm4_shareres_sz,
+ .pc_name = "SHARE",
},
[NLMPROC_UNSHARE] = {
.pc_func = nlm4svc_proc_unshare,
@@ -1407,8 +1450,10 @@ union nlm4svc_xdrstore {
struct nlm4_cancargs_wrapper cancargs;
struct nlm4_unlockargs_wrapper unlockargs;
struct nlm4_notifyargs_wrapper notifyargs;
+ struct nlm4_shareargs_wrapper shareargs;
struct nlm4_testres_wrapper testres;
struct nlm4_res_wrapper res;
+ struct nlm4_shareres_wrapper shareres;
struct nlm_args args;
};
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 37/42] lockd: Use xdrgen XDR functions for the NLMv4 UNSHARE procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (35 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 36/42] lockd: Use xdrgen XDR functions for the NLMv4 SHARE procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 38/42] lockd: Use xdrgen XDR functions for the NLMv4 NM_LOCK procedure Chuck Lever
` (5 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Now that the share helpers have been decoupled from the
NLMv3-specific struct nlm_args and file_lock initialization
has been hoisted into the procedure handler, the NLMv4 UNSHARE
procedure can be converted to use xdrgen-generated XDR
functions.
Replace the NLMPROC4_UNSHARE entry in the nlm_procedures4
array with an entry that uses xdrgen-built XDR decoders and
encoders. The procedure handler is updated to use the new
wrapper structures (nlm4_shareargs_wrapper and
nlm4_shareres_wrapper) and access arguments through the
argp->xdrgen hierarchy.
The .pc_argzero field is set to zero because xdrgen decoders
fully initialize all fields in argp->xdrgen, making the early
defensive memset unnecessary. The remaining argp fields that
fall outside the xdrgen structures are cleared explicitly as
needed.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 97 +++++++++++++++++++++++++++++----------------
1 file changed, 62 insertions(+), 35 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 74a8821e2bce..316b4d623130 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -1115,43 +1115,70 @@ static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp)
rpc_drop_reply : rpc_success;
}
-/*
- * UNSHARE: Release a DOS share.
+/**
+ * nlm4svc_proc_unshare - UNSHARE: Release a share reservation
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_drop_reply: Do not send an RPC reply.
+ *
+ * RPC synopsis:
+ * nlm4_shareres NLMPROC4_UNSHARE(nlm4_shareargs) = 21;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_GRANTED: The share reservation was released.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ *
+ * The Linux NLM server implementation also returns:
+ * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated.
+ * %NLM4_STALE_FH: The request specified an invalid file handle.
+ * %NLM4_FBIG: The request specified a length or offset
+ * that exceeds the range supported by the
+ * server.
+ * %NLM4_FAILED: The request failed for an unspecified reason.
*/
-static __be32
-nlm4svc_proc_unshare(struct svc_rqst *rqstp)
+static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_res *resp = rqstp->rq_resp;
+ struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp;
+ struct nlm4_shareres_wrapper *resp = rqstp->rq_resp;
struct nlm_lock *lock = &argp->lock;
- struct nlm_host *host;
- struct nlm_file *file;
+ struct nlm4_lock xdr_lock = {
+ .fh = argp->xdrgen.share.fh,
+ .oh = argp->xdrgen.share.oh,
+ .svid = ~(u32)0,
+ };
+ struct nlm_host *host = NULL;
+ struct nlm_file *file = NULL;
- dprintk("lockd: UNSHARE called\n");
+ resp->xdrgen.cookie = argp->xdrgen.cookie;
- resp->cookie = argp->cookie;
+ resp->xdrgen.stat = nlm_lck_denied_grace_period;
+ if (locks_in_grace(SVC_NET(rqstp)))
+ goto out;
- /* Don't accept requests during grace period */
- if (locks_in_grace(SVC_NET(rqstp))) {
- resp->status = nlm_lck_denied_grace_period;
- return rpc_success;
- }
+ resp->xdrgen.stat = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, true);
+ if (!host)
+ goto out;
- /* Obtain client and file */
- locks_init_lock(&lock->fl);
- lock->svid = ~(u32)0;
- resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file);
- if (resp->status)
- return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
+ resp->xdrgen.stat = nlm4svc_lookup_file(rqstp, host, lock, &file,
+ &xdr_lock, F_RDLCK);
+ if (resp->xdrgen.stat)
+ goto out;
- /* Now try to unshare the file */
- resp->status = nlmsvc_unshare_file(host, file, &lock->oh);
+ resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh);
- dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status));
nlmsvc_release_lockowner(lock);
+
+out:
+ if (file)
+ nlm_release_file(file);
nlmsvc_release_host(host);
- nlm_release_file(file);
- return rpc_success;
+ return resp->xdrgen.stat == nlm_drop_reply ?
+ rpc_drop_reply : rpc_success;
}
/*
@@ -1409,15 +1436,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = NLM4_nlm4_shareres_sz,
.pc_name = "SHARE",
},
- [NLMPROC_UNSHARE] = {
- .pc_func = nlm4svc_proc_unshare,
- .pc_decode = nlm4svc_decode_shareargs,
- .pc_encode = nlm4svc_encode_shareres,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St+1,
- .pc_name = "UNSHARE",
+ [NLMPROC4_UNSHARE] = {
+ .pc_func = nlm4svc_proc_unshare,
+ .pc_decode = nlm4_svc_decode_nlm4_shareargs,
+ .pc_encode = nlm4_svc_encode_nlm4_shareres,
+ .pc_argsize = sizeof(struct nlm4_shareargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_shareres_wrapper),
+ .pc_xdrressize = NLM4_nlm4_shareres_sz,
+ .pc_name = "UNSHARE",
},
[NLMPROC_NM_LOCK] = {
.pc_func = nlm4svc_proc_nm_lock,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 38/42] lockd: Use xdrgen XDR functions for the NLMv4 NM_LOCK procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (36 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 37/42] lockd: Use xdrgen XDR functions for the NLMv4 UNSHARE procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 39/42] lockd: Use xdrgen XDR functions for the NLMv4 FREE_ALL procedure Chuck Lever
` (4 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Now that nlm4svc_do_lock() has been introduced to handle both
monitored and non-monitored lock requests, the NLMv4 NM_LOCK
procedure can be converted to use xdrgen-generated XDR
functions. This conversion allows the removal of
__nlm4svc_proc_lock(), a helper function that was previously
shared between the LOCK and NM_LOCK procedures.
Replace the NLMPROC4_NM_LOCK entry in the nlm_procedures4
array with an entry that uses xdrgen-built XDR decoders and
encoders. The procedure handler is updated to call
nlm4svc_do_lock() directly and access arguments through the
argp->xdrgen hierarchy.
The .pc_argzero field is set to zero because xdrgen decoders
fully initialize all fields in argp->xdrgen, making the early
defensive memset unnecessary. The remaining argp fields that
fall outside the xdrgen structures are cleared explicitly as
needed.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 100 +++++++++++++++++++-------------------------
1 file changed, 44 insertions(+), 56 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 316b4d623130..76d259658604 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -353,43 +353,6 @@ static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp)
rpc_drop_reply : rpc_success;
}
-static __be32
-__nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_host *host;
- struct nlm_file *file;
- __be32 rc = rpc_success;
-
- dprintk("lockd: LOCK called\n");
-
- resp->cookie = argp->cookie;
-
- /* Obtain client and file */
- if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
-
- /* Now try to lock the file */
- resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
- argp->block, &argp->cookie,
- argp->reclaim);
- switch (resp->status) {
- case nlm_drop_reply:
- rc = rpc_drop_reply;
- break;
- case nlm__int__deadlock:
- resp->status = nlm4_deadlock;
- fallthrough;
- default:
- dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
- }
-
- nlmsvc_release_lockowner(&argp->lock);
- nlmsvc_release_host(host);
- nlm_release_file(file);
- return rc;
-}
-
static __be32
nlm4svc_do_lock(struct svc_rqst *rqstp, bool monitored)
{
@@ -1181,18 +1144,43 @@ static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp)
rpc_drop_reply : rpc_success;
}
-/*
- * NM_LOCK: Create an unmonitored lock
+/**
+ * nlm4svc_proc_nm_lock - NM_LOCK: Establish a non-monitored lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_drop_reply: Do not send an RPC reply.
+ *
+ * RPC synopsis:
+ * nlm4_res NLMPROC4_NM_LOCK(nlm4_lockargs) = 22;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_GRANTED: The requested lock was granted.
+ * %NLM4_DENIED: The requested lock conflicted with existing
+ * lock reservations for the file.
+ * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
+ * needed to process the request.
+ * %NLM4_BLOCKED: The blocking request cannot be granted
+ * immediately. The server will send an
+ * NLMPROC4_GRANTED callback to the client when
+ * the lock can be granted.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ *
+ * The Linux NLM server implementation also returns:
+ * %NLM4_DEADLCK: The request could not be granted and
+ * blocking would cause a deadlock.
+ * %NLM4_STALE_FH: The request specified an invalid file handle.
+ * %NLM4_FBIG: The request specified a length or offset
+ * that exceeds the range supported by the
+ * server.
+ * %NLM4_FAILED: The request failed for an unspecified reason.
*/
-static __be32
-nlm4svc_proc_nm_lock(struct svc_rqst *rqstp)
+static __be32 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
-
- dprintk("lockd: NM_LOCK called\n");
-
- argp->monitor = 0; /* just clean the monitor flag */
- return __nlm4svc_proc_lock(rqstp, rqstp->rq_resp);
+ return nlm4svc_do_lock(rqstp, false);
}
/*
@@ -1446,15 +1434,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = NLM4_nlm4_shareres_sz,
.pc_name = "UNSHARE",
},
- [NLMPROC_NM_LOCK] = {
- .pc_func = nlm4svc_proc_nm_lock,
- .pc_decode = nlm4svc_decode_lockargs,
- .pc_encode = nlm4svc_encode_res,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St,
- .pc_name = "NM_LOCK",
+ [NLMPROC4_NM_LOCK] = {
+ .pc_func = nlm4svc_proc_nm_lock,
+ .pc_decode = nlm4_svc_decode_nlm4_lockargs,
+ .pc_encode = nlm4_svc_encode_nlm4_res,
+ .pc_argsize = sizeof(struct nlm4_lockargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_res_wrapper),
+ .pc_xdrressize = NLM4_nlm4_res_sz,
+ .pc_name = "NM_LOCK",
},
[NLMPROC_FREE_ALL] = {
.pc_func = nlm4svc_proc_free_all,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 39/42] lockd: Use xdrgen XDR functions for the NLMv4 FREE_ALL procedure
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (37 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 38/42] lockd: Use xdrgen XDR functions for the NLMv4 NM_LOCK procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 40/42] lockd: Add LOCKD_SHARE_SVID constant for DOS sharing mode Chuck Lever
` (3 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
With all other NLMv4 procedures now converted to xdrgen-generated
XDR functions, the FREE_ALL procedure can be converted as well.
This conversion allows the removal of nlm4svc_retrieve_args(),
a 79-line helper function that was used only by FREE_ALL to
retrieve client information from lockd's internal data
structures.
Replace the NLMPROC4_FREE_ALL entry in the nlm_procedures4
array with an entry that uses xdrgen-built XDR decoders and
encoders. The procedure handler is updated to use the new
wrapper structure (nlm4_notify_wrapper) and call
nlm4svc_lookup_host() directly, eliminating the need for the
now-removed helper function.
The .pc_argzero field is set to zero because xdrgen decoders
fully initialize all fields in argp->xdrgen, making the early
defensive memset unnecessary. The remaining argp fields that
fall outside the xdrgen structures are cleared explicitly as
needed.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 120 ++++++++++++--------------------------------
1 file changed, 33 insertions(+), 87 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 76d259658604..6b1a80084d1a 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -69,6 +69,12 @@ struct nlm4_notifyargs_wrapper {
static_assert(offsetof(struct nlm4_notifyargs_wrapper, xdrgen) == 0);
+struct nlm4_notify_wrapper {
+ struct nlm4_notify xdrgen;
+};
+
+static_assert(offsetof(struct nlm4_notify_wrapper, xdrgen) == 0);
+
struct nlm4_testres_wrapper {
struct nlm4_testres xdrgen;
struct nlm_lock lock;
@@ -191,75 +197,6 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
return nlm_granted;
}
-/*
- * Obtain client and file from arguments
- */
-static __be32
-nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
- struct nlm_host **hostp, struct nlm_file **filp)
-{
- struct nlm_host *host = NULL;
- struct nlm_file *file = NULL;
- struct nlm_lock *lock = &argp->lock;
- __be32 error = 0;
-
- /* nfsd callbacks must have been installed for this procedure */
- if (!nlmsvc_ops)
- return nlm_lck_denied_nolocks;
-
- if (lock->lock_start > OFFSET_MAX ||
- (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start))))
- return nlm4_fbig;
-
- /* Obtain host handle */
- if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
- || (argp->monitor && nsm_monitor(host) < 0))
- goto no_locks;
- *hostp = host;
-
- /* Obtain file pointer. Not used by FREE_ALL call. */
- if (filp != NULL) {
- int mode = lock_to_openmode(&lock->fl);
-
- lock->fl.c.flc_flags = FL_POSIX;
-
- error = nlm_lookup_file(rqstp, &file, lock);
- if (error)
- goto no_locks;
- *filp = file;
-
- /* Set up the missing parts of the file_lock structure */
- lock->fl.c.flc_file = file->f_file[mode];
- lock->fl.c.flc_pid = current->tgid;
- lock->fl.fl_start = (loff_t)lock->lock_start;
- lock->fl.fl_end = lock->lock_len ?
- (loff_t)(lock->lock_start + lock->lock_len - 1) :
- OFFSET_MAX;
- lock->fl.fl_lmops = &nlmsvc_lock_operations;
- nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
- if (!lock->fl.c.flc_owner) {
- /* lockowner allocation has failed */
- nlmsvc_release_host(host);
- return nlm_lck_denied_nolocks;
- }
- }
-
- return 0;
-
-no_locks:
- nlmsvc_release_host(host);
- switch (error) {
- case nlm_granted:
- return nlm_lck_denied_nolocks;
- case nlm__int__stale_fh:
- return nlm4_stale_fh;
- case nlm__int__failed:
- return nlm4_failed;
- default:
- return error;
- }
-}
-
/**
* nlm4svc_proc_null - NULL: Test for presence of service
* @rqstp: RPC transaction context
@@ -1183,21 +1120,30 @@ static __be32 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp)
return nlm4svc_do_lock(rqstp, false);
}
-/*
- * FREE_ALL: Release all locks and shares held by client
+/**
+ * nlm4svc_proc_free_all - FREE_ALL: Discard client's lock and share state
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ *
+ * RPC synopsis:
+ * void NLMPROC4_FREE_ALL(nlm4_notify) = 23;
*/
-static __be32
-nlm4svc_proc_free_all(struct svc_rqst *rqstp)
+static __be32 nlm4svc_proc_free_all(struct svc_rqst *rqstp)
{
- struct nlm_args *argp = rqstp->rq_argp;
+ struct nlm4_notify_wrapper *argp = rqstp->rq_argp;
struct nlm_host *host;
- /* Obtain client */
- if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
- return rpc_success;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.name, false);
+ if (!host)
+ goto out;
nlmsvc_free_host_resources(host);
+
nlmsvc_release_host(host);
+
+out:
return rpc_success;
}
@@ -1444,15 +1390,15 @@ static const struct svc_procedure nlm4svc_procedures[24] = {
.pc_xdrressize = NLM4_nlm4_res_sz,
.pc_name = "NM_LOCK",
},
- [NLMPROC_FREE_ALL] = {
- .pc_func = nlm4svc_proc_free_all,
- .pc_decode = nlm4svc_decode_notify,
- .pc_encode = nlm4svc_encode_void,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_void),
- .pc_xdrressize = St,
- .pc_name = "FREE_ALL",
+ [NLMPROC4_FREE_ALL] = {
+ .pc_func = nlm4svc_proc_free_all,
+ .pc_decode = nlm4_svc_decode_nlm4_notify,
+ .pc_encode = nlm4_svc_encode_void,
+ .pc_argsize = sizeof(struct nlm4_notify_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = 0,
+ .pc_xdrressize = XDR_void,
+ .pc_name = "FREE_ALL",
},
};
@@ -1466,10 +1412,10 @@ union nlm4svc_xdrstore {
struct nlm4_unlockargs_wrapper unlockargs;
struct nlm4_notifyargs_wrapper notifyargs;
struct nlm4_shareargs_wrapper shareargs;
+ struct nlm4_notify_wrapper notify;
struct nlm4_testres_wrapper testres;
struct nlm4_res_wrapper res;
struct nlm4_shareres_wrapper shareres;
- struct nlm_args args;
};
static DEFINE_PER_CPU_ALIGNED(unsigned long,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 40/42] lockd: Add LOCKD_SHARE_SVID constant for DOS sharing mode
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (38 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 39/42] lockd: Use xdrgen XDR functions for the NLMv4 FREE_ALL procedure Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 41/42] lockd: Remove C macros that are no longer used Chuck Lever
` (2 subsequent siblings)
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Replace the magic value ~(u32)0 with a named constant. This value
is used as a synthetic svid when looking up lockowners for DOS
share operations, which have no real process ID associated with
them.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/share.h | 3 +++
fs/lockd/svc4proc.c | 4 ++--
fs/lockd/xdr.c | 3 ++-
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/fs/lockd/share.h b/fs/lockd/share.h
index a2867e30c593..20ea8ee49168 100644
--- a/fs/lockd/share.h
+++ b/fs/lockd/share.h
@@ -8,6 +8,9 @@
#ifndef _LOCKD_SHARE_H
#define _LOCKD_SHARE_H
+/* Synthetic svid for lockowner lookup during share operations */
+#define LOCKD_SHARE_SVID (~(u32)0)
+
/*
* DOS share for a specific file
*/
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 6b1a80084d1a..3c50bd18c45a 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -982,7 +982,7 @@ static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp)
struct nlm4_lock xdr_lock = {
.fh = argp->xdrgen.share.fh,
.oh = argp->xdrgen.share.oh,
- .svid = ~(u32)0,
+ .svid = LOCKD_SHARE_SVID,
};
resp->xdrgen.cookie = argp->xdrgen.cookie;
@@ -1048,7 +1048,7 @@ static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp)
struct nlm4_lock xdr_lock = {
.fh = argp->xdrgen.share.fh,
.oh = argp->xdrgen.share.oh,
- .svid = ~(u32)0,
+ .svid = LOCKD_SHARE_SVID,
};
struct nlm_host *host = NULL;
struct nlm_file *file = NULL;
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 5aac49d1875a..dfca8b8dab73 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -19,6 +19,7 @@
#include <uapi/linux/nfs2.h>
#include "lockd.h"
+#include "share.h"
#include "svcxdr.h"
static inline loff_t
@@ -274,7 +275,7 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
memset(lock, 0, sizeof(*lock));
locks_init_lock(&lock->fl);
- lock->svid = ~(u32)0;
+ lock->svid = LOCKD_SHARE_SVID;
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
return false;
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 41/42] lockd: Remove C macros that are no longer used
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (39 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 40/42] lockd: Add LOCKD_SHARE_SVID constant for DOS sharing mode Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 42/42] lockd: Remove dead code from fs/lockd/xdr4.c Chuck Lever
2026-01-26 12:51 ` [PATCH v2 00/42] Clarify module API boundaries Jeff Layton
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
The conversion of all NLMv4 procedures to xdrgen-generated
XDR functions is complete. The hand-rolled XDR size
calculation macros (Ck, No, St, Rg) and the nlm_void
structure definition served only the older implementations
and are now unused.
Also removes NLMDBG_FACILITY, which was set to the client
debug flag in server-side code but never referenced, and
corrects a comment to specify "NLMv4 Server procedures".
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc4proc.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 3c50bd18c45a..178473fabc7f 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -26,8 +26,6 @@
#include "nlm4xdr_gen.h"
#include "xdr4.h"
-#define NLMDBG_FACILITY NLMDBG_CLIENT
-
/*
* Wrapper structures combine xdrgen types with legacy nlm_lock.
* The xdrgen field must be first so the structure can be cast
@@ -1149,16 +1147,9 @@ static __be32 nlm4svc_proc_free_all(struct svc_rqst *rqstp)
/*
- * NLM Server procedures.
+ * NLMv4 Server procedures.
*/
-struct nlm_void { int dummy; };
-
-#define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */
-#define No (1+1024/4) /* netobj */
-#define St 1 /* status */
-#define Rg 4 /* range (offset + length) */
-
static const struct svc_procedure nlm4svc_procedures[24] = {
[NLMPROC4_NULL] = {
.pc_func = nlm4svc_proc_null,
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* [PATCH v2 42/42] lockd: Remove dead code from fs/lockd/xdr4.c
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (40 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 41/42] lockd: Remove C macros that are no longer used Chuck Lever
@ 2026-01-23 18:52 ` Chuck Lever
2026-01-26 12:51 ` [PATCH v2 00/42] Clarify module API boundaries Jeff Layton
42 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 18:52 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Now that all NLMv4 server-side procedures use XDR encoder and
decoder functions generated by xdrgen, the hand-written code in
fs/lockd/xdr4.c is no longer needed. This file contained the
original XDR processing logic that has been systematically
replaced throughout this series.
Remove the file and its Makefile reference to eliminate the
dead code. The helper function nlm4svc_set_file_lock_range()
is still needed by the generated code, so move it to xdr4.h
as an inline function where it remains accessible.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/Makefile | 2 +-
fs/lockd/clnt4xdr.c | 2 -
fs/lockd/lockd.h | 7 +
fs/lockd/svc4proc.c | 1 -
fs/lockd/xdr4.c | 334 --------------------------------------------
fs/lockd/xdr4.h | 33 -----
6 files changed, 8 insertions(+), 371 deletions(-)
delete mode 100644 fs/lockd/xdr4.c
delete mode 100644 fs/lockd/xdr4.h
diff --git a/fs/lockd/Makefile b/fs/lockd/Makefile
index 8e9d18a4348c..808f0f2a7be1 100644
--- a/fs/lockd/Makefile
+++ b/fs/lockd/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_LOCKD) += lockd.o
lockd-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o netlink.o
-lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o nlm4xdr_gen.o
+lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o svc4proc.o nlm4xdr_gen.o
lockd-$(CONFIG_PROC_FS) += procfs.o
#
diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c
index c09e67765cac..2058733eacf8 100644
--- a/fs/lockd/clnt4xdr.c
+++ b/fs/lockd/clnt4xdr.c
@@ -18,8 +18,6 @@
#include <uapi/linux/nfs3.h>
-#include "xdr4.h"
-
#define NLMDBG_FACILITY NLMDBG_XDR
#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
diff --git a/fs/lockd/lockd.h b/fs/lockd/lockd.h
index 17db7b3ad2c7..d63480b12858 100644
--- a/fs/lockd/lockd.h
+++ b/fs/lockd/lockd.h
@@ -52,6 +52,13 @@
*/
#define LOCKD_DFLT_TIMEO 10
+/* error codes new to NLMv4 */
+#define nlm4_deadlock cpu_to_be32(NLM_DEADLCK)
+#define nlm4_rofs cpu_to_be32(NLM_ROFS)
+#define nlm4_stale_fh cpu_to_be32(NLM_STALE_FH)
+#define nlm4_fbig cpu_to_be32(NLM_FBIG)
+#define nlm4_failed cpu_to_be32(NLM_FAILED)
+
/*
* Internal-use status codes, not to be placed on the wire.
* Version handlers translate these to appropriate wire values.
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 178473fabc7f..298b8104441d 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -24,7 +24,6 @@
#include "share.h"
#include "nlm4xdr_gen.h"
-#include "xdr4.h"
/*
* Wrapper structures combine xdrgen types with legacy nlm_lock.
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
deleted file mode 100644
index 308aac92a94e..000000000000
--- a/fs/lockd/xdr4.c
+++ /dev/null
@@ -1,334 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * linux/fs/lockd/xdr4.c
- *
- * XDR support for lockd and the lock client.
- *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
- * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
- */
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/nfs.h>
-
-#include <linux/sunrpc/xdr.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/svc.h>
-#include <linux/sunrpc/stats.h>
-
-#include "lockd.h"
-#include "svcxdr.h"
-#include "xdr4.h"
-
-static inline s64
-loff_t_to_s64(loff_t offset)
-{
- s64 res;
- if (offset > NLM4_OFFSET_MAX)
- res = NLM4_OFFSET_MAX;
- else if (offset < -NLM4_OFFSET_MAX)
- res = -NLM4_OFFSET_MAX;
- else
- res = offset;
- return res;
-}
-
-/*
- * NLM file handles are defined by specification to be a variable-length
- * XDR opaque no longer than 1024 bytes. However, this implementation
- * limits their length to the size of an NFSv3 file handle.
- */
-static bool
-svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
-{
- __be32 *p;
- u32 len;
-
- if (xdr_stream_decode_u32(xdr, &len) < 0)
- return false;
- if (len > NFS_MAXFHSIZE)
- return false;
-
- p = xdr_inline_decode(xdr, len);
- if (!p)
- return false;
- fh->size = len;
- memcpy(fh->data, p, len);
- memset(fh->data + len, 0, sizeof(fh->data) - len);
-
- return true;
-}
-
-static bool
-svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
-{
- struct file_lock *fl = &lock->fl;
-
- if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
- return false;
- if (!svcxdr_decode_fhandle(xdr, &lock->fh))
- return false;
- if (!svcxdr_decode_owner(xdr, &lock->oh))
- return false;
- if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
- return false;
- if (xdr_stream_decode_u64(xdr, &lock->lock_start) < 0)
- return false;
- if (xdr_stream_decode_u64(xdr, &lock->lock_len) < 0)
- return false;
-
- locks_init_lock(fl);
- fl->c.flc_type = F_RDLCK;
- lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len);
- return true;
-}
-
-static bool
-svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
-{
- const struct file_lock *fl = &lock->fl;
- s64 start, len;
-
- /* exclusive */
- if (xdr_stream_encode_bool(xdr, fl->c.flc_type != F_RDLCK) < 0)
- return false;
- if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
- return false;
- if (!svcxdr_encode_owner(xdr, &lock->oh))
- return false;
- start = loff_t_to_s64(fl->fl_start);
- if (fl->fl_end == OFFSET_MAX)
- len = 0;
- else
- len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
- if (xdr_stream_encode_u64(xdr, start) < 0)
- return false;
- if (xdr_stream_encode_u64(xdr, len) < 0)
- return false;
-
- return true;
-}
-
-static bool
-svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
-{
- if (!svcxdr_encode_stats(xdr, resp->status))
- return false;
- switch (resp->status) {
- case nlm_lck_denied:
- if (!svcxdr_encode_holder(xdr, &resp->lock))
- return false;
- }
-
- return true;
-}
-
-
-/*
- * Decode Call arguments
- */
-
-bool
-nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- return true;
-}
-
-bool
-nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- u32 exclusive;
-
- if (!svcxdr_decode_cookie(xdr, &argp->cookie))
- return false;
- if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
- return false;
- if (!svcxdr_decode_lock(xdr, &argp->lock))
- return false;
- if (exclusive)
- argp->lock.fl.c.flc_type = F_WRLCK;
-
- return true;
-}
-
-bool
-nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- u32 exclusive;
-
- if (!svcxdr_decode_cookie(xdr, &argp->cookie))
- return false;
- if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
- return false;
- if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
- return false;
- if (!svcxdr_decode_lock(xdr, &argp->lock))
- return false;
- if (exclusive)
- argp->lock.fl.c.flc_type = F_WRLCK;
- if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
- return false;
- if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
- return false;
- argp->monitor = 1; /* monitor client by default */
-
- return true;
-}
-
-bool
-nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- u32 exclusive;
-
- if (!svcxdr_decode_cookie(xdr, &argp->cookie))
- return false;
- if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
- return false;
- if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
- return false;
- if (!svcxdr_decode_lock(xdr, &argp->lock))
- return false;
- if (exclusive)
- argp->lock.fl.c.flc_type = F_WRLCK;
-
- return true;
-}
-
-bool
-nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_args *argp = rqstp->rq_argp;
-
- if (!svcxdr_decode_cookie(xdr, &argp->cookie))
- return false;
- if (!svcxdr_decode_lock(xdr, &argp->lock))
- return false;
- argp->lock.fl.c.flc_type = F_UNLCK;
-
- return true;
-}
-
-bool
-nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_res *resp = rqstp->rq_argp;
-
- if (!svcxdr_decode_cookie(xdr, &resp->cookie))
- return false;
- if (!svcxdr_decode_stats(xdr, &resp->status))
- return false;
-
- return true;
-}
-
-bool
-nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_reboot *argp = rqstp->rq_argp;
- __be32 *p;
- u32 len;
-
- if (xdr_stream_decode_u32(xdr, &len) < 0)
- return false;
- if (len > SM_MAXSTRLEN)
- return false;
- p = xdr_inline_decode(xdr, len);
- if (!p)
- return false;
- argp->len = len;
- argp->mon = (char *)p;
- if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
- return false;
- p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
- if (!p)
- return false;
- memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
-
- return true;
-}
-
-bool
-nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_lock *lock = &argp->lock;
-
- if (!svcxdr_decode_cookie(xdr, &argp->cookie))
- return false;
- if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
- return false;
- if (!svcxdr_decode_fhandle(xdr, &lock->fh))
- return false;
- if (!svcxdr_decode_owner(xdr, &lock->oh))
- return false;
- /* XXX: Range checks are missing in the original code */
- if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
- return false;
- if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
- return false;
-
- return true;
-}
-
-bool
-nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_args *argp = rqstp->rq_argp;
- struct nlm_lock *lock = &argp->lock;
-
- if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
- return false;
- if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
- return false;
-
- return true;
-}
-
-
-/*
- * Encode Reply results
- */
-
-bool
-nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- return true;
-}
-
-bool
-nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_res *resp = rqstp->rq_resp;
-
- return svcxdr_encode_cookie(xdr, &resp->cookie) &&
- svcxdr_encode_testrply(xdr, resp);
-}
-
-bool
-nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_res *resp = rqstp->rq_resp;
-
- return svcxdr_encode_cookie(xdr, &resp->cookie) &&
- svcxdr_encode_stats(xdr, resp->status);
-}
-
-bool
-nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
-{
- struct nlm_res *resp = rqstp->rq_resp;
-
- if (!svcxdr_encode_cookie(xdr, &resp->cookie))
- return false;
- if (!svcxdr_encode_stats(xdr, resp->status))
- return false;
- /* sequence */
- if (xdr_stream_encode_u32(xdr, 0) < 0)
- return false;
-
- return true;
-}
diff --git a/fs/lockd/xdr4.h b/fs/lockd/xdr4.h
deleted file mode 100644
index 4ddf51a2e0ea..000000000000
--- a/fs/lockd/xdr4.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * XDR types for the NLM protocol
- *
- * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
- */
-
-#ifndef _LOCKD_XDR4_H
-#define _LOCKD_XDR4_H
-
-/* error codes new to NLMv4 */
-#define nlm4_deadlock cpu_to_be32(NLM_DEADLCK)
-#define nlm4_rofs cpu_to_be32(NLM_ROFS)
-#define nlm4_stale_fh cpu_to_be32(NLM_STALE_FH)
-#define nlm4_fbig cpu_to_be32(NLM_FBIG)
-#define nlm4_failed cpu_to_be32(NLM_FAILED)
-
-bool nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-
-bool nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-bool nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
-
-#endif /* _LOCKD_XDR4_H */
--
2.52.0
^ permalink raw reply related [flat|nested] 53+ messages in thread
* Re: [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt
2026-01-23 18:52 ` [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt Chuck Lever
@ 2026-01-23 20:23 ` Jeff Layton
2026-01-23 20:44 ` Chuck Lever
0 siblings, 1 reply; 53+ messages in thread
From: Jeff Layton @ 2026-01-23 20:23 UTC (permalink / raw)
To: Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
On Fri, 2026-01-23 at 13:52 -0500, Chuck Lever wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
>
> The external API definitions for lockd reside in linux/lockd/bind.h.
> Because "struct nlm_host" is an internal lockd structure, bind.h
> does not include a definition of it. Dereferencing that structure
> outside of lockd violates the layering boundary between NFS and
> lockd.
>
> The proper approach is to use the nlmclnt_rpc_clnt() helper function
> already provided in lockd/bind.h, which retrieves the NLM host's
> struct rpc_clnt without exposing internal lockd structures. This
> maintains clean separation between the NFS client and lockd
> internals.
>
> Note that the nlm_host's h_rpcclnt field can be NULL during
> initialization (host.c:141) or after cleanup (host.c:629). Add a
> NULL check before calling shutdown_client() to prevent a potential
> NULL pointer dereference in the sysfs shutdown path.
>
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> fs/nfs/sysfs.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c
> index ea6e6168092b..186b29de0129 100644
> --- a/fs/nfs/sysfs.c
> +++ b/fs/nfs/sysfs.c
> @@ -12,7 +12,7 @@
> #include <linux/string.h>
> #include <linux/nfs_fs.h>
> #include <linux/rcupdate.h>
> -#include <linux/lockd/lockd.h>
> +#include <linux/lockd/bind.h>
>
> #include "internal.h"
> #include "nfs4_fs.h"
> @@ -284,8 +284,12 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
> if (!IS_ERR(server->client_acl))
> shutdown_client(server->client_acl);
>
> - if (server->nlm_host)
> - shutdown_client(server->nlm_host->h_rpcclnt);
> + if (server->nlm_host) {
> + struct rpc_clnt *nlm_clnt = nlmclnt_rpc_clnt(server->nlm_host);
> +
> + if (nlm_clnt)
> + shutdown_client(nlm_clnt);
I don't see any locking here. Soon after this thing goes NULL, the
nlm_clnt can be freed. ISTM that this ought to take a reference to
nlm_clnt and put it afterward.
> + }
> out:
> shutdown_nfs_client(server->nfs_client);
> return count;
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt
2026-01-23 20:23 ` Jeff Layton
@ 2026-01-23 20:44 ` Chuck Lever
2026-01-23 21:30 ` Jeff Layton
0 siblings, 1 reply; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 20:44 UTC (permalink / raw)
To: Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
On 1/23/26 3:23 PM, Jeff Layton wrote:
> On Fri, 2026-01-23 at 13:52 -0500, Chuck Lever wrote:
>> From: Chuck Lever <chuck.lever@oracle.com>
>>
>> The external API definitions for lockd reside in linux/lockd/bind.h.
>> Because "struct nlm_host" is an internal lockd structure, bind.h
>> does not include a definition of it. Dereferencing that structure
>> outside of lockd violates the layering boundary between NFS and
>> lockd.
>>
>> The proper approach is to use the nlmclnt_rpc_clnt() helper function
>> already provided in lockd/bind.h, which retrieves the NLM host's
>> struct rpc_clnt without exposing internal lockd structures. This
>> maintains clean separation between the NFS client and lockd
>> internals.
>>
>> Note that the nlm_host's h_rpcclnt field can be NULL during
>> initialization (host.c:141) or after cleanup (host.c:629). Add a
>> NULL check before calling shutdown_client() to prevent a potential
>> NULL pointer dereference in the sysfs shutdown path.
>>
>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>> ---
>> fs/nfs/sysfs.c | 10 +++++++---
>> 1 file changed, 7 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c
>> index ea6e6168092b..186b29de0129 100644
>> --- a/fs/nfs/sysfs.c
>> +++ b/fs/nfs/sysfs.c
>> @@ -12,7 +12,7 @@
>> #include <linux/string.h>
>> #include <linux/nfs_fs.h>
>> #include <linux/rcupdate.h>
>> -#include <linux/lockd/lockd.h>
>> +#include <linux/lockd/bind.h>
>>
>> #include "internal.h"
>> #include "nfs4_fs.h"
>> @@ -284,8 +284,12 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
>> if (!IS_ERR(server->client_acl))
>> shutdown_client(server->client_acl);
>>
>> - if (server->nlm_host)
>> - shutdown_client(server->nlm_host->h_rpcclnt);
>> + if (server->nlm_host) {
>> + struct rpc_clnt *nlm_clnt = nlmclnt_rpc_clnt(server->nlm_host);
>> +
>> + if (nlm_clnt)
>> + shutdown_client(nlm_clnt);
>
> I don't see any locking here. Soon after this thing goes NULL, the
> nlm_clnt can be freed. ISTM that this ought to take a reference to
> nlm_clnt and put it afterward.
So there is no locking here before the patch is applied. The patch does
not change that. Do you mean that the patch should add the additional
reference count bump (and document that fix in the commit message) ?
Mason's prompts did not call this out, so I assumed there wasn't an
obvious UAF possible in this path.
>
>> + }
>> out:
>> shutdown_nfs_client(server->nfs_client);
>> return count;
>
--
Chuck Lever
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt
2026-01-23 20:44 ` Chuck Lever
@ 2026-01-23 21:30 ` Jeff Layton
2026-01-23 21:37 ` Chuck Lever
0 siblings, 1 reply; 53+ messages in thread
From: Jeff Layton @ 2026-01-23 21:30 UTC (permalink / raw)
To: Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Benjamin Coddington
Cc: linux-nfs, Chuck Lever
On Fri, 2026-01-23 at 15:44 -0500, Chuck Lever wrote:
> On 1/23/26 3:23 PM, Jeff Layton wrote:
> > On Fri, 2026-01-23 at 13:52 -0500, Chuck Lever wrote:
> > > From: Chuck Lever <chuck.lever@oracle.com>
> > >
> > > The external API definitions for lockd reside in linux/lockd/bind.h.
> > > Because "struct nlm_host" is an internal lockd structure, bind.h
> > > does not include a definition of it. Dereferencing that structure
> > > outside of lockd violates the layering boundary between NFS and
> > > lockd.
> > >
> > > The proper approach is to use the nlmclnt_rpc_clnt() helper function
> > > already provided in lockd/bind.h, which retrieves the NLM host's
> > > struct rpc_clnt without exposing internal lockd structures. This
> > > maintains clean separation between the NFS client and lockd
> > > internals.
> > >
> > > Note that the nlm_host's h_rpcclnt field can be NULL during
> > > initialization (host.c:141) or after cleanup (host.c:629). Add a
> > > NULL check before calling shutdown_client() to prevent a potential
> > > NULL pointer dereference in the sysfs shutdown path.
> > >
> > > Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> > > ---
> > > fs/nfs/sysfs.c | 10 +++++++---
> > > 1 file changed, 7 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c
> > > index ea6e6168092b..186b29de0129 100644
> > > --- a/fs/nfs/sysfs.c
> > > +++ b/fs/nfs/sysfs.c
> > > @@ -12,7 +12,7 @@
> > > #include <linux/string.h>
> > > #include <linux/nfs_fs.h>
> > > #include <linux/rcupdate.h>
> > > -#include <linux/lockd/lockd.h>
> > > +#include <linux/lockd/bind.h>
> > >
> > > #include "internal.h"
> > > #include "nfs4_fs.h"
> > > @@ -284,8 +284,12 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
> > > if (!IS_ERR(server->client_acl))
> > > shutdown_client(server->client_acl);
> > >
> > > - if (server->nlm_host)
> > > - shutdown_client(server->nlm_host->h_rpcclnt);
> > > + if (server->nlm_host) {
> > > + struct rpc_clnt *nlm_clnt = nlmclnt_rpc_clnt(server->nlm_host);
> > > +
> > > + if (nlm_clnt)
> > > + shutdown_client(nlm_clnt);
> >
> > I don't see any locking here. Soon after this thing goes NULL, the
> > nlm_clnt can be freed. ISTM that this ought to take a reference to
> > nlm_clnt and put it afterward.
>
> So there is no locking here before the patch is applied. The patch does
> not change that. Do you mean that the patch should add the additional
> reference count bump (and document that fix in the commit message) ?
>
> Mason's prompts did not call this out, so I assumed there wasn't an
> obvious UAF possible in this path.
>
(Adding Ben since he wrote this originally...)
Sorry, I didn't make it clear. This is (possibly) an existing bug and
not something that is changed by your patches.
If that value can go NULL and be freed (and it looks like it can in
nlm_shutdown_hosts_net()) then I think that could race with someone
writing to the "shutdown" file. OTOH, maybe that can't happen because
the sysfs file gets removed before lockd_down() runs? I'm not sure.
The safest thing might be to take and hold the (global) nlm_host_mutex
around the NLM parts of shutdown_store(). Maybe we could add a helper
to the nlm public interface that does that so we don't need to expose
that mutex outside of NLM?
>
> >
> > > + }
> > > out:
> > > shutdown_nfs_client(server->nfs_client);
> > > return count;
> >
>
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt
2026-01-23 21:30 ` Jeff Layton
@ 2026-01-23 21:37 ` Chuck Lever
0 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-23 21:37 UTC (permalink / raw)
To: Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
Benjamin Coddington
Cc: linux-nfs, Chuck Lever
On Fri, Jan 23, 2026, at 4:30 PM, Jeff Layton wrote:
> On Fri, 2026-01-23 at 15:44 -0500, Chuck Lever wrote:
>> On 1/23/26 3:23 PM, Jeff Layton wrote:
>> > On Fri, 2026-01-23 at 13:52 -0500, Chuck Lever wrote:
>> > > From: Chuck Lever <chuck.lever@oracle.com>
>> > >
>> > > The external API definitions for lockd reside in linux/lockd/bind.h.
>> > > Because "struct nlm_host" is an internal lockd structure, bind.h
>> > > does not include a definition of it. Dereferencing that structure
>> > > outside of lockd violates the layering boundary between NFS and
>> > > lockd.
>> > >
>> > > The proper approach is to use the nlmclnt_rpc_clnt() helper function
>> > > already provided in lockd/bind.h, which retrieves the NLM host's
>> > > struct rpc_clnt without exposing internal lockd structures. This
>> > > maintains clean separation between the NFS client and lockd
>> > > internals.
>> > >
>> > > Note that the nlm_host's h_rpcclnt field can be NULL during
>> > > initialization (host.c:141) or after cleanup (host.c:629). Add a
>> > > NULL check before calling shutdown_client() to prevent a potential
>> > > NULL pointer dereference in the sysfs shutdown path.
>> > >
>> > > Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>> > > ---
>> > > fs/nfs/sysfs.c | 10 +++++++---
>> > > 1 file changed, 7 insertions(+), 3 deletions(-)
>> > >
>> > > diff --git a/fs/nfs/sysfs.c b/fs/nfs/sysfs.c
>> > > index ea6e6168092b..186b29de0129 100644
>> > > --- a/fs/nfs/sysfs.c
>> > > +++ b/fs/nfs/sysfs.c
>> > > @@ -12,7 +12,7 @@
>> > > #include <linux/string.h>
>> > > #include <linux/nfs_fs.h>
>> > > #include <linux/rcupdate.h>
>> > > -#include <linux/lockd/lockd.h>
>> > > +#include <linux/lockd/bind.h>
>> > >
>> > > #include "internal.h"
>> > > #include "nfs4_fs.h"
>> > > @@ -284,8 +284,12 @@ shutdown_store(struct kobject *kobj, struct kobj_attribute *attr,
>> > > if (!IS_ERR(server->client_acl))
>> > > shutdown_client(server->client_acl);
>> > >
>> > > - if (server->nlm_host)
>> > > - shutdown_client(server->nlm_host->h_rpcclnt);
>> > > + if (server->nlm_host) {
>> > > + struct rpc_clnt *nlm_clnt = nlmclnt_rpc_clnt(server->nlm_host);
>> > > +
>> > > + if (nlm_clnt)
>> > > + shutdown_client(nlm_clnt);
>> >
>> > I don't see any locking here. Soon after this thing goes NULL, the
>> > nlm_clnt can be freed. ISTM that this ought to take a reference to
>> > nlm_clnt and put it afterward.
>>
>> So there is no locking here before the patch is applied. The patch does
>> not change that. Do you mean that the patch should add the additional
>> reference count bump (and document that fix in the commit message) ?
>>
>> Mason's prompts did not call this out, so I assumed there wasn't an
>> obvious UAF possible in this path.
>>
>
> (Adding Ben since he wrote this originally...)
>
> Sorry, I didn't make it clear. This is (possibly) an existing bug and
> not something that is changed by your patches.
>
> If that value can go NULL and be freed (and it looks like it can in
> nlm_shutdown_hosts_net()) then I think that could race with someone
> writing to the "shutdown" file. OTOH, maybe that can't happen because
> the sysfs file gets removed before lockd_down() runs? I'm not sure.
>
> The safest thing might be to take and hold the (global) nlm_host_mutex
> around the NLM parts of shutdown_store(). Maybe we could add a helper
> to the nlm public interface that does that so we don't need to expose
> that mutex outside of NLM?
I asked Claude specifically to look for races, and he agrees there
is a pre-existing synchronization issue in here. Certainly could
be addressed via a pre-requisite patch to 05/42.
--
Chuck Lever
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/
2026-01-23 18:52 ` [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/ Chuck Lever
@ 2026-01-24 1:20 ` kernel test robot
2026-01-24 2:57 ` kernel test robot
1 sibling, 0 replies; 53+ messages in thread
From: kernel test robot @ 2026-01-24 1:20 UTC (permalink / raw)
To: Chuck Lever, NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo,
Tom Talpey
Cc: oe-kbuild-all, linux-nfs, Chuck Lever
Hi Chuck,
kernel test robot noticed the following build errors:
[auto build test ERROR on trondmy-nfs/linux-next]
[also build test ERROR on brauner-vfs/vfs.all linus/master v6.19-rc6 next-20260122]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Chuck-Lever/lockd-Simplify-cast_status-in-svcproc-c/20260124-025646
base: git://git.linux-nfs.org/projects/trondmy/linux-nfs.git linux-next
patch link: https://lore.kernel.org/r/20260123185259.1215767-11-cel%40kernel.org
patch subject: [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/
config: alpha-defconfig (https://download.01.org/0day-ci/archive/20260124/202601240901.DyDjt2Ka-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260124/202601240901.DyDjt2Ka-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601240901.DyDjt2Ka-lkp@intel.com/
All errors (new ones prefixed by >>):
fs/nfs/nfs3proc.c: In function 'nfs3_proc_lock':
>> fs/nfs/nfs3proc.c:1009:15: error: invalid use of undefined type 'struct file_lock'
1009 | if (fl->c.flc_flags & FL_CLOSE) {
| ^~
>> fs/nfs/nfs3proc.c:1009:31: error: 'FL_CLOSE' undeclared (first use in this function); did you mean 'OP_CLOSE'?
1009 | if (fl->c.flc_flags & FL_CLOSE) {
| ^~~~~~~~
| OP_CLOSE
fs/nfs/nfs3proc.c:1009:31: note: each undeclared identifier is reported only once for each function it appears in
vim +1009 fs/nfs/nfs3proc.c
f30cb757f680f9 Benjamin Coddington 2017-04-11 1000
^1da177e4c3f41 Linus Torvalds 2005-04-16 1001 static int
^1da177e4c3f41 Linus Torvalds 2005-04-16 1002 nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
^1da177e4c3f41 Linus Torvalds 2005-04-16 1003 {
496ad9aa8ef448 Al Viro 2013-01-23 1004 struct inode *inode = file_inode(filp);
f30cb757f680f9 Benjamin Coddington 2017-04-11 1005 struct nfs_lock_context *l_ctx = NULL;
f30cb757f680f9 Benjamin Coddington 2017-04-11 1006 struct nfs_open_context *ctx = nfs_file_open_context(filp);
f30cb757f680f9 Benjamin Coddington 2017-04-11 1007 int status;
1093a60ef34bb1 Chuck Lever 2008-01-11 1008
dd1fac6ae648ca Jeff Layton 2024-01-31 @1009 if (fl->c.flc_flags & FL_CLOSE) {
f30cb757f680f9 Benjamin Coddington 2017-04-11 1010 l_ctx = nfs_get_lock_context(ctx);
f30cb757f680f9 Benjamin Coddington 2017-04-11 1011 if (IS_ERR(l_ctx))
f30cb757f680f9 Benjamin Coddington 2017-04-11 1012 l_ctx = NULL;
f30cb757f680f9 Benjamin Coddington 2017-04-11 1013 else
f30cb757f680f9 Benjamin Coddington 2017-04-11 1014 set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
f30cb757f680f9 Benjamin Coddington 2017-04-11 1015 }
f30cb757f680f9 Benjamin Coddington 2017-04-11 1016
f30cb757f680f9 Benjamin Coddington 2017-04-11 1017 status = nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, l_ctx);
f30cb757f680f9 Benjamin Coddington 2017-04-11 1018
f30cb757f680f9 Benjamin Coddington 2017-04-11 1019 if (l_ctx)
f30cb757f680f9 Benjamin Coddington 2017-04-11 1020 nfs_put_lock_context(l_ctx);
f30cb757f680f9 Benjamin Coddington 2017-04-11 1021
f30cb757f680f9 Benjamin Coddington 2017-04-11 1022 return status;
^1da177e4c3f41 Linus Torvalds 2005-04-16 1023 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 1024
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/
2026-01-23 18:52 ` [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/ Chuck Lever
2026-01-24 1:20 ` kernel test robot
@ 2026-01-24 2:57 ` kernel test robot
1 sibling, 0 replies; 53+ messages in thread
From: kernel test robot @ 2026-01-24 2:57 UTC (permalink / raw)
To: Chuck Lever, NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo,
Tom Talpey
Cc: llvm, oe-kbuild-all, linux-nfs, Chuck Lever
Hi Chuck,
kernel test robot noticed the following build errors:
[auto build test ERROR on trondmy-nfs/linux-next]
[also build test ERROR on brauner-vfs/vfs.all linus/master v6.19-rc6 next-20260123]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Chuck-Lever/lockd-Simplify-cast_status-in-svcproc-c/20260124-025646
base: git://git.linux-nfs.org/projects/trondmy/linux-nfs.git linux-next
patch link: https://lore.kernel.org/r/20260123185259.1215767-11-cel%40kernel.org
patch subject: [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/
config: hexagon-defconfig (https://download.01.org/0day-ci/archive/20260124/202601241020.YgD8ze9Q-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260124/202601241020.YgD8ze9Q-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601241020.YgD8ze9Q-lkp@intel.com/
All errors (new ones prefixed by >>):
>> fs/nfs/nfs3proc.c:1009:8: error: incomplete definition of type 'struct file_lock'
1009 | if (fl->c.flc_flags & FL_CLOSE) {
| ~~^
include/linux/fs.h:1332:8: note: forward declaration of 'struct file_lock'
1332 | struct file_lock;
| ^
>> fs/nfs/nfs3proc.c:1009:24: error: use of undeclared identifier 'FL_CLOSE'; did you mean 'OP_CLOSE'?
1009 | if (fl->c.flc_flags & FL_CLOSE) {
| ^~~~~~~~
| OP_CLOSE
include/linux/nfs4.h:83:2: note: 'OP_CLOSE' declared here
83 | OP_CLOSE = 4,
| ^
2 errors generated.
vim +1009 fs/nfs/nfs3proc.c
f30cb757f680f96 Benjamin Coddington 2017-04-11 1000
^1da177e4c3f415 Linus Torvalds 2005-04-16 1001 static int
^1da177e4c3f415 Linus Torvalds 2005-04-16 1002 nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
^1da177e4c3f415 Linus Torvalds 2005-04-16 1003 {
496ad9aa8ef4480 Al Viro 2013-01-23 1004 struct inode *inode = file_inode(filp);
f30cb757f680f96 Benjamin Coddington 2017-04-11 1005 struct nfs_lock_context *l_ctx = NULL;
f30cb757f680f96 Benjamin Coddington 2017-04-11 1006 struct nfs_open_context *ctx = nfs_file_open_context(filp);
f30cb757f680f96 Benjamin Coddington 2017-04-11 1007 int status;
1093a60ef34bb12 Chuck Lever 2008-01-11 1008
dd1fac6ae648cac Jeff Layton 2024-01-31 @1009 if (fl->c.flc_flags & FL_CLOSE) {
f30cb757f680f96 Benjamin Coddington 2017-04-11 1010 l_ctx = nfs_get_lock_context(ctx);
f30cb757f680f96 Benjamin Coddington 2017-04-11 1011 if (IS_ERR(l_ctx))
f30cb757f680f96 Benjamin Coddington 2017-04-11 1012 l_ctx = NULL;
f30cb757f680f96 Benjamin Coddington 2017-04-11 1013 else
f30cb757f680f96 Benjamin Coddington 2017-04-11 1014 set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
f30cb757f680f96 Benjamin Coddington 2017-04-11 1015 }
f30cb757f680f96 Benjamin Coddington 2017-04-11 1016
f30cb757f680f96 Benjamin Coddington 2017-04-11 1017 status = nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, l_ctx);
f30cb757f680f96 Benjamin Coddington 2017-04-11 1018
f30cb757f680f96 Benjamin Coddington 2017-04-11 1019 if (l_ctx)
f30cb757f680f96 Benjamin Coddington 2017-04-11 1020 nfs_put_lock_context(l_ctx);
f30cb757f680f96 Benjamin Coddington 2017-04-11 1021
f30cb757f680f96 Benjamin Coddington 2017-04-11 1022 return status;
^1da177e4c3f415 Linus Torvalds 2005-04-16 1023 }
^1da177e4c3f415 Linus Torvalds 2005-04-16 1024
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 02/42] lockd: Introduce nlm__int__deadlock
2026-01-23 18:52 ` [PATCH v2 02/42] lockd: Introduce nlm__int__deadlock Chuck Lever
@ 2026-01-26 12:34 ` Jeff Layton
2026-01-26 14:36 ` Chuck Lever
0 siblings, 1 reply; 53+ messages in thread
From: Jeff Layton @ 2026-01-26 12:34 UTC (permalink / raw)
To: Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
On Fri, 2026-01-23 at 13:52 -0500, Chuck Lever wrote:
>
> +/*
> + * Internal-use status codes, not to be placed on the wire.
> + * Version handlers translate these to appropriate wire values.
> + */
> +#define nlm_drop_reply cpu_to_be32(30000)
> +#define nlm__int__deadlock cpu_to_be32(30001)
nit: the double underscores look weird next to nlm_drop_reply. Maybe
you could also rename it to nlm__int__drop_reply?
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 00/42] Clarify module API boundaries
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
` (41 preceding siblings ...)
2026-01-23 18:52 ` [PATCH v2 42/42] lockd: Remove dead code from fs/lockd/xdr4.c Chuck Lever
@ 2026-01-26 12:51 ` Jeff Layton
2026-01-26 14:35 ` Chuck Lever
42 siblings, 1 reply; 53+ messages in thread
From: Jeff Layton @ 2026-01-26 12:51 UTC (permalink / raw)
To: Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
On Fri, 2026-01-23 at 13:52 -0500, Chuck Lever wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
>
> The first thirteen patches in this series refactor the lockd code
> base to clearly separate its public API from internal implementation
> details. The remainder are presented for context, but demonstrate
> the intended purpose of the clean-up in the first thirteen.
>
> The lockd subsystem currently exposes internal implementation headers
> through include/linux/lockd/, creating implicit API contracts that
> complicate maintenance. External consumers such as NFSD and the NFS
> client have developed dependencies on internal structures like struct
> nlm_host, and wire protocol constants leak into high-level module
> interfaces.
>
> These patches work to establish clean architectural boundaries. The
> public API in include/linux/lockd/ is reduced to bind.h and nlm.h,
> which define the contract between lockd and its consumers. Private
> implementation details including XDR definitions, share management,
> and host structures are relocated to fs/lockd/ where they belong.
> Layering violations are corrected: the NFS client now uses accessor
> helpers instead of dereferencing internal structures, and nlm_fopen()
> returns errno values instead of wire protocol codes.
>
> These changes enable subsequent work to modernize the NLMv4 XDR
> layer using xdrgen without risk of breaking external consumers.
> This work appears in the remaining patches in this series, which
> are presented here only to provide context for the API adjustments.
> No need to review those closely just yet.
>
> The series is based on the public nfsd-testing branch.
>
> ---
>
> Changes since v1:
> - Refine the pre-requisite header adjustments
> - Reduce stack consumption by moving large structures to wrappers
> - Additional extensive clean up
>
> Chuck Lever (42):
> lockd: Simplify cast_status() in svcproc.c
> lockd: Introduce nlm__int__deadlock
> lockd: Have nlm_fopen() return errno values
> lockd: Relocate nlmsvc_unlock API declarations
> NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt
> lockd: Move xdr4.h from include/linux/lockd/ to fs/lockd/
> lockd: Move share.h from include/linux/lockd/ to fs/lockd/
> lockd: Relocate include/linux/lockd/lockd.h
> lockd: Remove lockd/debug.h
> lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/
> lockd: Make linux/lockd/nlm.h an internal header
> lockd: Move nlm4svc_set_file_lock_range()
> lockd: Relocate svc_version definitions to XDR layer
> Documentation: Add the RPC language description of NLM version 4
> lockd: Use xdrgen XDR functions for the NLMv4 NULL procedure
> lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure
> lockd: Use xdrgen XDR functions for the NLMv4 LOCK procedure
> lockd: Use xdrgen XDR functions for the NLMv4 CANCEL procedure
> lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK procedure
> lockd: Use xdrgen XDR functions for the NLMv4 GRANTED procedure
> lockd: Refactor nlm4svc_callback()
> lockd: Use xdrgen XDR functions for the NLMv4 TEST_MSG procedure
> lockd: Use xdrgen XDR functions for the NLMv4 LOCK_MSG procedure
> lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_MSG procedure
> lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_MSG procedure
> lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_MSG procedure
> lockd: Use xdrgen XDR functions for the NLMv4 TEST_RES procedure
> lockd: Use xdrgen XDR functions for the NLMv4 LOCK_RES procedure
> lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_RES procedure
> lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_RES procedure
> lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_RES procedure
> lockd: Use xdrgen XDR functions for the NLMv4 SM_NOTIFY procedure
> lockd: Convert server-side undefined procedures to xdrgen
> lockd: Hoist file_lock init out of nlm4svc_decode_shareargs()
> lockd: Prepare share helpers for xdrgen conversion
> lockd: Use xdrgen XDR functions for the NLMv4 SHARE procedure
> lockd: Use xdrgen XDR functions for the NLMv4 UNSHARE procedure
> lockd: Use xdrgen XDR functions for the NLMv4 NM_LOCK procedure
> lockd: Use xdrgen XDR functions for the NLMv4 FREE_ALL procedure
> lockd: Add LOCKD_SHARE_SVID constant for DOS sharing mode
> lockd: Remove C macros that are no longer used
> lockd: Remove dead code from fs/lockd/xdr4.c
>
> Documentation/sunrpc/xdr/nlm4.x | 211 ++++
> fs/lockd/Makefile | 30 +-
> fs/lockd/clnt4xdr.c | 5 +-
> fs/lockd/clntlock.c | 2 +-
> fs/lockd/clntproc.c | 2 +-
> fs/lockd/clntxdr.c | 3 +-
> fs/lockd/host.c | 2 +-
> {include/linux => fs}/lockd/lockd.h | 99 +-
> fs/lockd/mon.c | 2 +-
> {include/linux => fs}/lockd/nlm.h | 8 +-
> fs/lockd/nlm4xdr_gen.c | 724 +++++++++++
> fs/lockd/nlm4xdr_gen.h | 32 +
> {include/linux => fs}/lockd/share.h | 19 +-
> fs/lockd/svc.c | 50 +-
> fs/lockd/svc4proc.c | 1783 ++++++++++++++++++---------
> fs/lockd/svclock.c | 12 +-
> fs/lockd/svcproc.c | 99 +-
> fs/lockd/svcshare.c | 40 +-
> fs/lockd/svcsubs.c | 32 +-
> fs/lockd/trace.h | 3 +-
> fs/lockd/xdr.c | 6 +-
> {include/linux => fs}/lockd/xdr.h | 15 +-
> fs/lockd/xdr4.c | 347 ------
> fs/nfs/sysfs.c | 10 +-
> fs/nfsd/lockd.c | 51 +-
> fs/nfsd/nfsctl.c | 2 +-
> include/linux/lockd/bind.h | 23 +-
> include/linux/lockd/debug.h | 40 -
> include/linux/lockd/xdr4.h | 43 -
> include/linux/sunrpc/xdrgen/nlm4.h | 233 ++++
> 30 files changed, 2750 insertions(+), 1178 deletions(-)
> create mode 100644 Documentation/sunrpc/xdr/nlm4.x
> rename {include/linux => fs}/lockd/lockd.h (84%)
> rename {include/linux => fs}/lockd/nlm.h (91%)
> create mode 100644 fs/lockd/nlm4xdr_gen.c
> create mode 100644 fs/lockd/nlm4xdr_gen.h
> rename {include/linux => fs}/lockd/share.h (58%)
> rename {include/linux => fs}/lockd/xdr.h (91%)
> delete mode 100644 fs/lockd/xdr4.c
> delete mode 100644 include/linux/lockd/debug.h
> delete mode 100644 include/linux/lockd/xdr4.h
> create mode 100644 include/linux/sunrpc/xdrgen/nlm4.h
I went through the series and it looks good overall. I definitely like
moving away from hand-rolled XDR handling. You can add this to the
series:
Reviewed-by: Jeff Layton <jlayton@kernel.org>
There is still the matter of the race vs. the shutdown file, but that's
a preexisting problem. I presume you intend to let this sit in -next
for a while? It's a big change so it'd be good to have a nice long test
cycle with it.
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 00/42] Clarify module API boundaries
2026-01-26 12:51 ` [PATCH v2 00/42] Clarify module API boundaries Jeff Layton
@ 2026-01-26 14:35 ` Chuck Lever
0 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-26 14:35 UTC (permalink / raw)
To: Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
On 1/26/26 7:51 AM, Jeff Layton wrote:
> On Fri, 2026-01-23 at 13:52 -0500, Chuck Lever wrote:
>> From: Chuck Lever <chuck.lever@oracle.com>
>>
>> The first thirteen patches in this series refactor the lockd code
>> base to clearly separate its public API from internal implementation
>> details. The remainder are presented for context, but demonstrate
>> the intended purpose of the clean-up in the first thirteen.
>>
>> The lockd subsystem currently exposes internal implementation headers
>> through include/linux/lockd/, creating implicit API contracts that
>> complicate maintenance. External consumers such as NFSD and the NFS
>> client have developed dependencies on internal structures like struct
>> nlm_host, and wire protocol constants leak into high-level module
>> interfaces.
>>
>> These patches work to establish clean architectural boundaries. The
>> public API in include/linux/lockd/ is reduced to bind.h and nlm.h,
>> which define the contract between lockd and its consumers. Private
>> implementation details including XDR definitions, share management,
>> and host structures are relocated to fs/lockd/ where they belong.
>> Layering violations are corrected: the NFS client now uses accessor
>> helpers instead of dereferencing internal structures, and nlm_fopen()
>> returns errno values instead of wire protocol codes.
>>
>> These changes enable subsequent work to modernize the NLMv4 XDR
>> layer using xdrgen without risk of breaking external consumers.
>> This work appears in the remaining patches in this series, which
>> are presented here only to provide context for the API adjustments.
>> No need to review those closely just yet.
>>
>> The series is based on the public nfsd-testing branch.
>>
>> ---
>>
>> Changes since v1:
>> - Refine the pre-requisite header adjustments
>> - Reduce stack consumption by moving large structures to wrappers
>> - Additional extensive clean up
>>
>> Chuck Lever (42):
>> lockd: Simplify cast_status() in svcproc.c
>> lockd: Introduce nlm__int__deadlock
>> lockd: Have nlm_fopen() return errno values
>> lockd: Relocate nlmsvc_unlock API declarations
>> NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt
>> lockd: Move xdr4.h from include/linux/lockd/ to fs/lockd/
>> lockd: Move share.h from include/linux/lockd/ to fs/lockd/
>> lockd: Relocate include/linux/lockd/lockd.h
>> lockd: Remove lockd/debug.h
>> lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/
>> lockd: Make linux/lockd/nlm.h an internal header
>> lockd: Move nlm4svc_set_file_lock_range()
>> lockd: Relocate svc_version definitions to XDR layer
>> Documentation: Add the RPC language description of NLM version 4
>> lockd: Use xdrgen XDR functions for the NLMv4 NULL procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 LOCK procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 CANCEL procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 GRANTED procedure
>> lockd: Refactor nlm4svc_callback()
>> lockd: Use xdrgen XDR functions for the NLMv4 TEST_MSG procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 LOCK_MSG procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_MSG procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_MSG procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_MSG procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 TEST_RES procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 LOCK_RES procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_RES procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_RES procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_RES procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 SM_NOTIFY procedure
>> lockd: Convert server-side undefined procedures to xdrgen
>> lockd: Hoist file_lock init out of nlm4svc_decode_shareargs()
>> lockd: Prepare share helpers for xdrgen conversion
>> lockd: Use xdrgen XDR functions for the NLMv4 SHARE procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 UNSHARE procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 NM_LOCK procedure
>> lockd: Use xdrgen XDR functions for the NLMv4 FREE_ALL procedure
>> lockd: Add LOCKD_SHARE_SVID constant for DOS sharing mode
>> lockd: Remove C macros that are no longer used
>> lockd: Remove dead code from fs/lockd/xdr4.c
>>
>> Documentation/sunrpc/xdr/nlm4.x | 211 ++++
>> fs/lockd/Makefile | 30 +-
>> fs/lockd/clnt4xdr.c | 5 +-
>> fs/lockd/clntlock.c | 2 +-
>> fs/lockd/clntproc.c | 2 +-
>> fs/lockd/clntxdr.c | 3 +-
>> fs/lockd/host.c | 2 +-
>> {include/linux => fs}/lockd/lockd.h | 99 +-
>> fs/lockd/mon.c | 2 +-
>> {include/linux => fs}/lockd/nlm.h | 8 +-
>> fs/lockd/nlm4xdr_gen.c | 724 +++++++++++
>> fs/lockd/nlm4xdr_gen.h | 32 +
>> {include/linux => fs}/lockd/share.h | 19 +-
>> fs/lockd/svc.c | 50 +-
>> fs/lockd/svc4proc.c | 1783 ++++++++++++++++++---------
>> fs/lockd/svclock.c | 12 +-
>> fs/lockd/svcproc.c | 99 +-
>> fs/lockd/svcshare.c | 40 +-
>> fs/lockd/svcsubs.c | 32 +-
>> fs/lockd/trace.h | 3 +-
>> fs/lockd/xdr.c | 6 +-
>> {include/linux => fs}/lockd/xdr.h | 15 +-
>> fs/lockd/xdr4.c | 347 ------
>> fs/nfs/sysfs.c | 10 +-
>> fs/nfsd/lockd.c | 51 +-
>> fs/nfsd/nfsctl.c | 2 +-
>> include/linux/lockd/bind.h | 23 +-
>> include/linux/lockd/debug.h | 40 -
>> include/linux/lockd/xdr4.h | 43 -
>> include/linux/sunrpc/xdrgen/nlm4.h | 233 ++++
>> 30 files changed, 2750 insertions(+), 1178 deletions(-)
>> create mode 100644 Documentation/sunrpc/xdr/nlm4.x
>> rename {include/linux => fs}/lockd/lockd.h (84%)
>> rename {include/linux => fs}/lockd/nlm.h (91%)
>> create mode 100644 fs/lockd/nlm4xdr_gen.c
>> create mode 100644 fs/lockd/nlm4xdr_gen.h
>> rename {include/linux => fs}/lockd/share.h (58%)
>> rename {include/linux => fs}/lockd/xdr.h (91%)
>> delete mode 100644 fs/lockd/xdr4.c
>> delete mode 100644 include/linux/lockd/debug.h
>> delete mode 100644 include/linux/lockd/xdr4.h
>> create mode 100644 include/linux/sunrpc/xdrgen/nlm4.h
>
> I went through the series and it looks good overall. I definitely like
> moving away from hand-rolled XDR handling. You can add this to the
> series:
>
> Reviewed-by: Jeff Layton <jlayton@kernel.org>
>
> There is still the matter of the race vs. the shutdown file, but that's
> a preexisting problem.
So the first time around I didn't quite catch the gist of your proposal
to add a lockd API to deal with this. Obviously it makes sense that such
an API will also remove the direct access to the internal struct field.
So I've folded all that together into a replacement for 05/42.
> I presume you intend to let this sit in -next
> for a while? It's a big change so it'd be good to have a nice long test
> cycle with it.
I was thinking of applying at least 1 - 13 to nfsd-testing soon so it
will show up in nfsd-next as soon as the 7.0 merge window closes.
--
Chuck Lever
^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [PATCH v2 02/42] lockd: Introduce nlm__int__deadlock
2026-01-26 12:34 ` Jeff Layton
@ 2026-01-26 14:36 ` Chuck Lever
0 siblings, 0 replies; 53+ messages in thread
From: Chuck Lever @ 2026-01-26 14:36 UTC (permalink / raw)
To: Jeff Layton, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
On 1/26/26 7:34 AM, Jeff Layton wrote:
> On Fri, 2026-01-23 at 13:52 -0500, Chuck Lever wrote:
>>
>> +/*
>> + * Internal-use status codes, not to be placed on the wire.
>> + * Version handlers translate these to appropriate wire values.
>> + */
>> +#define nlm_drop_reply cpu_to_be32(30000)
>> +#define nlm__int__deadlock cpu_to_be32(30001)
>
> nit: the double underscores look weird next to nlm_drop_reply. Maybe
> you could also rename it to nlm__int__drop_reply?
>
What I'd really like to do is replace nlm_drop_reply with setting the
RQ_DROPME flag.
--
Chuck Lever
^ permalink raw reply [flat|nested] 53+ messages in thread
end of thread, other threads:[~2026-01-26 14:36 UTC | newest]
Thread overview: 53+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-23 18:52 [PATCH v2 00/42] Clarify module API boundaries Chuck Lever
2026-01-23 18:52 ` [PATCH v2 01/42] lockd: Simplify cast_status() in svcproc.c Chuck Lever
2026-01-23 18:52 ` [PATCH v2 02/42] lockd: Introduce nlm__int__deadlock Chuck Lever
2026-01-26 12:34 ` Jeff Layton
2026-01-26 14:36 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 03/42] lockd: Have nlm_fopen() return errno values Chuck Lever
2026-01-23 18:52 ` [PATCH v2 04/42] lockd: Relocate nlmsvc_unlock API declarations Chuck Lever
2026-01-23 18:52 ` [PATCH v2 05/42] NFS: Use nlmclnt_rpc_clnt() helper to retrieve nlm_host's rpc_clnt Chuck Lever
2026-01-23 20:23 ` Jeff Layton
2026-01-23 20:44 ` Chuck Lever
2026-01-23 21:30 ` Jeff Layton
2026-01-23 21:37 ` Chuck Lever
2026-01-23 18:52 ` [PATCH v2 06/42] lockd: Move xdr4.h from include/linux/lockd/ to fs/lockd/ Chuck Lever
2026-01-23 18:52 ` [PATCH v2 07/42] lockd: Move share.h " Chuck Lever
2026-01-23 18:52 ` [PATCH v2 08/42] lockd: Relocate include/linux/lockd/lockd.h Chuck Lever
2026-01-23 18:52 ` [PATCH v2 09/42] lockd: Remove lockd/debug.h Chuck Lever
2026-01-23 18:52 ` [PATCH v2 10/42] lockd: Move xdr.h from include/linux/lockd/ to fs/lockd/ Chuck Lever
2026-01-24 1:20 ` kernel test robot
2026-01-24 2:57 ` kernel test robot
2026-01-23 18:52 ` [PATCH v2 11/42] lockd: Make linux/lockd/nlm.h an internal header Chuck Lever
2026-01-23 18:52 ` [PATCH v2 12/42] lockd: Move nlm4svc_set_file_lock_range() Chuck Lever
2026-01-23 18:52 ` [PATCH v2 13/42] lockd: Relocate svc_version definitions to XDR layer Chuck Lever
2026-01-23 18:52 ` [PATCH v2 14/42] Documentation: Add the RPC language description of NLM version 4 Chuck Lever
2026-01-23 18:52 ` [PATCH v2 15/42] lockd: Use xdrgen XDR functions for the NLMv4 NULL procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 16/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 17/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 18/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 19/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 20/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 21/42] lockd: Refactor nlm4svc_callback() Chuck Lever
2026-01-23 18:52 ` [PATCH v2 22/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST_MSG procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 23/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK_MSG procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 24/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_MSG procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 25/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_MSG procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 26/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_MSG procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 27/42] lockd: Use xdrgen XDR functions for the NLMv4 TEST_RES procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 28/42] lockd: Use xdrgen XDR functions for the NLMv4 LOCK_RES procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 29/42] lockd: Use xdrgen XDR functions for the NLMv4 CANCEL_RES procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 30/42] lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK_RES procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 31/42] lockd: Use xdrgen XDR functions for the NLMv4 GRANTED_RES procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 32/42] lockd: Use xdrgen XDR functions for the NLMv4 SM_NOTIFY procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 33/42] lockd: Convert server-side undefined procedures to xdrgen Chuck Lever
2026-01-23 18:52 ` [PATCH v2 34/42] lockd: Hoist file_lock init out of nlm4svc_decode_shareargs() Chuck Lever
2026-01-23 18:52 ` [PATCH v2 35/42] lockd: Prepare share helpers for xdrgen conversion Chuck Lever
2026-01-23 18:52 ` [PATCH v2 36/42] lockd: Use xdrgen XDR functions for the NLMv4 SHARE procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 37/42] lockd: Use xdrgen XDR functions for the NLMv4 UNSHARE procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 38/42] lockd: Use xdrgen XDR functions for the NLMv4 NM_LOCK procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 39/42] lockd: Use xdrgen XDR functions for the NLMv4 FREE_ALL procedure Chuck Lever
2026-01-23 18:52 ` [PATCH v2 40/42] lockd: Add LOCKD_SHARE_SVID constant for DOS sharing mode Chuck Lever
2026-01-23 18:52 ` [PATCH v2 41/42] lockd: Remove C macros that are no longer used Chuck Lever
2026-01-23 18:52 ` [PATCH v2 42/42] lockd: Remove dead code from fs/lockd/xdr4.c Chuck Lever
2026-01-26 12:51 ` [PATCH v2 00/42] Clarify module API boundaries Jeff Layton
2026-01-26 14:35 ` Chuck Lever
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox