File: /usr/src/linux/fs/lockd/svc4proc.c

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