]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
lockd: Use xdrgen XDR functions for the NLMv3 UNLOCK procedure
authorChuck Lever <chuck.lever@oracle.com>
Tue, 12 May 2026 18:13:52 +0000 (14:13 -0400)
committerChuck Lever <cel@kernel.org>
Tue, 9 Jun 2026 20:32:59 +0000 (16:32 -0400)
The NLM UNLOCK procedure allows clients to release held locks,
completing the basic lock lifecycle alongside TEST, LOCK, and
CANCEL procedures already converted in this series.

Convert UNLOCK to use the xdrgen functions
nlm_svc_decode_nlm_unlockargs and nlm_svc_encode_nlm_res
generated from the NLM version 3 protocol specification, reusing
the nlm3svc_lookup_host() and nlm3svc_lookup_file() helpers
introduced earlier in the series. The procedure handler uses
xdrgen types through a wrapper structure that bridges between
generated code and the legacy lockd_lock representation still
used by the core lockd logic.

Setting pc_argzero to zero is safe because the generated decoder
fills the argp->xdrgen subfields before the procedure runs, so
the zeroing memset performed by the dispatch layer is not needed.
The lock member of the wrapper is populated explicitly in
nlm3svc_lookup_file() rather than relying on zero-initialization.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/lockd/svcproc.c

index a5e40ca3f10942ba83f7aba9ed344fae63fdf426..ccc6a633df7bac44528ecba09e13a1b954e69e6a 100644 (file)
@@ -72,6 +72,13 @@ struct nlm_cancargs_wrapper {
 
 static_assert(offsetof(struct nlm_cancargs_wrapper, xdrgen) == 0);
 
+struct nlm_unlockargs_wrapper {
+       struct nlm_unlockargs           xdrgen;
+       struct lockd_lock               lock;
+};
+
+static_assert(offsetof(struct nlm_unlockargs_wrapper, xdrgen) == 0);
+
 static __be32
 nlm_netobj_to_cookie(struct lockd_cookie *cookie, netobj *object)
 {
@@ -619,10 +626,61 @@ __nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct lockd_res *resp)
        return rpc_success;
 }
 
+/**
+ * nlmsvc_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:
+ *   nlm_res NLM_UNLOCK(nlm_unlockargs) = 4;
+ *
+ * Permissible procedure status codes:
+ *   %LCK_GRANTED:             The requested lock was released.
+ *   %LCK_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:
+ *   %LCK_DENIED_NOLOCKS:      A needed resource could not be allocated.
+ */
 static __be32
 nlmsvc_proc_unlock(struct svc_rqst *rqstp)
 {
-       return __nlmsvc_proc_unlock(rqstp, rqstp->rq_resp);
+       struct nlm_unlockargs_wrapper *argp = rqstp->rq_argp;
+       struct nlm_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 = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
+       if (!host)
+               goto out;
+
+       resp->xdrgen.stat.stat = nlm3svc_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;
 }
 
 /*
@@ -944,15 +1002,15 @@ static const struct svc_procedure nlmsvc_procedures[24] = {
                .pc_xdrressize  = NLM3_nlm_res_sz,
                .pc_name        = "CANCEL",
        },
-       [NLMPROC_UNLOCK] = {
-               .pc_func = nlmsvc_proc_unlock,
-               .pc_decode = nlmsvc_decode_unlockargs,
-               .pc_encode = nlmsvc_encode_res,
-               .pc_argsize = sizeof(struct lockd_args),
-               .pc_argzero = sizeof(struct lockd_args),
-               .pc_ressize = sizeof(struct lockd_res),
-               .pc_xdrressize = Ck+St,
-               .pc_name = "UNLOCK",
+       [NLM_UNLOCK] = {
+               .pc_func        = nlmsvc_proc_unlock,
+               .pc_decode      = nlm_svc_decode_nlm_unlockargs,
+               .pc_encode      = nlm_svc_encode_nlm_res,
+               .pc_argsize     = sizeof(struct nlm_unlockargs_wrapper),
+               .pc_argzero     = 0,
+               .pc_ressize     = sizeof(struct nlm_res_wrapper),
+               .pc_xdrressize  = NLM3_nlm_res_sz,
+               .pc_name        = "UNLOCK",
        },
        [NLMPROC_GRANTED] = {
                .pc_func = nlmsvc_proc_granted,
@@ -1153,6 +1211,7 @@ union nlmsvc_xdrstore {
        struct nlm_testargs_wrapper     testargs;
        struct nlm_lockargs_wrapper     lockargs;
        struct nlm_cancargs_wrapper     cancargs;
+       struct nlm_unlockargs_wrapper   unlockargs;
        struct nlm_testres_wrapper      testres;
        struct nlm_res_wrapper          res;
        struct lockd_args               args;