Skip to content

Commit

Permalink
[PATCH] NLM: Fix the NLM_GRANTED callback checks
Browse files Browse the repository at this point in the history
If 2 threads attached to the same process are blocking on different locks on
different files (maybe even on different servers) but have the same lock
arguments (i.e.  same offset+length - actually quite common, since most
processes try to lock the entire file) then the first GRANTED call that wakes
one up will also wake the other.

Currently when the NLM_GRANTED callback comes in, lockd walks the list of
blocked locks in search of a match to the lock that the NLM server has
granted.  Although it checks the lock pid, start and end, it fails to check
the filehandle and the server address.

By checking the filehandle and server IP address, we ensure that this only
happens if the locks truly are referencing the same file.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Trond Myklebust authored and Linus Torvalds committed Feb 15, 2006
1 parent 7c8903f commit 5ac5f9d
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 15 deletions.
27 changes: 17 additions & 10 deletions fs/lockd/clntlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ long nlmclnt_block(struct nlm_rqst *req, long timeout)
/*
* The server lockd has called us back to tell us the lock was granted
*/
u32
nlmclnt_grant(struct nlm_lock *lock)
u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
{
const struct file_lock *fl = &lock->fl;
const struct nfs_fh *fh = &lock->fh;
struct nlm_wait *block;
u32 res = nlm_lck_denied;

Expand All @@ -122,14 +123,20 @@ nlmclnt_grant(struct nlm_lock *lock)
* Warning: must not use cookie to match it!
*/
list_for_each_entry(block, &nlm_blocked, b_list) {
if (nlm_compare_locks(block->b_lock, &lock->fl)) {
/* Alright, we found a lock. Set the return status
* and wake up the caller
*/
block->b_status = NLM_LCK_GRANTED;
wake_up(&block->b_wait);
res = nlm_granted;
}
struct file_lock *fl_blocked = block->b_lock;

if (!nlm_compare_locks(fl_blocked, fl))
continue;
if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
continue;
if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_dentry->d_inode) ,fh) != 0)
continue;
/* Alright, we found a lock. Set the return status
* and wake up the caller
*/
block->b_status = NLM_LCK_GRANTED;
wake_up(&block->b_wait);
res = nlm_granted;
}
return res;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/lockd/svc4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;

dprintk("lockd: GRANTED called\n");
resp->status = nlmclnt_grant(&argp->lock);
resp->status = nlmclnt_grant(&rqstp->rq_addr, &argp->lock);
dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
return rpc_success;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/lockd/svcproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;

dprintk("lockd: GRANTED called\n");
resp->status = nlmclnt_grant(&argp->lock);
resp->status = nlmclnt_grant(&rqstp->rq_addr, &argp->lock);
dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
return rpc_success;
}
Expand Down
6 changes: 3 additions & 3 deletions include/linux/lockd/lockd.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ struct nlm_rqst * nlmclnt_alloc_call(void);
int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl);
void nlmclnt_finish_block(struct nlm_rqst *req);
long nlmclnt_block(struct nlm_rqst *req, long timeout);
u32 nlmclnt_grant(struct nlm_lock *);
u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
void nlmclnt_recovery(struct nlm_host *, u32);
int nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
int nlmclnt_setgrantargs(struct nlm_rqst *, struct nlm_lock *);
Expand Down Expand Up @@ -204,7 +204,7 @@ nlmsvc_file_inode(struct nlm_file *file)
* Compare two host addresses (needs modifying for ipv6)
*/
static __inline__ int
nlm_cmp_addr(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
nlm_cmp_addr(const struct sockaddr_in *sin1, const struct sockaddr_in *sin2)
{
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
}
Expand All @@ -214,7 +214,7 @@ nlm_cmp_addr(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
* When the second lock is of type F_UNLCK, this acts like a wildcard.
*/
static __inline__ int
nlm_compare_locks(struct file_lock *fl1, struct file_lock *fl2)
nlm_compare_locks(const struct file_lock *fl1, const struct file_lock *fl2)
{
return fl1->fl_pid == fl2->fl_pid
&& fl1->fl_start == fl2->fl_start
Expand Down

0 comments on commit 5ac5f9d

Please sign in to comment.