lockd: Use xdrgen XDR functions for the NLMv4 UNLOCK procedure

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.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
Chuck Lever
2026-02-17 17:06:58 -05:00
parent 496a0e971a
commit a2ac36e79b

View File

@@ -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;
@@ -601,10 +608,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__int__drop_reply ?
rpc_drop_reply : rpc_success;
}
/*
@@ -914,15 +977,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,
@@ -1123,6 +1186,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;