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