[PATCH] NLM: Fix the NLM_GRANTED callback checks
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 14 Feb 2006 21:53:04 +0000 (13:53 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 15 Feb 2006 00:09:34 +0000 (16:09 -0800)
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>
fs/lockd/clntlock.c
fs/lockd/svc4proc.c
fs/lockd/svcproc.c
include/linux/lockd/lockd.h

index 3eaf6e70108781fec63c61a32141b435532faae3..da6354baa0b804b36d2778282b31bc5ae8e2d858 100644 (file)
@@ -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;
 
@@ -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;
 }
index 4063095d849e0280ceecbeb4d510a600810b7797..b10f913aa06ae44f7d797920ed9e981b610caa5d 100644 (file)
@@ -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;
 }
index 3bc437e0cf5b6f0d6618c806fc9f835b084dbc52..35681d9cf1fcf52ca816249221a5b4c48b293c4e 100644 (file)
@@ -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;
 }
index 920766cea79cbc15634411e4c9633c27f6c8fd61..ef21ed296039dc87527c3eb777992851e0774bcf 100644 (file)
@@ -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 *);
@@ -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;
 }
@@ -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