NLM,NFSv4: Wait on local locks before we put RPC calls on the wire
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 29 Jun 2006 20:38:39 +0000 (16:38 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 5 Jul 2006 17:13:18 +0000 (13:13 -0400)
Use FL_ACCESS flag to test and/or wait for local locks before we try
requesting a lock from the server

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/lockd/clntproc.c
fs/nfs/nfs4proc.c

index 24c691f..89ba0df 100644 (file)
@@ -496,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
        struct nlm_host *host = req->a_host;
        struct nlm_res  *resp = &req->a_res;
        struct nlm_wait *block = NULL;
+       unsigned char fl_flags = fl->fl_flags;
        int status = -ENOLCK;
 
        if (!host->h_monitored && nsm_monitor(host) < 0) {
@@ -503,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
                                        host->h_name);
                goto out;
        }
+       fl->fl_flags |= FL_ACCESS;
+       status = do_vfs_lock(fl);
+       if (status < 0)
+               goto out;
 
        block = nlmclnt_prepare_block(host, fl);
 again:
@@ -537,8 +542,8 @@ again:
                        up_read(&host->h_rwsem);
                        goto again;
                }
-               fl->fl_flags |= FL_SLEEP;
                /* Ensure the resulting lock will get added to granted list */
+               fl->fl_flags = fl_flags | FL_SLEEP;
                if (do_vfs_lock(fl) < 0)
                        printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
                up_read(&host->h_rwsem);
@@ -551,6 +556,7 @@ out_unblock:
                nlmclnt_cancel(host, req->a_args.block, fl);
 out:
        nlm_release_call(req);
+       fl->fl_flags = fl_flags;
        return status;
 }
 
index 8bdfe3f..e6ee97f 100644 (file)
@@ -3489,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
 static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
        struct nfs4_client *clp = state->owner->so_client;
+       unsigned char fl_flags = request->fl_flags;
        int status;
 
        /* Is this a delegated open? */
-       if (NFS_I(state->inode)->delegation_state != 0) {
-               /* Yes: cache locks! */
-               status = do_vfs_lock(request->fl_file, request);
-               /* ...but avoid races with delegation recall... */
-               if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags))
-                       return status;
-       }
-       down_read(&clp->cl_sem);
        status = nfs4_set_lock_state(state, request);
        if (status != 0)
                goto out;
+       request->fl_flags |= FL_ACCESS;
+       status = do_vfs_lock(request->fl_file, request);
+       if (status < 0)
+               goto out;
+       down_read(&clp->cl_sem);
+       if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
+               struct nfs_inode *nfsi = NFS_I(state->inode);
+               /* Yes: cache locks! */
+               down_read(&nfsi->rwsem);
+               /* ...but avoid races with delegation recall... */
+               if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
+                       request->fl_flags = fl_flags & ~FL_SLEEP;
+                       status = do_vfs_lock(request->fl_file, request);
+                       up_read(&nfsi->rwsem);
+                       goto out_unlock;
+               }
+               up_read(&nfsi->rwsem);
+       }
        status = _nfs4_do_setlk(state, cmd, request, 0);
        if (status != 0)
-               goto out;
+               goto out_unlock;
        /* Note: we always want to sleep here! */
-       request->fl_flags |= FL_SLEEP;
+       request->fl_flags = fl_flags | FL_SLEEP;
        if (do_vfs_lock(request->fl_file, request) < 0)
                printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
-out:
+out_unlock:
        up_read(&clp->cl_sem);
+out:
+       request->fl_flags = fl_flags;
        return status;
 }