]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
lockd: Have nlm_fopen() return errno values
authorChuck Lever <chuck.lever@oracle.com>
Wed, 28 Jan 2026 15:19:25 +0000 (10:19 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 30 Mar 2026 01:25:09 +0000 (21:25 -0400)
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.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/lockd/svc4proc.c
fs/lockd/svcproc.c
fs/lockd/svcsubs.c
fs/nfsd/lockd.c
include/linux/lockd/bind.h
include/linux/lockd/lockd.h

index 55b6dcc56db135d7dd28cba81fd31355479fc73a..4ceb27cc72e4d9202ba9a54f0f3570fc3cc50b2f 100644 (file)
@@ -73,9 +73,21 @@ 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:
+               if (be32_to_cpu(error) >= 30000) {
+                       pr_warn_once("lockd: unhandled internal status %u\n",
+                                    be32_to_cpu(error));
+                       return nlm4_failed;
+               }
+               return error;
+       }
 }
 
 /*
index 27ed71935e45256d4624cbc8ac6f106162c82d28..272c8f36ed2a80f8acd5d47845011d7debd3a010 100644 (file)
@@ -39,8 +39,20 @@ 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;
+       default:
+               if (be32_to_cpu(status) >= 30000)
+                       pr_warn_once("lockd: unhandled internal status %u\n",
+                                    be32_to_cpu(status));
+               break;
+       }
        return status;
 }
 #endif
index dd0214dcb69503006181a1533c440fc04a329d73..967739d2aa9097488adfd04b9966c7724f8f884e 100644 (file)
@@ -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__int__drop_reply;
+                       break;
+               case -ESTALE:
+                       nlmerr = nlm__int__stale_fh;
+                       break;
+               default:
+                       nlmerr = nlm__int__failed;
+                       break;
+               }
+       }
+
+       return nlmerr;
 }
 
 /*
index 8c230ccd6645b81ecbc3e888d45fc07097ec4f67..6fe1325815e0e9929a39db74d98a5ec0bbbcd15c 100644 (file)
 
 #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__int__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)
 {
index c53c81242e72716f17f580c17b3694b3aff8c8f5..2f5dd9e943ee2c4af812a64fe39ffea44aae495b 100644 (file)
@@ -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;
index 7936919121379e1daf2f897afc6c3a573c7b250c..195e6ce28f6e7700701fb836286055e63c8c70e9 100644 (file)
@@ -44,6 +44,8 @@
  */
 #define nlm__int__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).