1
2
3#include <linux/module.h>
4#include <linux/init.h>
5#include <linux/sysctl.h>
6#include <linux/moduleparam.h>
7
8#include <linux/sched.h>
9#include <linux/errno.h>
10#include <linux/in.h>
11#include <linux/uio.h>
12#include <linux/slab.h>
13#include <linux/smp.h>
14#include <linux/smp_lock.h>
15#include <linux/mutex.h>
16
17#include <linux/sunrpc/types.h>
18#include <linux/sunrpc/stats.h>
19#include <linux/sunrpc/clnt.h>
20#include <linux/sunrpc/svc.h>
21#include <linux/sunrpc/svcsock.h>
22#include <net/ip.h>
23#include <linux/lockd/lockd.h>
24#include <linux/lockd/sm_inter.h>
25#include <linux/nfs.h>
26
27#define NLMDBG_FACILITY		NLMDBG_SVC
28#define LOCKD_BUFSIZE		(1024 + NLMSVC_XDRSIZE)
29#define ALLOWED_SIGS		(sigmask(SIGKILL))
30
31static struct svc_program	nlmsvc_program;
32
33struct nlmsvc_binding *		nlmsvc_ops;
34EXPORT_SYMBOL(nlmsvc_ops);
35
36static DEFINE_MUTEX(nlmsvc_mutex);
37static unsigned int		nlmsvc_users;
38static pid_t			nlmsvc_pid;
39static struct svc_serv		*nlmsvc_serv;
40int				nlmsvc_grace_period;
41unsigned long			nlmsvc_timeout;
42
43static DECLARE_COMPLETION(lockd_start_done);
44static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
45
46/*
47 * These can be set at insmod time (useful for NFS as root filesystem),
48 * and also changed through the sysctl interface.  -- Jamie Lokier, Aug 2003
49 */
50static unsigned long		nlm_grace_period;
51static unsigned long		nlm_timeout = LOCKD_DFLT_TIMEO;
52static int			nlm_udpport, nlm_tcpport;
53int				nsm_use_hostnames = 0;
54
55/*
56 * Constants needed for the sysctl interface.
57 */
58static const unsigned long	nlm_grace_period_min = 0;
59static const unsigned long	nlm_grace_period_max = 240;
60static const unsigned long	nlm_timeout_min = 3;
61static const unsigned long	nlm_timeout_max = 20;
62static const int		nlm_port_min = 0, nlm_port_max = 65535;
63
64static struct ctl_table_header * nlm_sysctl_table;
65
66static unsigned long set_grace_period(void)
67{
68	unsigned long grace_period;
69
70	/* Note: nlm_timeout should always be nonzero */
71	if (nlm_grace_period)
72		grace_period = ((nlm_grace_period + nlm_timeout - 1)
73				/ nlm_timeout) * nlm_timeout * HZ;
74	else
75		grace_period = nlm_timeout * 5 * HZ;
76	nlmsvc_grace_period = 1;
77	return grace_period + jiffies;
78}
79
80static inline void clear_grace_period(void)
81{
82	nlmsvc_grace_period = 0;
83}
84
85/*
86 * This is the lockd kernel thread
87 */
88static void
89lockd(struct svc_rqst *rqstp)
90{
91	int		err = 0;
92	unsigned long grace_period_expire;
93
94	/* Lock module and set up kernel thread */
95	/* lockd_up is waiting for us to startup, so will
96	 * be holding a reference to this module, so it
97	 * is safe to just claim another reference
98	 */
99	__module_get(THIS_MODULE);
100	lock_kernel();
101
102	/*
103	 * Let our maker know we're running.
104	 */
105	nlmsvc_pid = current->pid;
106	nlmsvc_serv = rqstp->rq_server;
107	complete(&lockd_start_done);
108
109	daemonize("lockd");
110
111	/* Process request with signals blocked, but allow SIGKILL.  */
112	allow_signal(SIGKILL);
113
114	/* kick rpciod */
115	rpciod_up();
116
117	dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
118
119	if (!nlm_timeout)
120		nlm_timeout = LOCKD_DFLT_TIMEO;
121	nlmsvc_timeout = nlm_timeout * HZ;
122
123	grace_period_expire = set_grace_period();
124
125	/*
126	 * The main request loop. We don't terminate until the last
127	 * NFS mount or NFS daemon has gone away, and we've been sent a
128	 * signal, or else another process has taken over our job.
129	 */
130	while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) {
131		long timeout = MAX_SCHEDULE_TIMEOUT;
132		char buf[RPC_MAX_ADDRBUFLEN];
133
134		if (signalled()) {
135			flush_signals(current);
136			if (nlmsvc_ops) {
137				nlmsvc_invalidate_all();
138				grace_period_expire = set_grace_period();
139			}
140		}
141
142		/*
143		 * Retry any blocked locks that have been notified by
144		 * the VFS. Don't do this during grace period.
145		 * (Theoretically, there shouldn't even be blocked locks
146		 * during grace period).
147		 */
148		if (!nlmsvc_grace_period) {
149			timeout = nlmsvc_retry_blocked();
150		} else if (time_before(grace_period_expire, jiffies))
151			clear_grace_period();
152
153		/*
154		 * Find a socket with data available and call its
155		 * recvfrom routine.
156		 */
157		err = svc_recv(rqstp, timeout);
158		if (err == -EAGAIN || err == -EINTR)
159			continue;
160		if (err < 0) {
161			printk(KERN_WARNING
162			       "lockd: terminating on error %d\n",
163			       -err);
164			break;
165		}
166
167		dprintk("lockd: request from %s\n",
168				svc_print_addr(rqstp, buf, sizeof(buf)));
169
170		svc_process(rqstp);
171	}
172
173	flush_signals(current);
174
175	/*
176	 * Check whether there's a new lockd process before
177	 * shutting down the hosts and clearing the slot.
178	 */
179	if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
180		if (nlmsvc_ops)
181			nlmsvc_invalidate_all();
182		nlm_shutdown_hosts();
183		nlmsvc_pid = 0;
184		nlmsvc_serv = NULL;
185	} else
186		printk(KERN_DEBUG
187			"lockd: new process, skipping host shutdown\n");
188	wake_up(&lockd_exit);
189
190	/* Exit the RPC thread */
191	svc_exit_thread(rqstp);
192
193	/* release rpciod */
194	rpciod_down();
195
196	/* Release module */
197	unlock_kernel();
198	module_put_and_exit(0);
199}
200
201
202static int find_socket(struct svc_serv *serv, int proto)
203{
204	struct svc_sock *svsk;
205	int found = 0;
206	list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
207		if (svsk->sk_sk->sk_protocol == proto) {
208			found = 1;
209			break;
210		}
211	return found;
212}
213
214/*
215 * Make any sockets that are needed but not present.
216 * If nlm_udpport or nlm_tcpport were set as module
217 * options, make those sockets unconditionally
218 */
219static int make_socks(struct svc_serv *serv, int proto)
220{
221	static int warned;
222	int err = 0;
223
224	if (proto == IPPROTO_UDP || nlm_udpport)
225		if (!find_socket(serv, IPPROTO_UDP))
226			err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport,
227						SVC_SOCK_DEFAULTS);
228	if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport))
229		if (!find_socket(serv, IPPROTO_TCP))
230			err = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport,
231						SVC_SOCK_DEFAULTS);
232
233	if (err >= 0) {
234		warned = 0;
235		err = 0;
236	} else if (warned++ == 0)
237		printk(KERN_WARNING
238		       "lockd_up: makesock failed, error=%d\n", err);
239	return err;
240}
241
242/*
243 * Bring up the lockd process if it's not already up.
244 */
245int
246lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
247{
248	struct svc_serv *	serv;
249	int			error = 0;
250
251	mutex_lock(&nlmsvc_mutex);
252	/*
253	 * Check whether we're already up and running.
254	 */
255	if (nlmsvc_pid) {
256		if (proto)
257			error = make_socks(nlmsvc_serv, proto);
258		goto out;
259	}
260
261	/*
262	 * Sanity check: if there's no pid,
263	 * we should be the first user ...
264	 */
265	if (nlmsvc_users)
266		printk(KERN_WARNING
267			"lockd_up: no pid, %d users??\n", nlmsvc_users);
268
269	error = -ENOMEM;
270	serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
271	if (!serv) {
272		printk(KERN_WARNING "lockd_up: create service failed\n");
273		goto out;
274	}
275
276	if ((error = make_socks(serv, proto)) < 0)
277		goto destroy_and_out;
278
279	/*
280	 * Create the kernel thread and wait for it to start.
281	 */
282	error = svc_create_thread(lockd, serv);
283	if (error) {
284		printk(KERN_WARNING
285			"lockd_up: create thread failed, error=%d\n", error);
286		goto destroy_and_out;
287	}
288	wait_for_completion(&lockd_start_done);
289
290	/*
291	 * Note: svc_serv structures have an initial use count of 1,
292	 * so we exit through here on both success and failure.
293	 */
294destroy_and_out:
295	svc_destroy(serv);
296out:
297	if (!error)
298		nlmsvc_users++;
299	mutex_unlock(&nlmsvc_mutex);
300	return error;
301}
302EXPORT_SYMBOL(lockd_up);
303
304/*
305 * Decrement the user count and bring down lockd if we're the last.
306 */
307void
308lockd_down(void)
309{
310	static int warned;
311
312	mutex_lock(&nlmsvc_mutex);
313	if (nlmsvc_users) {
314		if (--nlmsvc_users)
315			goto out;
316	} else
317		printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid);
318
319	if (!nlmsvc_pid) {
320		if (warned++ == 0)
321			printk(KERN_WARNING "lockd_down: no lockd running.\n");
322		goto out;
323	}
324	warned = 0;
325
326	kill_proc(nlmsvc_pid, SIGKILL, 1);
327	/*
328	 * Wait for the lockd process to exit, but since we're holding
329	 * the lockd semaphore, we can't wait around forever ...
330	 */
331	clear_thread_flag(TIF_SIGPENDING);
332	interruptible_sleep_on_timeout(&lockd_exit, HZ);
333	if (nlmsvc_pid) {
334		printk(KERN_WARNING
335			"lockd_down: lockd failed to exit, clearing pid\n");
336		nlmsvc_pid = 0;
337	}
338	spin_lock_irq(&current->sighand->siglock);
339	recalc_sigpending();
340	spin_unlock_irq(&current->sighand->siglock);
341out:
342	mutex_unlock(&nlmsvc_mutex);
343}
344EXPORT_SYMBOL(lockd_down);
345
346/*
347 * Sysctl parameters (same as module parameters, different interface).
348 */
349
350static ctl_table nlm_sysctls[] = {
351	{
352		.ctl_name	= CTL_UNNUMBERED,
353		.procname	= "nlm_grace_period",
354		.data		= &nlm_grace_period,
355		.maxlen		= sizeof(unsigned long),
356		.mode		= 0644,
357		.proc_handler	= &proc_doulongvec_minmax,
358		.extra1		= (unsigned long *) &nlm_grace_period_min,
359		.extra2		= (unsigned long *) &nlm_grace_period_max,
360	},
361	{
362		.ctl_name	= CTL_UNNUMBERED,
363		.procname	= "nlm_timeout",
364		.data		= &nlm_timeout,
365		.maxlen		= sizeof(unsigned long),
366		.mode		= 0644,
367		.proc_handler	= &proc_doulongvec_minmax,
368		.extra1		= (unsigned long *) &nlm_timeout_min,
369		.extra2		= (unsigned long *) &nlm_timeout_max,
370	},
371	{
372		.ctl_name	= CTL_UNNUMBERED,
373		.procname	= "nlm_udpport",
374		.data		= &nlm_udpport,
375		.maxlen		= sizeof(int),
376		.mode		= 0644,
377		.proc_handler	= &proc_dointvec_minmax,
378		.extra1		= (int *) &nlm_port_min,
379		.extra2		= (int *) &nlm_port_max,
380	},
381	{
382		.ctl_name	= CTL_UNNUMBERED,
383		.procname	= "nlm_tcpport",
384		.data		= &nlm_tcpport,
385		.maxlen		= sizeof(int),
386		.mode		= 0644,
387		.proc_handler	= &proc_dointvec_minmax,
388		.extra1		= (int *) &nlm_port_min,
389		.extra2		= (int *) &nlm_port_max,
390	},
391	{
392		.ctl_name	= CTL_UNNUMBERED,
393		.procname	= "nsm_use_hostnames",
394		.data		= &nsm_use_hostnames,
395		.maxlen		= sizeof(int),
396		.mode		= 0644,
397		.proc_handler	= &proc_dointvec,
398	},
399	{
400		.ctl_name	= CTL_UNNUMBERED,
401		.procname	= "nsm_local_state",
402		.data		= &nsm_local_state,
403		.maxlen		= sizeof(int),
404		.mode		= 0644,
405		.proc_handler	= &proc_dointvec,
406	},
407	{ .ctl_name = 0 }
408};
409
410static ctl_table nlm_sysctl_dir[] = {
411	{
412		.ctl_name	= CTL_UNNUMBERED,
413		.procname	= "nfs",
414		.mode		= 0555,
415		.child		= nlm_sysctls,
416	},
417	{ .ctl_name = 0 }
418};
419
420static ctl_table nlm_sysctl_root[] = {
421	{
422		.ctl_name	= CTL_FS,
423		.procname	= "fs",
424		.mode		= 0555,
425		.child		= nlm_sysctl_dir,
426	},
427	{ .ctl_name = 0 }
428};
429
430/*
431 * Module (and sysfs) parameters.
432 */
433
434#define param_set_min_max(name, type, which_strtol, min, max)		\
435static int param_set_##name(const char *val, struct kernel_param *kp)	\
436{									\
437	char *endp;							\
438	__typeof__(type) num = which_strtol(val, &endp, 0);		\
439	if (endp == val || *endp || num < (min) || num > (max))		\
440		return -EINVAL;						\
441	*((int *) kp->arg) = num;					\
442	return 0;							\
443}
444
445static inline int is_callback(u32 proc)
446{
447	return proc == NLMPROC_GRANTED
448		|| proc == NLMPROC_GRANTED_MSG
449		|| proc == NLMPROC_TEST_RES
450		|| proc == NLMPROC_LOCK_RES
451		|| proc == NLMPROC_CANCEL_RES
452		|| proc == NLMPROC_UNLOCK_RES
453		|| proc == NLMPROC_NSM_NOTIFY;
454}
455
456
457static int lockd_authenticate(struct svc_rqst *rqstp)
458{
459	rqstp->rq_client = NULL;
460	switch (rqstp->rq_authop->flavour) {
461		case RPC_AUTH_NULL:
462		case RPC_AUTH_UNIX:
463			if (rqstp->rq_proc == 0)
464				return SVC_OK;
465			if (is_callback(rqstp->rq_proc)) {
466				/* Leave it to individual procedures to
467				 * call nlmsvc_lookup_host(rqstp)
468				 */
469				return SVC_OK;
470			}
471			return svc_set_client(rqstp);
472	}
473	return SVC_DENIED;
474}
475
476
477param_set_min_max(port, int, simple_strtol, 0, 65535)
478param_set_min_max(grace_period, unsigned long, simple_strtoul,
479		  nlm_grace_period_min, nlm_grace_period_max)
480param_set_min_max(timeout, unsigned long, simple_strtoul,
481		  nlm_timeout_min, nlm_timeout_max)
482
483MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
484MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
485MODULE_LICENSE("GPL");
486
487module_param_call(nlm_grace_period, param_set_grace_period, param_get_ulong,
488		  &nlm_grace_period, 0644);
489module_param_call(nlm_timeout, param_set_timeout, param_get_ulong,
490		  &nlm_timeout, 0644);
491module_param_call(nlm_udpport, param_set_port, param_get_int,
492		  &nlm_udpport, 0644);
493module_param_call(nlm_tcpport, param_set_port, param_get_int,
494		  &nlm_tcpport, 0644);
495module_param(nsm_use_hostnames, bool, 0644);
496
497/*
498 * Initialising and terminating the module.
499 */
500
501static int __init init_nlm(void)
502{
503	nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
504	return nlm_sysctl_table ? 0 : -ENOMEM;
505}
506
507static void __exit exit_nlm(void)
508{
509	nlm_shutdown_hosts();
510	unregister_sysctl_table(nlm_sysctl_table);
511}
512
513module_init(init_nlm);
514module_exit(exit_nlm);
515
516/*
517 * Define NLM program and procedures
518 */
519static struct svc_version	nlmsvc_version1 = {
520		.vs_vers	= 1,
521		.vs_nproc	= 17,
522		.vs_proc	= nlmsvc_procedures,
523		.vs_xdrsize	= NLMSVC_XDRSIZE,
524};
525static struct svc_version	nlmsvc_version3 = {
526		.vs_vers	= 3,
527		.vs_nproc	= 24,
528		.vs_proc	= nlmsvc_procedures,
529		.vs_xdrsize	= NLMSVC_XDRSIZE,
530};
531#ifdef CONFIG_LOCKD_V4
532static struct svc_version	nlmsvc_version4 = {
533		.vs_vers	= 4,
534		.vs_nproc	= 24,
535		.vs_proc	= nlmsvc_procedures4,
536		.vs_xdrsize	= NLMSVC_XDRSIZE,
537};
538#endif
539static struct svc_version *	nlmsvc_version[] = {
540	[1] = &nlmsvc_version1,
541	[3] = &nlmsvc_version3,
542#ifdef CONFIG_LOCKD_V4
543	[4] = &nlmsvc_version4,
544#endif
545};
546
547static struct svc_stat		nlmsvc_stats;
548
549#define NLM_NRVERS	ARRAY_SIZE(nlmsvc_version)
550static struct svc_program	nlmsvc_program = {
551	.pg_prog		= NLM_PROGRAM,		/* program number */
552	.pg_nvers		= NLM_NRVERS,		/* number of entries in nlmsvc_version */
553	.pg_vers		= nlmsvc_version,	/* version table */
554	.pg_name		= "lockd",		/* service name */
555	.pg_class		= "nfsd",		/* share authentication with nfsd */
556	.pg_stats		= &nlmsvc_stats,	/* stats table */
557	.pg_authenticate = &lockd_authenticate	/* export authentication */
558};
559