summaryrefslogtreecommitdiffstats
path: root/fs/lockd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/lockd')
-rw-r--r--fs/lockd/clntproc.c34
-rw-r--r--fs/lockd/svc.c24
-rw-r--r--fs/lockd/svcsubs.c64
3 files changed, 78 insertions, 44 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index c25a19c97..d0c70c276 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -90,7 +90,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
struct nfs_server *nfssrv = NFS_SERVER(inode);
struct nlm_host *host;
struct nlm_rqst reqst, *call = &reqst;
- unsigned long oldmask;
+ sigset_t oldset;
+ unsigned long flags;
int status;
/* Always use NLM version 1 over UDP for now... */
@@ -114,16 +115,21 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
}
/* Keep the old signal mask */
- oldmask = current->blocked;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ oldset = current->blocked;
/* If we're cleaning up locks because the process is exiting,
* perform the RPC call asynchronously. */
if (cmd == F_SETLK && fl->fl_type == F_UNLCK
- && (current->flags & PF_EXITING)) {
- current->blocked = ~0UL; /* Mask all signals */
+ && (current->flags & PF_EXITING)) {
+ sigfillset(&current->blocked); /* Mask all signals */
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
call = nlmclnt_alloc_call();
call->a_flags = RPC_TASK_ASYNC;
} else {
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
call->a_flags = 0;
}
call->a_host = host;
@@ -145,7 +151,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
rpc_free(call);
- current->blocked = oldmask;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ current->blocked = oldset;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
done:
dprintk("lockd: clnt proc returns %d\n", status);
@@ -454,11 +463,16 @@ int
nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
{
struct nlm_rqst *req;
- unsigned long oldmask = current->blocked;
+ unsigned long flags;
+ sigset_t oldset;
int status;
/* Block all signals while setting up call */
- current->blocked = ~0UL;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ oldset = current->blocked;
+ sigfillset(&current->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
do {
req = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
@@ -474,7 +488,11 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
if (status < 0)
rpc_free(req);
- current->blocked = oldmask;
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ current->blocked = oldset;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
return status;
}
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index c5f77ef89..e649cf633 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -37,8 +37,7 @@
#define NLMDBG_FACILITY NLMDBG_SVC
#define LOCKD_BUFSIZE (1024 + NLMSSVC_XDRSIZE)
-#define BLOCKABLE_SIGS (~(_S(SIGKILL) | _S(SIGSTOP)))
-#define _S(sig) (1 << ((sig) - 1))
+#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern struct svc_program nlmsvc_program;
struct nlmsvc_binding * nlmsvc_ops = NULL;
@@ -65,7 +64,6 @@ static void
lockd(struct svc_rqst *rqstp)
{
struct svc_serv *serv = rqstp->rq_server;
- sigset_t oldsigmask;
int err = 0;
/* Lock module and set up kernel thread */
@@ -118,8 +116,11 @@ lockd(struct svc_rqst *rqstp)
*/
while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
{
- if (signalled())
- current->signal = 0;
+ if (signalled()) {
+ spin_lock_irq(&current->sigmask_lock);
+ flush_signals(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ }
/*
* Retry any blocked locks that have been notified by
@@ -162,10 +163,17 @@ lockd(struct svc_rqst *rqstp)
}
/* Process request with all signals blocked. */
- oldsigmask = current->blocked;
- current->blocked = BLOCKABLE_SIGS;
+ spin_lock_irq(&current->sigmask_lock);
+ siginitsetinv(&current->blocked, ~BLOCKABLE_SIGS);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
svc_process(serv, rqstp);
- current->blocked = oldsigmask;
+
+ spin_lock_irq(&current->sigmask_lock);
+ sigemptyset(&current->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
/* Unlock export hash tables */
if (nlmsvc_ops)
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 0c2380de3..ce405d8d5 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -24,24 +24,25 @@
* Global file hash table
*/
#define FILE_NRHASH 32
-#define FILE_HASH(dhash) ((dhash) & FILE_NRHASH)
+#define FILE_HASH_BITS 5
static struct nlm_file * nlm_files[FILE_NRHASH];
static struct semaphore nlm_file_sema = MUTEX;
+static unsigned int file_hash(dev_t dev, ino_t ino)
+{
+ unsigned long tmp = (unsigned long) ino | (unsigned long) dev;
+ tmp = tmp + (tmp >> FILE_HASH_BITS) + (tmp >> FILE_HASH_BITS*2);
+ return tmp & (FILE_NRHASH - 1);
+}
+
/*
* 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,
@@ -49,40 +50,38 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
{
struct nlm_file *file;
struct knfs_fh *fh = (struct knfs_fh *) f;
- struct dentry *dentry = fh->fh_dcookie;
- unsigned int hash = FILE_HASH(dentry->d_name.hash);
+ unsigned int hash = file_hash(fh->fh_dev, fh->fh_ino);
u32 nfserr;
- dprintk("lockd: nlm_file_lookup(%s/%s)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+ dprintk("lockd: nlm_file_lookup(%s/%ld)\n",
+ kdevname(fh->fh_dev), fh->fh_ino);
/* Lock file table */
down(&nlm_file_sema);
for (file = nlm_files[hash]; file; file = file->f_next) {
- if (file->f_handle.fh_dcookie == dentry
- && !memcmp(&file->f_handle, fh, sizeof(*fh)))
+ if (file->f_handle.fh_dcookie == fh->fh_dcookie &&
+ !memcmp(&file->f_handle, fh, sizeof(*fh)))
goto found;
}
- 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;
- }
+ dprintk("lockd: creating file for %s/%ld\n",
+ kdevname(fh->fh_dev), fh->fh_ino);
+ nfserr = nlm_lck_denied_nolocks;
+ file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL);
+ if (!file)
+ goto out_unlock;
memset(file, 0, sizeof(*file));
file->f_handle = *fh;
file->f_sema = MUTEX;
/* Open the file. Note that this must not sleep for too long, else
- * we would lock up lockd:-) So no NFS re-exports, folks. */
+ * we would lock up lockd:-) So no NFS re-exports, folks.
+ */
if ((nfserr = nlmsvc_ops->fopen(rqstp, fh, &file->f_file)) != 0) {
dprintk("lockd: open failed (nfserr %ld)\n", ntohl(nfserr));
- kfree(file);
- up(&nlm_file_sema);
- return nlm_lck_denied;
+ goto out_free;
}
file->f_next = nlm_files[hash];
@@ -91,9 +90,17 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
found:
dprintk("lockd: found file %p (count %d)\n", file, file->f_count);
*result = file;
- up(&nlm_file_sema);
file->f_count++;
- return 0;
+ nfserr = 0;
+
+out_unlock:
+ up(&nlm_file_sema);
+ return nfserr;
+
+out_free:
+ kfree(file);
+ nfserr = nlm_lck_denied;
+ goto out_unlock;
}
/*
@@ -102,11 +109,12 @@ found:
static inline void
nlm_delete_file(struct nlm_file *file)
{
- struct dentry *dentry = file->f_file.f_dentry;
+ struct inode *inode = file->f_file.f_dentry->d_inode;
struct nlm_file **fp, *f;
- dprintk("lockd: closing file %p\n", dentry);
- fp = nlm_files + FILE_HASH(dentry->d_name.hash);
+ dprintk("lockd: closing file %s/%ld\n",
+ kdevname(inode->i_dev), inode->i_ino);
+ fp = nlm_files + file_hash(inode->i_dev, inode->i_ino);
while ((f = *fp) != NULL) {
if (f == file) {
*fp = file->f_next;