From 24e36663c375df577d2dcae437713481ffd6850c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 2 Oct 2006 02:17:45 -0700 Subject: [PATCH] knfsd: be more selective in which sockets lockd listens on Currently lockd listens on UDP always, and TCP if CONFIG_NFSD_TCP is set. However as lockd performs services of the client as well, this is a problem. If CONFIG_NfSD_TCP is not set, and a tcp mount is used, the server will not be able to call back to lockd. So: - add an option to lockd_up saying which protocol is needed - Always open sockets for which an explicit port was given, otherwise only open a socket of the type required - Change nfsd to do one lockd_up per socket rather than one per thread. This - removes the dependancy on CONFIG_NFSD_TCP - means that lockd may open sockets other than at startup - means that lockd will *not* listen on UDP if the only mounts are TCP mount (and nfsd hasn't started). The latter is the only one that concerns me at all - I don't know if this might be a problem with some servers. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/lockd/clntlock.c | 2 +- fs/lockd/svc.c | 47 +++++++++++++++++++++++++++++++++++++++------- fs/nfs/client.c | 3 ++- fs/nfsd/nfssvc.c | 16 ++++++++++------ include/linux/lockd/bind.h | 2 +- 5 files changed, 54 insertions(+), 16 deletions(-) diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index f95cc3f3c42d..6abb465b650f 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -202,7 +202,7 @@ reclaimer(void *ptr) /* This one ensures that our parent doesn't terminate while the * reclaim is in progress */ lock_kernel(); - lockd_up(); + lockd_up(0); nlmclnt_prepare_reclaim(host); /* First, reclaim all locks that have been marked. */ diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 13feba45030e..8d19de6a14dc 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,7 @@ EXPORT_SYMBOL(nlmsvc_ops); static DEFINE_MUTEX(nlmsvc_mutex); static unsigned int nlmsvc_users; static pid_t nlmsvc_pid; +static struct svc_serv *nlmsvc_serv; int nlmsvc_grace_period; unsigned long nlmsvc_timeout; @@ -112,6 +114,7 @@ lockd(struct svc_rqst *rqstp) * Let our maker know we're running. */ nlmsvc_pid = current->pid; + nlmsvc_serv = serv; complete(&lockd_start_done); daemonize("lockd"); @@ -189,6 +192,7 @@ lockd(struct svc_rqst *rqstp) nlmsvc_invalidate_all(); nlm_shutdown_hosts(); nlmsvc_pid = 0; + nlmsvc_serv = NULL; } else printk(KERN_DEBUG "lockd: new process, skipping host shutdown\n"); @@ -205,11 +209,42 @@ lockd(struct svc_rqst *rqstp) module_put_and_exit(0); } + +static int find_socket(struct svc_serv *serv, int proto) +{ + struct svc_sock *svsk; + int found = 0; + list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) + if (svsk->sk_sk->sk_protocol == proto) { + found = 1; + break; + } + return found; +} + +static int make_socks(struct svc_serv *serv, int proto) +{ + /* Make any sockets that are needed but not present. + * If nlm_udpport or nlm_tcpport were set as module + * options, make those sockets unconditionally + */ + int err = 0; + if (proto == IPPROTO_UDP || nlm_udpport) + if (!find_socket(serv, IPPROTO_UDP)) + err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport); + if (err) + return err; + if (proto == IPPROTO_TCP || nlm_tcpport) + if (!find_socket(serv, IPPROTO_TCP)) + err= svc_makesock(serv, IPPROTO_TCP, nlm_tcpport); + return err; +} + /* * Bring up the lockd process if it's not already up. */ int -lockd_up(void) +lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ { static int warned; struct svc_serv * serv; @@ -224,8 +259,10 @@ lockd_up(void) /* * Check whether we're already up and running. */ - if (nlmsvc_pid) + if (nlmsvc_pid) { + error = make_socks(nlmsvc_serv, proto); goto out; + } /* * Sanity check: if there's no pid, @@ -242,11 +279,7 @@ lockd_up(void) goto out; } - if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0 -#ifdef CONFIG_NFSD_TCP - || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0 -#endif - ) { + if ((error = make_socks(serv, proto)) < 0) { if (warned++ == 0) printk(KERN_WARNING "lockd_up: makesock failed, error=%d\n", error); diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ec1938d4b814..8106f3b29e4a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -460,7 +460,8 @@ static int nfs_start_lockd(struct nfs_server *server) goto out; if (server->flags & NFS_MOUNT_NONLM) goto out; - error = lockd_up(); + error = lockd_up((server->flags & NFS_MOUNT_TCP) ? + IPPROTO_TCP : IPPROTO_UDP); if (error < 0) server->flags |= NFS_MOUNT_NONLM; else diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index c52c99964a4c..0339b4ddfa3b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -134,6 +134,9 @@ static int killsig; /* signal that was used to kill last nfsd */ static void nfsd_last_thread(struct svc_serv *serv) { /* When last nfsd thread exits we need to do some clean-up */ + struct svc_sock *svsk; + list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) + lockd_down(); nfsd_serv = NULL; nfsd_racache_shutdown(); nfs4_state_shutdown(); @@ -218,11 +221,16 @@ nfsd_svc(unsigned short port, int nrservs) error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); if (error < 0) goto failure; - + error = lockd_up(IPPROTO_UDP); + if (error < 0) + goto failure; #ifdef CONFIG_NFSD_TCP error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); if (error < 0) goto failure; + error = lockd_up(IPPROTO_TCP); + if (error < 0) + goto failure; #endif do_gettimeofday(&nfssvc_boot); /* record boot time */ } else @@ -306,8 +314,6 @@ nfsd(struct svc_rqst *rqstp) nfsdstats.th_cnt++; - lockd_up(); /* start lockd */ - me.task = current; list_add(&me.list, &nfsd_list); @@ -364,13 +370,11 @@ nfsd(struct svc_rqst *rqstp) break; killsig = signo; } - /* Clear signals before calling lockd_down() and svc_exit_thread() */ + /* Clear signals before calling svc_exit_thread() */ flush_signals(current); lock_kernel(); - /* Release lockd */ - lockd_down(); list_del(&me.list); nfsdstats.th_cnt --; diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index b054debef2e0..81e3a185f951 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h @@ -30,7 +30,7 @@ extern struct nlmsvc_binding * nlmsvc_ops; * Functions exported by the lockd module */ extern int nlmclnt_proc(struct inode *, int, struct file_lock *); -extern int lockd_up(void); +extern int lockd_up(int proto); extern void lockd_down(void); #endif /* LINUX_LOCKD_BIND_H */ -- cgit v1.2.3