NLM: Further cancel fixes
authorJ. Bruce Fields <bfields@fieldses.org>
Tue, 3 Jan 2006 08:55:46 +0000 (09:55 +0100)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 6 Jan 2006 19:58:54 +0000 (14:58 -0500)
 If the server receives an NLM cancel call and finds no waiting lock to
 cancel, then chances are the lock has already been applied, and the client
 just hadn't yet processed the NLM granted callback before it sent the
 cancel.

 The Open Group text, for example, perimts a server to return either success
 (LCK_GRANTED) or failure (LCK_DENIED) in this case.  But returning an error
 seems more helpful; the client may be able to use it to recognize that a
 race has occurred and to recover from the race.

 So, modify the relevant functions to return an error in this case.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/lockd/svclock.c
fs/locks.c
include/linux/fs.h

index b56d439bad8297339c36a432d233d0b27fd57c1f..9cfced65d4a2f5bba1525a3b9e20fb14f150414d 100644 (file)
@@ -227,25 +227,27 @@ failed:
  * It is the caller's responsibility to check whether the file
  * can be closed hereafter.
  */
-static void
+static int
 nlmsvc_delete_block(struct nlm_block *block, int unlock)
 {
        struct file_lock        *fl = &block->b_call.a_args.lock.fl;
        struct nlm_file         *file = block->b_file;
        struct nlm_block        **bp;
+       int status = 0;
 
        dprintk("lockd: deleting block %p...\n", block);
 
        /* Remove block from list */
        nlmsvc_remove_block(block);
-       posix_unblock_lock(file->f_file, fl);
+       if (unlock)
+               status = posix_unblock_lock(file->f_file, fl);
 
        /* If the block is in the middle of a GRANT callback,
         * don't kill it yet. */
        if (block->b_incall) {
                nlmsvc_insert_block(block, NLM_NEVER);
                block->b_done = 1;
-               return;
+               return status;
        }
 
        /* Remove block from file's list of blocks */
@@ -260,6 +262,7 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock)
                nlm_release_host(block->b_host);
        nlmclnt_freegrantargs(&block->b_call);
        kfree(block);
+       return status;
 }
 
 /*
@@ -270,6 +273,7 @@ int
 nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
 {
        struct nlm_block        *block, *next;
+       /* XXX: Will everything get cleaned up if we don't unlock here? */
 
        down(&file->f_sema);
        for (block = file->f_blocks; block; block = next) {
@@ -439,6 +443,7 @@ u32
 nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
 {
        struct nlm_block        *block;
+       int status = 0;
 
        dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n",
                                file->f_file->f_dentry->d_inode->i_sb->s_id,
@@ -449,9 +454,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
 
        down(&file->f_sema);
        if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
-               nlmsvc_delete_block(block, 1);
+               status = nlmsvc_delete_block(block, 1);
        up(&file->f_sema);
-       return nlm_granted;
+       return status ? nlm_lck_denied : nlm_granted;
 }
 
 /*
index 75650d52fe60a126cdfbb523f039dc08f9954855..fb32d6218e213e3e31c5fe000dcb5ef362b3f176 100644 (file)
@@ -1958,13 +1958,18 @@ EXPORT_SYMBOL(posix_block_lock);
  *
  *     lockd needs to block waiting for locks.
  */
-void
+int
 posix_unblock_lock(struct file *filp, struct file_lock *waiter)
 {
+       int status = 0;
+
        lock_kernel();
        if (waiter->fl_next)
                __locks_delete_block(waiter);
+       else
+               status = -ENOENT;
        unlock_kernel();
+       return status;
 }
 
 EXPORT_SYMBOL(posix_unblock_lock);
index 115e72be25d0cd7b7a7436e4d82f389b7cbf7c8f..2c9c48d65630ed68464f377f8e2578e88f2497bf 100644 (file)
@@ -760,7 +760,7 @@ extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
 extern int posix_lock_file(struct file *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern void posix_block_lock(struct file_lock *, struct file_lock *);
-extern void posix_unblock_lock(struct file *, struct file_lock *);
+extern int posix_unblock_lock(struct file *, struct file_lock *);
 extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags);