xref: /openbmc/linux/fs/lockd/svc4proc.c (revision 82e6fdd6)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * linux/fs/lockd/svc4proc.c
4  *
5  * Lockd server procedures. We don't implement the NLM_*_RES
6  * procedures because we don't use the async procedures.
7  *
8  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
9  */
10 
11 #include <linux/types.h>
12 #include <linux/time.h>
13 #include <linux/lockd/lockd.h>
14 #include <linux/lockd/share.h>
15 #include <linux/sunrpc/svc_xprt.h>
16 
17 #define NLMDBG_FACILITY		NLMDBG_CLIENT
18 
19 /*
20  * Obtain client and file from arguments
21  */
22 static __be32
23 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
24 			struct nlm_host **hostp, struct nlm_file **filp)
25 {
26 	struct nlm_host		*host = NULL;
27 	struct nlm_file		*file = NULL;
28 	struct nlm_lock		*lock = &argp->lock;
29 	__be32			error = 0;
30 
31 	/* nfsd callbacks must have been installed for this procedure */
32 	if (!nlmsvc_ops)
33 		return nlm_lck_denied_nolocks;
34 
35 	/* Obtain host handle */
36 	if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
37 	 || (argp->monitor && nsm_monitor(host) < 0))
38 		goto no_locks;
39 	*hostp = host;
40 
41 	/* Obtain file pointer. Not used by FREE_ALL call. */
42 	if (filp != NULL) {
43 		if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
44 			goto no_locks;
45 		*filp = file;
46 
47 		/* Set up the missing parts of the file_lock structure */
48 		lock->fl.fl_file  = file->f_file;
49 		lock->fl.fl_owner = (fl_owner_t) host;
50 		lock->fl.fl_lmops = &nlmsvc_lock_operations;
51 	}
52 
53 	return 0;
54 
55 no_locks:
56 	nlmsvc_release_host(host);
57  	if (error)
58 		return error;
59 	return nlm_lck_denied_nolocks;
60 }
61 
62 /*
63  * NULL: Test for presence of service
64  */
65 static __be32
66 nlm4svc_proc_null(struct svc_rqst *rqstp)
67 {
68 	dprintk("lockd: NULL          called\n");
69 	return rpc_success;
70 }
71 
72 /*
73  * TEST: Check for conflicting lock
74  */
75 static __be32
76 __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp)
77 {
78 	struct nlm_args *argp = rqstp->rq_argp;
79 	struct nlm_host	*host;
80 	struct nlm_file	*file;
81 	__be32 rc = rpc_success;
82 
83 	dprintk("lockd: TEST4        called\n");
84 	resp->cookie = argp->cookie;
85 
86 	/* Obtain client and file */
87 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
88 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
89 
90 	/* Now check for conflicting locks */
91 	resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie);
92 	if (resp->status == nlm_drop_reply)
93 		rc = rpc_drop_reply;
94 	else
95 		dprintk("lockd: TEST4        status %d\n", ntohl(resp->status));
96 
97 	nlmsvc_release_host(host);
98 	nlm_release_file(file);
99 	return rc;
100 }
101 
102 static __be32
103 nlm4svc_proc_test(struct svc_rqst *rqstp)
104 {
105 	return __nlm4svc_proc_test(rqstp, rqstp->rq_resp);
106 }
107 
108 static __be32
109 __nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp)
110 {
111 	struct nlm_args *argp = rqstp->rq_argp;
112 	struct nlm_host	*host;
113 	struct nlm_file	*file;
114 	__be32 rc = rpc_success;
115 
116 	dprintk("lockd: LOCK          called\n");
117 
118 	resp->cookie = argp->cookie;
119 
120 	/* Obtain client and file */
121 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
122 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
123 
124 #if 0
125 	/* If supplied state doesn't match current state, we assume it's
126 	 * an old request that time-warped somehow. Any error return would
127 	 * do in this case because it's irrelevant anyway.
128 	 *
129 	 * NB: We don't retrieve the remote host's state yet.
130 	 */
131 	if (host->h_nsmstate && host->h_nsmstate != argp->state) {
132 		resp->status = nlm_lck_denied_nolocks;
133 	} else
134 #endif
135 
136 	/* Now try to lock the file */
137 	resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
138 					argp->block, &argp->cookie,
139 					argp->reclaim);
140 	if (resp->status == nlm_drop_reply)
141 		rc = rpc_drop_reply;
142 	else
143 		dprintk("lockd: LOCK         status %d\n", ntohl(resp->status));
144 
145 	nlmsvc_release_host(host);
146 	nlm_release_file(file);
147 	return rc;
148 }
149 
150 static __be32
151 nlm4svc_proc_lock(struct svc_rqst *rqstp)
152 {
153 	return __nlm4svc_proc_lock(rqstp, rqstp->rq_resp);
154 }
155 
156 static __be32
157 __nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_res *resp)
158 {
159 	struct nlm_args *argp = rqstp->rq_argp;
160 	struct nlm_host	*host;
161 	struct nlm_file	*file;
162 
163 	dprintk("lockd: CANCEL        called\n");
164 
165 	resp->cookie = argp->cookie;
166 
167 	/* Don't accept requests during grace period */
168 	if (locks_in_grace(SVC_NET(rqstp))) {
169 		resp->status = nlm_lck_denied_grace_period;
170 		return rpc_success;
171 	}
172 
173 	/* Obtain client and file */
174 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
175 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
176 
177 	/* Try to cancel request. */
178 	resp->status = nlmsvc_cancel_blocked(SVC_NET(rqstp), file, &argp->lock);
179 
180 	dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
181 	nlmsvc_release_host(host);
182 	nlm_release_file(file);
183 	return rpc_success;
184 }
185 
186 static __be32
187 nlm4svc_proc_cancel(struct svc_rqst *rqstp)
188 {
189 	return __nlm4svc_proc_cancel(rqstp, rqstp->rq_resp);
190 }
191 
192 /*
193  * UNLOCK: release a lock
194  */
195 static __be32
196 __nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_res *resp)
197 {
198 	struct nlm_args *argp = rqstp->rq_argp;
199 	struct nlm_host	*host;
200 	struct nlm_file	*file;
201 
202 	dprintk("lockd: UNLOCK        called\n");
203 
204 	resp->cookie = argp->cookie;
205 
206 	/* Don't accept new lock requests during grace period */
207 	if (locks_in_grace(SVC_NET(rqstp))) {
208 		resp->status = nlm_lck_denied_grace_period;
209 		return rpc_success;
210 	}
211 
212 	/* Obtain client and file */
213 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
214 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
215 
216 	/* Now try to remove the lock */
217 	resp->status = nlmsvc_unlock(SVC_NET(rqstp), file, &argp->lock);
218 
219 	dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
220 	nlmsvc_release_host(host);
221 	nlm_release_file(file);
222 	return rpc_success;
223 }
224 
225 static __be32
226 nlm4svc_proc_unlock(struct svc_rqst *rqstp)
227 {
228 	return __nlm4svc_proc_unlock(rqstp, rqstp->rq_resp);
229 }
230 
231 /*
232  * GRANTED: A server calls us to tell that a process' lock request
233  * was granted
234  */
235 static __be32
236 __nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_res *resp)
237 {
238 	struct nlm_args *argp = rqstp->rq_argp;
239 
240 	resp->cookie = argp->cookie;
241 
242 	dprintk("lockd: GRANTED       called\n");
243 	resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
244 	dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
245 	return rpc_success;
246 }
247 
248 static __be32
249 nlm4svc_proc_granted(struct svc_rqst *rqstp)
250 {
251 	return __nlm4svc_proc_granted(rqstp, rqstp->rq_resp);
252 }
253 
254 /*
255  * This is the generic lockd callback for async RPC calls
256  */
257 static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
258 {
259 	dprintk("lockd: %5u callback returned %d\n", task->tk_pid,
260 			-task->tk_status);
261 }
262 
263 static void nlm4svc_callback_release(void *data)
264 {
265 	nlmsvc_release_call(data);
266 }
267 
268 static const struct rpc_call_ops nlm4svc_callback_ops = {
269 	.rpc_call_done = nlm4svc_callback_exit,
270 	.rpc_release = nlm4svc_callback_release,
271 };
272 
273 /*
274  * `Async' versions of the above service routines. They aren't really,
275  * because we send the callback before the reply proper. I hope this
276  * doesn't break any clients.
277  */
278 static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc,
279 		__be32 (*func)(struct svc_rqst *,  struct nlm_res *))
280 {
281 	struct nlm_args *argp = rqstp->rq_argp;
282 	struct nlm_host	*host;
283 	struct nlm_rqst	*call;
284 	__be32 stat;
285 
286 	host = nlmsvc_lookup_host(rqstp,
287 				  argp->lock.caller,
288 				  argp->lock.len);
289 	if (host == NULL)
290 		return rpc_system_err;
291 
292 	call = nlm_alloc_call(host);
293 	nlmsvc_release_host(host);
294 	if (call == NULL)
295 		return rpc_system_err;
296 
297 	stat = func(rqstp, &call->a_res);
298 	if (stat != 0) {
299 		nlmsvc_release_call(call);
300 		return stat;
301 	}
302 
303 	call->a_flags = RPC_TASK_ASYNC;
304 	if (nlm_async_reply(call, proc, &nlm4svc_callback_ops) < 0)
305 		return rpc_system_err;
306 	return rpc_success;
307 }
308 
309 static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp)
310 {
311 	dprintk("lockd: TEST_MSG      called\n");
312 	return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, __nlm4svc_proc_test);
313 }
314 
315 static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
316 {
317 	dprintk("lockd: LOCK_MSG      called\n");
318 	return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, __nlm4svc_proc_lock);
319 }
320 
321 static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
322 {
323 	dprintk("lockd: CANCEL_MSG    called\n");
324 	return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, __nlm4svc_proc_cancel);
325 }
326 
327 static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
328 {
329 	dprintk("lockd: UNLOCK_MSG    called\n");
330 	return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, __nlm4svc_proc_unlock);
331 }
332 
333 static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
334 {
335 	dprintk("lockd: GRANTED_MSG   called\n");
336 	return nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, __nlm4svc_proc_granted);
337 }
338 
339 /*
340  * SHARE: create a DOS share or alter existing share.
341  */
342 static __be32
343 nlm4svc_proc_share(struct svc_rqst *rqstp)
344 {
345 	struct nlm_args *argp = rqstp->rq_argp;
346 	struct nlm_res *resp = rqstp->rq_resp;
347 	struct nlm_host	*host;
348 	struct nlm_file	*file;
349 
350 	dprintk("lockd: SHARE         called\n");
351 
352 	resp->cookie = argp->cookie;
353 
354 	/* Don't accept new lock requests during grace period */
355 	if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
356 		resp->status = nlm_lck_denied_grace_period;
357 		return rpc_success;
358 	}
359 
360 	/* Obtain client and file */
361 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
362 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
363 
364 	/* Now try to create the share */
365 	resp->status = nlmsvc_share_file(host, file, argp);
366 
367 	dprintk("lockd: SHARE         status %d\n", ntohl(resp->status));
368 	nlmsvc_release_host(host);
369 	nlm_release_file(file);
370 	return rpc_success;
371 }
372 
373 /*
374  * UNSHARE: Release a DOS share.
375  */
376 static __be32
377 nlm4svc_proc_unshare(struct svc_rqst *rqstp)
378 {
379 	struct nlm_args *argp = rqstp->rq_argp;
380 	struct nlm_res *resp = rqstp->rq_resp;
381 	struct nlm_host	*host;
382 	struct nlm_file	*file;
383 
384 	dprintk("lockd: UNSHARE       called\n");
385 
386 	resp->cookie = argp->cookie;
387 
388 	/* Don't accept requests during grace period */
389 	if (locks_in_grace(SVC_NET(rqstp))) {
390 		resp->status = nlm_lck_denied_grace_period;
391 		return rpc_success;
392 	}
393 
394 	/* Obtain client and file */
395 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
396 		return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
397 
398 	/* Now try to lock the file */
399 	resp->status = nlmsvc_unshare_file(host, file, argp);
400 
401 	dprintk("lockd: UNSHARE       status %d\n", ntohl(resp->status));
402 	nlmsvc_release_host(host);
403 	nlm_release_file(file);
404 	return rpc_success;
405 }
406 
407 /*
408  * NM_LOCK: Create an unmonitored lock
409  */
410 static __be32
411 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp)
412 {
413 	struct nlm_args *argp = rqstp->rq_argp;
414 
415 	dprintk("lockd: NM_LOCK       called\n");
416 
417 	argp->monitor = 0;		/* just clean the monitor flag */
418 	return nlm4svc_proc_lock(rqstp);
419 }
420 
421 /*
422  * FREE_ALL: Release all locks and shares held by client
423  */
424 static __be32
425 nlm4svc_proc_free_all(struct svc_rqst *rqstp)
426 {
427 	struct nlm_args *argp = rqstp->rq_argp;
428 	struct nlm_host	*host;
429 
430 	/* Obtain client */
431 	if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
432 		return rpc_success;
433 
434 	nlmsvc_free_host_resources(host);
435 	nlmsvc_release_host(host);
436 	return rpc_success;
437 }
438 
439 /*
440  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
441  */
442 static __be32
443 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
444 {
445 	struct nlm_reboot *argp = rqstp->rq_argp;
446 
447 	dprintk("lockd: SM_NOTIFY     called\n");
448 
449 	if (!nlm_privileged_requester(rqstp)) {
450 		char buf[RPC_MAX_ADDRBUFLEN];
451 		printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
452 				svc_print_addr(rqstp, buf, sizeof(buf)));
453 		return rpc_system_err;
454 	}
455 
456 	nlm_host_rebooted(SVC_NET(rqstp), argp);
457 	return rpc_success;
458 }
459 
460 /*
461  * client sent a GRANTED_RES, let's remove the associated block
462  */
463 static __be32
464 nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
465 {
466 	struct nlm_res *argp = rqstp->rq_argp;
467 
468         if (!nlmsvc_ops)
469                 return rpc_success;
470 
471         dprintk("lockd: GRANTED_RES   called\n");
472 
473         nlmsvc_grant_reply(&argp->cookie, argp->status);
474         return rpc_success;
475 }
476 
477 
478 /*
479  * NLM Server procedures.
480  */
481 
482 #define nlm4svc_encode_norep	nlm4svc_encode_void
483 #define nlm4svc_decode_norep	nlm4svc_decode_void
484 #define nlm4svc_decode_testres	nlm4svc_decode_void
485 #define nlm4svc_decode_lockres	nlm4svc_decode_void
486 #define nlm4svc_decode_unlockres	nlm4svc_decode_void
487 #define nlm4svc_decode_cancelres	nlm4svc_decode_void
488 #define nlm4svc_decode_grantedres	nlm4svc_decode_void
489 
490 #define nlm4svc_proc_none	nlm4svc_proc_null
491 #define nlm4svc_proc_test_res	nlm4svc_proc_null
492 #define nlm4svc_proc_lock_res	nlm4svc_proc_null
493 #define nlm4svc_proc_cancel_res	nlm4svc_proc_null
494 #define nlm4svc_proc_unlock_res	nlm4svc_proc_null
495 
496 struct nlm_void			{ int dummy; };
497 
498 #define PROC(name, xargt, xrest, argt, rest, respsize)	\
499  { .pc_func	= nlm4svc_proc_##name,	\
500    .pc_decode	= nlm4svc_decode_##xargt,	\
501    .pc_encode	= nlm4svc_encode_##xrest,	\
502    .pc_release	= NULL,					\
503    .pc_argsize	= sizeof(struct nlm_##argt),		\
504    .pc_ressize	= sizeof(struct nlm_##rest),		\
505    .pc_xdrressize = respsize,				\
506  }
507 #define	Ck	(1+XDR_QUADLEN(NLM_MAXCOOKIELEN))	/* cookie */
508 #define	No	(1+1024/4)				/* netobj */
509 #define	St	1					/* status */
510 #define	Rg	4					/* range (offset + length) */
511 const struct svc_procedure nlmsvc_procedures4[] = {
512   PROC(null,		void,		void,		void,	void, 1),
513   PROC(test,		testargs,	testres,	args,	res, Ck+St+2+No+Rg),
514   PROC(lock,		lockargs,	res,		args,	res, Ck+St),
515   PROC(cancel,		cancargs,	res,		args,	res, Ck+St),
516   PROC(unlock,		unlockargs,	res,		args,	res, Ck+St),
517   PROC(granted,		testargs,	res,		args,	res, Ck+St),
518   PROC(test_msg,	testargs,	norep,		args,	void, 1),
519   PROC(lock_msg,	lockargs,	norep,		args,	void, 1),
520   PROC(cancel_msg,	cancargs,	norep,		args,	void, 1),
521   PROC(unlock_msg,	unlockargs,	norep,		args,	void, 1),
522   PROC(granted_msg,	testargs,	norep,		args,	void, 1),
523   PROC(test_res,	testres,	norep,		res,	void, 1),
524   PROC(lock_res,	lockres,	norep,		res,	void, 1),
525   PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
526   PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
527   PROC(granted_res,	res,		norep,		res,	void, 1),
528   /* statd callback */
529   PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
530   PROC(none,		void,		void,		void,	void, 0),
531   PROC(none,		void,		void,		void,	void, 0),
532   PROC(none,		void,		void,		void,	void, 0),
533   PROC(share,		shareargs,	shareres,	args,	res, Ck+St+1),
534   PROC(unshare,		shareargs,	shareres,	args,	res, Ck+St+1),
535   PROC(nm_lock,		lockargs,	res,		args,	res, Ck+St),
536   PROC(free_all,	notify,		void,		args,	void, 1),
537 
538 };
539