Commit d751a7cd authored by Jeff Layton's avatar Jeff Layton Committed by J. Bruce Fields

NLM: Convert lockd to use kthreads

Have lockd_up start lockd using kthread_run. With this change,
lockd_down now blocks until lockd actually exits, so there's no longer
need for the waitqueue code at the end of lockd_down. This also means
that only one lockd can be running at a time which simplifies the code
within lockd's main loop.

This also adds a check for kthread_should_stop in the main loop of
nlmsvc_retry_blocked and after that function returns. There's no sense
continuing to retry blocks if lockd is coming down anyway.
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
parent 7086721f
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/sunrpc/types.h> #include <linux/sunrpc/types.h>
...@@ -48,14 +49,11 @@ EXPORT_SYMBOL(nlmsvc_ops); ...@@ -48,14 +49,11 @@ EXPORT_SYMBOL(nlmsvc_ops);
static DEFINE_MUTEX(nlmsvc_mutex); static DEFINE_MUTEX(nlmsvc_mutex);
static unsigned int nlmsvc_users; static unsigned int nlmsvc_users;
static pid_t nlmsvc_pid; static struct task_struct *nlmsvc_task;
static struct svc_serv *nlmsvc_serv; static struct svc_serv *nlmsvc_serv;
int nlmsvc_grace_period; int nlmsvc_grace_period;
unsigned long nlmsvc_timeout; unsigned long nlmsvc_timeout;
static DECLARE_COMPLETION(lockd_start_done);
static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
/* /*
* These can be set at insmod time (useful for NFS as root filesystem), * These can be set at insmod time (useful for NFS as root filesystem),
* and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003
...@@ -111,35 +109,30 @@ static inline void clear_grace_period(void) ...@@ -111,35 +109,30 @@ static inline void clear_grace_period(void)
/* /*
* This is the lockd kernel thread * This is the lockd kernel thread
*/ */
static void static int
lockd(struct svc_rqst *rqstp) lockd(void *vrqstp)
{ {
int err = 0; int err = 0;
struct svc_rqst *rqstp = vrqstp;
unsigned long grace_period_expire; unsigned long grace_period_expire;
/* Lock module and set up kernel thread */ /* try_to_freeze() is called from svc_recv() */
/* lockd_up is waiting for us to startup, so will
* be holding a reference to this module, so it
* is safe to just claim another reference
*/
__module_get(THIS_MODULE);
lock_kernel();
/*
* Let our maker know we're running.
*/
nlmsvc_pid = current->pid;
nlmsvc_serv = rqstp->rq_server;
complete(&lockd_start_done);
daemonize("lockd");
set_freezable(); set_freezable();
/* Process request with signals blocked, but allow SIGKILL. */ /* Allow SIGKILL to tell lockd to drop all of its locks */
allow_signal(SIGKILL); allow_signal(SIGKILL);
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
/*
* FIXME: it would be nice if lockd didn't spend its entire life
* running under the BKL. At the very least, it would be good to
* have someone clarify what it's intended to protect here. I've
* seen some handwavy posts about posix locking needing to be
* done under the BKL, but it's far from clear.
*/
lock_kernel();
if (!nlm_timeout) if (!nlm_timeout)
nlm_timeout = LOCKD_DFLT_TIMEO; nlm_timeout = LOCKD_DFLT_TIMEO;
nlmsvc_timeout = nlm_timeout * HZ; nlmsvc_timeout = nlm_timeout * HZ;
...@@ -148,10 +141,9 @@ lockd(struct svc_rqst *rqstp) ...@@ -148,10 +141,9 @@ lockd(struct svc_rqst *rqstp)
/* /*
* The main request loop. We don't terminate until the last * The main request loop. We don't terminate until the last
* NFS mount or NFS daemon has gone away, and we've been sent a * NFS mount or NFS daemon has gone away.
* signal, or else another process has taken over our job.
*/ */
while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { while (!kthread_should_stop()) {
long timeout = MAX_SCHEDULE_TIMEOUT; long timeout = MAX_SCHEDULE_TIMEOUT;
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
...@@ -161,6 +153,7 @@ lockd(struct svc_rqst *rqstp) ...@@ -161,6 +153,7 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_invalidate_all(); nlmsvc_invalidate_all();
grace_period_expire = set_grace_period(); grace_period_expire = set_grace_period();
} }
continue;
} }
/* /*
...@@ -195,28 +188,19 @@ lockd(struct svc_rqst *rqstp) ...@@ -195,28 +188,19 @@ lockd(struct svc_rqst *rqstp)
} }
flush_signals(current); flush_signals(current);
/*
* Check whether there's a new lockd process before
* shutting down the hosts and clearing the slot.
*/
if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
if (nlmsvc_ops) if (nlmsvc_ops)
nlmsvc_invalidate_all(); nlmsvc_invalidate_all();
nlm_shutdown_hosts(); nlm_shutdown_hosts();
nlmsvc_pid = 0;
unlock_kernel();
nlmsvc_task = NULL;
nlmsvc_serv = NULL; nlmsvc_serv = NULL;
} else
printk(KERN_DEBUG
"lockd: new process, skipping host shutdown\n");
wake_up(&lockd_exit);
/* Exit the RPC thread */ /* Exit the RPC thread */
svc_exit_thread(rqstp); svc_exit_thread(rqstp);
/* Release module */ return 0;
unlock_kernel();
module_put_and_exit(0);
} }
/* /*
...@@ -261,14 +245,15 @@ static int make_socks(struct svc_serv *serv, int proto) ...@@ -261,14 +245,15 @@ static int make_socks(struct svc_serv *serv, int proto)
int int
lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
{ {
struct svc_serv * serv; struct svc_serv *serv;
struct svc_rqst *rqstp;
int error = 0; int error = 0;
mutex_lock(&nlmsvc_mutex); mutex_lock(&nlmsvc_mutex);
/* /*
* Check whether we're already up and running. * Check whether we're already up and running.
*/ */
if (nlmsvc_pid) { if (nlmsvc_serv) {
if (proto) if (proto)
error = make_socks(nlmsvc_serv, proto); error = make_socks(nlmsvc_serv, proto);
goto out; goto out;
...@@ -295,13 +280,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ ...@@ -295,13 +280,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
/* /*
* Create the kernel thread and wait for it to start. * Create the kernel thread and wait for it to start.
*/ */
error = svc_create_thread(lockd, serv); rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]);
if (error) { if (IS_ERR(rqstp)) {
error = PTR_ERR(rqstp);
printk(KERN_WARNING
"lockd_up: svc_rqst allocation failed, error=%d\n",
error);
goto destroy_and_out;
}
svc_sock_update_bufs(serv);
nlmsvc_serv = rqstp->rq_server;
nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name);
if (IS_ERR(nlmsvc_task)) {
error = PTR_ERR(nlmsvc_task);
nlmsvc_task = NULL;
nlmsvc_serv = NULL;
printk(KERN_WARNING printk(KERN_WARNING
"lockd_up: create thread failed, error=%d\n", error); "lockd_up: kthread_run failed, error=%d\n", error);
svc_exit_thread(rqstp);
goto destroy_and_out; goto destroy_and_out;
} }
wait_for_completion(&lockd_start_done);
/* /*
* Note: svc_serv structures have an initial use count of 1, * Note: svc_serv structures have an initial use count of 1,
...@@ -323,37 +323,21 @@ EXPORT_SYMBOL(lockd_up); ...@@ -323,37 +323,21 @@ EXPORT_SYMBOL(lockd_up);
void void
lockd_down(void) lockd_down(void)
{ {
static int warned;
mutex_lock(&nlmsvc_mutex); mutex_lock(&nlmsvc_mutex);
if (nlmsvc_users) { if (nlmsvc_users) {
if (--nlmsvc_users) if (--nlmsvc_users)
goto out; goto out;
} else } else {
printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); printk(KERN_ERR "lockd_down: no users! task=%p\n",
nlmsvc_task);
if (!nlmsvc_pid) { BUG();
if (warned++ == 0)
printk(KERN_WARNING "lockd_down: no lockd running.\n");
goto out;
} }
warned = 0;
kill_proc(nlmsvc_pid, SIGKILL, 1); if (!nlmsvc_task) {
/* printk(KERN_ERR "lockd_down: no lockd running.\n");
* Wait for the lockd process to exit, but since we're holding BUG();
* the lockd semaphore, we can't wait around forever ...
*/
clear_thread_flag(TIF_SIGPENDING);
interruptible_sleep_on_timeout(&lockd_exit, HZ);
if (nlmsvc_pid) {
printk(KERN_WARNING
"lockd_down: lockd failed to exit, clearing pid\n");
nlmsvc_pid = 0;
} }
spin_lock_irq(&current->sighand->siglock); kthread_stop(nlmsvc_task);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
out: out:
mutex_unlock(&nlmsvc_mutex); mutex_unlock(&nlmsvc_mutex);
} }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/lockd/nlm.h> #include <linux/lockd/nlm.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/kthread.h>
#define NLMDBG_FACILITY NLMDBG_SVCLOCK #define NLMDBG_FACILITY NLMDBG_SVCLOCK
...@@ -887,7 +888,7 @@ nlmsvc_retry_blocked(void) ...@@ -887,7 +888,7 @@ nlmsvc_retry_blocked(void)
unsigned long timeout = MAX_SCHEDULE_TIMEOUT; unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
struct nlm_block *block; struct nlm_block *block;
while (!list_empty(&nlm_blocked)) { while (!list_empty(&nlm_blocked) && !kthread_should_stop()) {
block = list_entry(nlm_blocked.next, struct nlm_block, b_list); block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
if (block->b_when == NLM_NEVER) if (block->b_when == NLM_NEVER)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment