xref: /linux/fs/nfsd/lockd.c (revision 5ea5880764cbb164afb17a62e76ca75dc371409d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This file contains all the stubs needed when communicating with lockd.
4  * This level of indirection is necessary so we can run nfsd+lockd without
5  * requiring the nfs client to be compiled in/loaded, and vice versa.
6  *
7  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
8  */
9 
10 #include <linux/file.h>
11 #include <linux/lockd/bind.h>
12 #include "nfsd.h"
13 #include "vfs.h"
14 
15 #define NFSDDBG_FACILITY		NFSDDBG_LOCKD
16 
17 /**
18  * nlm_fopen - Open an NFSD file
19  * @rqstp: NLM RPC procedure execution context
20  * @f: NFS file handle to be opened
21  * @filp: OUT: an opened struct file
22  * @flags: the POSIX open flags to use
23  *
24  * nlm_fopen() holds the dentry reference until nlm_fclose() releases it.
25  *
26  * Returns zero on success or a negative errno value if the file
27  * cannot be opened.
28  */
29 static int nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f,
30 		     struct file **filp, int flags)
31 {
32 	__be32		nfserr;
33 	int		access;
34 	struct svc_fh	fh;
35 
36 	/* must initialize before using! but maxsize doesn't matter */
37 	fh_init(&fh,0);
38 	fh.fh_handle.fh_size = f->size;
39 	memcpy(&fh.fh_handle.fh_raw, f->data, f->size);
40 	fh.fh_export = NULL;
41 
42 	/*
43 	 * Allow BYPASS_GSS as some client implementations use AUTH_SYS
44 	 * for NLM even when GSS is used for NFS.
45 	 * Allow OWNER_OVERRIDE as permission might have been changed
46 	 * after the file was opened.
47 	 * Pass MAY_NLM so that authentication can be completely bypassed
48 	 * if NFSEXP_NOAUTHNLM is set.  Some older clients use AUTH_NULL
49 	 * for NLM requests.
50 	 */
51 	access = (flags == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ;
52 	access |= NFSD_MAY_NLM | NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_BYPASS_GSS;
53 	nfserr = nfsd_open(rqstp, &fh, S_IFREG, access, filp);
54 	fh_put(&fh);
55 
56 	switch (nfserr) {
57 	case nfs_ok:
58 		break;
59 	case nfserr_jukebox:
60 		/*
61 		 * This error can indicate a presence of a conflicting
62 		 * delegation to an NLM lock request. Options are:
63 		 * (1) For now, drop this request and make the client
64 		 * retry. When delegation is returned, client's lock retry
65 		 * will complete.
66 		 * (2) NLM4_DENIED as per "spec" signals to the client
67 		 * that the lock is unavailable now but client can retry.
68 		 * Linux client implementation does not. It treats
69 		 * NLM4_DENIED same as NLM4_FAILED and fails the request.
70 		 * (3) For the future, treat this as blocked lock and try
71 		 * to callback when the delegation is returned but might
72 		 * not have a proper lock request to block on.
73 		 */
74 		return -EWOULDBLOCK;
75 	case nfserr_stale:
76 		return -ESTALE;
77 	default:
78 		return -ENOLCK;
79 	}
80 
81 	return 0;
82 }
83 
84 /**
85  * nlm_fclose - Close an NFSD file
86  * @filp: a struct file that was opened by nlm_fopen()
87  */
88 static void
89 nlm_fclose(struct file *filp)
90 {
91 	fput(filp);
92 }
93 
94 static const struct nlmsvc_binding nfsd_nlm_ops = {
95 	.fopen		= nlm_fopen,		/* open file for locking */
96 	.fclose		= nlm_fclose,		/* close file */
97 };
98 
99 void
100 nfsd_lockd_init(void)
101 {
102 	dprintk("nfsd: initializing lockd\n");
103 	nlmsvc_ops = &nfsd_nlm_ops;
104 }
105 
106 void
107 nfsd_lockd_shutdown(void)
108 {
109 	nlmsvc_ops = NULL;
110 }
111