summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2012-03-28 21:56:19 +0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-04-13 09:13:54 -0700
commit49c8ca7ade694f65de205adc08c23a710244b6b0 (patch)
tree7567a9aea2a5b2cf1d9cf8b34cfb52f1b0f8e21f /fs
parentc9f568f1a99794aa7b749828c41fb7cdf55fe435 (diff)
downloadlwn-49c8ca7ade694f65de205adc08c23a710244b6b0.tar.gz
lwn-49c8ca7ade694f65de205adc08c23a710244b6b0.zip
CIFS: Fix VFS lock usage for oplocked files
commit 66189be74ff5f9f3fd6444315b85be210d07cef2 upstream. We can deadlock if we have a write oplock and two processes use the same file handle. In this case the first process can't unlock its lock if the second process blocked on the lock in the same time. Fix it by using posix_lock_file rather than posix_lock_file_wait under cinode->lock_mutex. If we request a blocking lock and posix_lock_file indicates that there is another lock that prevents us, wait untill that lock is released and restart our call. Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <sfrench@us.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/file.c10
-rw-r--r--fs/locks.c3
2 files changed, 11 insertions, 2 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 159fcc56dc2d..0f7dc228c10a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -835,13 +835,21 @@ cifs_posix_lock_set(struct file *file, struct file_lock *flock)
if ((flock->fl_flags & FL_POSIX) == 0)
return rc;
+try_again:
mutex_lock(&cinode->lock_mutex);
if (!cinode->can_cache_brlcks) {
mutex_unlock(&cinode->lock_mutex);
return rc;
}
- rc = posix_lock_file_wait(file, flock);
+
+ rc = posix_lock_file(file, flock, NULL);
mutex_unlock(&cinode->lock_mutex);
+ if (rc == FILE_LOCK_DEFERRED) {
+ rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
+ if (!rc)
+ goto try_again;
+ locks_delete_block(flock);
+ }
return rc;
}
diff --git a/fs/locks.c b/fs/locks.c
index 637694bf3a03..0d68f1f81799 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -510,12 +510,13 @@ static void __locks_delete_block(struct file_lock *waiter)
/*
*/
-static void locks_delete_block(struct file_lock *waiter)
+void locks_delete_block(struct file_lock *waiter)
{
lock_flocks();
__locks_delete_block(waiter);
unlock_flocks();
}
+EXPORT_SYMBOL(locks_delete_block);
/* Insert waiter into blocker's block list.
* We use a circular list so that processes can be easily woken up in