]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
lockd: Use xdrgen XDR functions for the NLMv3 CANCEL procedure
authorChuck Lever <chuck.lever@oracle.com>
Tue, 12 May 2026 18:13:51 +0000 (14:13 -0400)
committerChuck Lever <cel@kernel.org>
Tue, 9 Jun 2026 20:32:59 +0000 (16:32 -0400)
The NLM CANCEL procedure allows clients to cancel outstanding
blocked lock requests. This patch continues the xdrgen migration
by converting the CANCEL procedure. CANCEL reuses the
nlm3svc_lookup_host() and nlm3svc_lookup_file() helpers
established in the TEST procedure conversion.

This patch converts the CANCEL procedure to use xdrgen functions
nlm_svc_decode_nlm_cancargs and nlm_svc_encode_nlm_res generated
from the NLM version 3 protocol specification. 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 66bc9a2efddb810a8645bd8576df1a99c3e2b005..a5e40ca3f10942ba83f7aba9ed344fae63fdf426 100644 (file)
@@ -65,6 +65,13 @@ struct nlm_res_wrapper {
 
 static_assert(offsetof(struct nlm_res_wrapper, xdrgen) == 0);
 
+struct nlm_cancargs_wrapper {
+       struct nlm_cancargs             xdrgen;
+       struct lockd_lock               lock;
+};
+
+static_assert(offsetof(struct nlm_cancargs_wrapper, xdrgen) == 0);
+
 static __be32
 nlm_netobj_to_cookie(struct lockd_cookie *cookie, netobj *object)
 {
@@ -517,10 +524,63 @@ __nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct lockd_res *resp)
        return rpc_success;
 }
 
+/**
+ * nlmsvc_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:
+ *   nlm_res NLM_CANCEL(nlm_cancargs) = 3;
+ *
+ * Permissible procedure status codes:
+ *   %LCK_GRANTED:             The requested lock was canceled.
+ *   %LCK_DENIED:              There was no lock to cancel.
+ *   %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_cancel(struct svc_rqst *rqstp)
 {
-       return __nlmsvc_proc_cancel(rqstp, rqstp->rq_resp);
+       struct nlm_cancargs_wrapper *argp = rqstp->rq_argp;
+       unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
+       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,
+                                                    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__int__drop_reply ?
+               rpc_drop_reply : rpc_success;
 }
 
 /*
@@ -874,15 +934,15 @@ static const struct svc_procedure nlmsvc_procedures[24] = {
                .pc_xdrressize  = NLM3_nlm_res_sz,
                .pc_name        = "LOCK",
        },
-       [NLMPROC_CANCEL] = {
-               .pc_func = nlmsvc_proc_cancel,
-               .pc_decode = nlmsvc_decode_cancargs,
-               .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 = "CANCEL",
+       [NLM_CANCEL] = {
+               .pc_func        = nlmsvc_proc_cancel,
+               .pc_decode      = nlm_svc_decode_nlm_cancargs,
+               .pc_encode      = nlm_svc_encode_nlm_res,
+               .pc_argsize     = sizeof(struct nlm_cancargs_wrapper),
+               .pc_argzero     = 0,
+               .pc_ressize     = sizeof(struct nlm_res_wrapper),
+               .pc_xdrressize  = NLM3_nlm_res_sz,
+               .pc_name        = "CANCEL",
        },
        [NLMPROC_UNLOCK] = {
                .pc_func = nlmsvc_proc_unlock,
@@ -1092,6 +1152,7 @@ static const struct svc_procedure nlmsvc_procedures[24] = {
 union nlmsvc_xdrstore {
        struct nlm_testargs_wrapper     testargs;
        struct nlm_lockargs_wrapper     lockargs;
+       struct nlm_cancargs_wrapper     cancargs;
        struct nlm_testres_wrapper      testres;
        struct nlm_res_wrapper          res;
        struct lockd_args               args;