From 230e5ab6a084ed50470f101934782dbf54b0d06b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 6 Dec 1997 23:51:34 +0000 Subject: Merge with Linux 2.1.67. --- fs/lockd/clntproc.c | 8 ++- fs/lockd/svc.c | 141 ++++++++++++++++++++++++++++++++++++++++++---------- fs/lockd/svcsubs.c | 17 +++++-- 3 files changed, 133 insertions(+), 33 deletions(-) (limited to 'fs/lockd') diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index d219de5ea..c25a19c97 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -160,8 +160,9 @@ static inline int nlmclnt_grace_wait(struct nlm_host *host) { if (!host->h_reclaiming) - current->timeout = 10 * HZ; + current->timeout = jiffies + 10 * HZ; interruptible_sleep_on(&host->h_gracewait); + current->timeout = 0; return signalled()? -ERESTARTSYS : 0; } @@ -178,9 +179,11 @@ nlmclnt_alloc_call(void) sizeof(struct nlm_rqst)); if (call) return call; - current->timeout = 5 * HZ; + printk("nlmclnt_alloc_call: failed, waiting for memory\n"); + current->timeout = jiffies + 5 * HZ; current->state = TASK_INTERRUPTIBLE; schedule(); + current->timeout = 0; } return NULL; } @@ -232,6 +235,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) /* Back off a little and try again */ current->timeout = jiffies + 15 * HZ; interruptible_sleep_on(&host->h_gracewait); + current->timeout = 0; } while (!signalled()); return -ERESTARTSYS; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index fc133b51e..c5f77ef89 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -42,11 +42,15 @@ extern struct svc_program nlmsvc_program; struct nlmsvc_binding * nlmsvc_ops = NULL; -static int nlmsvc_sema = 0; -static int nlmsvc_pid = 0; +static struct semaphore nlmsvc_sema = MUTEX; +static unsigned int nlmsvc_users = 0; +static pid_t nlmsvc_pid = 0; unsigned long nlmsvc_grace_period = 0; unsigned long nlmsvc_timeout = 0; +static struct wait_queue * lockd_start = NULL; +static struct wait_queue * lockd_exit = NULL; + /* * Currently the following can be set only at insmod time. * Ideally, they would be accessible through the sysctl interface. @@ -64,10 +68,16 @@ lockd(struct svc_rqst *rqstp) sigset_t oldsigmask; int err = 0; - lock_kernel(); /* Lock module and set up kernel thread */ MOD_INC_USE_COUNT; - /* exit_files(current); */ + lock_kernel(); + + /* + * Let our maker know we're running. + */ + nlmsvc_pid = current->pid; + wake_up(&lockd_start); + exit_mm(current); current->session = 1; current->pgrp = 1; @@ -76,6 +86,12 @@ lockd(struct svc_rqst *rqstp) /* kick rpciod */ rpciod_up(); + /* + * N.B. current do_fork() doesn't like NULL task->files, + * so we defer closing files until forking rpciod. + */ + exit_files(current); + dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); if (!nlm_timeout) @@ -94,14 +110,14 @@ lockd(struct svc_rqst *rqstp) nlmsvc_grace_period += jiffies; nlmsvc_timeout = nlm_timeout * HZ; - nlmsvc_pid = current->pid; /* * 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 - * signal. + * signal, or else another process has taken over our job. */ - while (nlmsvc_sema || !signalled()) { + while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) + { if (signalled()) current->signal = 0; @@ -156,8 +172,17 @@ lockd(struct svc_rqst *rqstp) nlmsvc_ops->exp_unlock(); } - nlm_shutdown_hosts(); - + /* + * Check whether there's a new lockd process before + * shutting down the hosts and clearing the slot. + */ + if (!nlmsvc_pid || current->pid == nlmsvc_pid) { + nlm_shutdown_hosts(); + nlmsvc_pid = 0; + } else + printk("lockd: new process, skipping host shutdown\n"); + wake_up(&lockd_exit); + /* Exit the RPC thread */ svc_exit_thread(rqstp); @@ -166,7 +191,6 @@ lockd(struct svc_rqst *rqstp) /* Release module */ MOD_DEC_USE_COUNT; - nlmsvc_pid = 0; } /* @@ -185,42 +209,100 @@ lockd_makesock(struct svc_serv *serv, int protocol, unsigned short port) return svc_create_socket(serv, protocol, &sin); } +/* + * Bring up the lockd process if it's not already up. + */ int lockd_up(void) { struct svc_serv * serv; - int error; + int error = 0; - if (nlmsvc_pid || nlmsvc_sema++) - return 0; + down(&nlmsvc_sema); + /* + * Unconditionally increment the user count ... this is + * the number of clients who _want_ a lockd process. + */ + nlmsvc_users++; + /* + * Check whether we're already up and running. + */ + if (nlmsvc_pid) + goto out; - dprintk("lockd: creating service\n"); - if ((serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE)) == NULL) - return -ENOMEM; + /* + * Sanity check: if there's no pid, + * we should be the first user ... + */ + if (nlmsvc_users > 1) + printk("lockd_up: no pid, %d users??\n", nlmsvc_users); + + error = -ENOMEM; + serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE); + if (!serv) { + printk("lockd_up: create service failed\n"); + goto out; + } - if ((error = lockd_makesock(serv, IPPROTO_UDP, 0)) < 0 + if ((error = lockd_makesock(serv, IPPROTO_UDP, 0)) < 0 || (error = lockd_makesock(serv, IPPROTO_TCP, 0)) < 0) { - svc_destroy(serv); - return error; + printk("lockd_up: makesock failed, error=%d\n", error); + goto destroy_and_out; } - if ((error = svc_create_thread(lockd, serv)) < 0) - nlmsvc_sema--; + /* + * Create the kernel thread and wait for it to start. + */ + error = svc_create_thread(lockd, serv); + if (error) { + printk("lockd_up: create thread failed, error=%d\n", error); + goto destroy_and_out; + } + sleep_on(&lockd_start); - /* Release server */ + /* + * Note: svc_serv structures have an initial use count of 1, + * so we exit through here on both success and failure. + */ +destroy_and_out: svc_destroy(serv); - return 0; +out: + up(&nlmsvc_sema); + return error; } +/* + * Decrement the user count and bring down lockd if we're the last. + */ void lockd_down(void) { - if (!nlmsvc_pid || --nlmsvc_sema > 0) - return; + down(&nlmsvc_sema); + if (nlmsvc_users) { + if (--nlmsvc_users) + goto out; + } else + printk("lockd_down: no users! pid=%d\n", nlmsvc_pid); + + if (!nlmsvc_pid) { + printk("lockd_down: nothing to do!\n"); + goto out; + } kill_proc(nlmsvc_pid, SIGKILL, 1); - nlmsvc_sema = 0; - nlmsvc_pid = 0; + /* + * Wait for the lockd process to exit, but since we're holding + * the lockd semaphore, we can't wait around forever ... + */ + current->timeout = jiffies + 5 * HZ; + interruptible_sleep_on(&lockd_exit); + current->timeout = 0; + if (nlmsvc_pid) { + printk("lockd_down: lockd failed to exit, clearing pid\n"); + nlmsvc_pid = 0; + } +out: + up(&nlmsvc_sema); } #ifdef MODULE @@ -235,6 +317,11 @@ lockd_down(void) int init_module(void) { + /* Init the static variables */ + nlmsvc_sema = MUTEX; + nlmsvc_users = 0; + nlmsvc_pid = 0; + lockd_exit = NULL; nlmxdr_init(); return 0; } diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 3526867ca..0c2380de3 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -32,10 +32,16 @@ static struct semaphore nlm_file_sema = MUTEX; * Lookup file info. If it doesn't exist, create a file info struct * and open a (VFS) file for the given inode. * + * The NFS filehandle must have been validated prior to this call, + * as we assume that the dentry pointer is valid. + * * FIXME: * Note that we open the file O_RDONLY even when creating write locks. * This is not quite right, but for now, we assume the client performs * the proper R/W checking. + * + * The dentry in the FH may not be validated .. can we call this with + * the full svc_fh? */ u32 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, @@ -43,21 +49,24 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, { struct nlm_file *file; struct knfs_fh *fh = (struct knfs_fh *) f; - unsigned int hash = FILE_HASH(fh->fh_dhash); + struct dentry *dentry = fh->fh_dcookie; + unsigned int hash = FILE_HASH(dentry->d_name.hash); u32 nfserr; - dprintk("lockd: nlm_file_lookup(%p)\n", fh->fh_dentry); + dprintk("lockd: nlm_file_lookup(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); /* Lock file table */ down(&nlm_file_sema); for (file = nlm_files[hash]; file; file = file->f_next) { - if (file->f_handle.fh_dentry == fh->fh_dentry + if (file->f_handle.fh_dcookie == dentry && !memcmp(&file->f_handle, fh, sizeof(*fh))) goto found; } - dprintk("lockd: creating file for %p\n", fh->fh_dentry); + dprintk("lockd: creating file for %s/%s\n", + dentry->d_parent->d_name.name, dentry->d_name.name); if (!(file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL))) { up(&nlm_file_sema); return nlm_lck_denied_nolocks; -- cgit v1.2.3