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