aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2012-03-28 13:56:19 -0400
committerSteve French <sfrench@us.ibm.com>2012-04-01 14:54:27 -0400
commit66189be74ff5f9f3fd6444315b85be210d07cef2 (patch)
tree7a179ddd7e233668dbb108faf847ceb768d2e92c
parent9ebb389d0a03b4415fe9014f6922a2412cb1109c (diff)
CIFS: Fix VFS lock usage for oplocked files
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. Cc: stable@kernel.org Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/file.c10
-rw-r--r--fs/locks.c3
-rw-r--r--include/linux/fs.h5
3 files changed, 16 insertions, 2 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 460d87b7cda0..fae765dac934 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)
835 if ((flock->fl_flags & FL_POSIX) == 0) 835 if ((flock->fl_flags & FL_POSIX) == 0)
836 return rc; 836 return rc;
837 837
838try_again:
838 mutex_lock(&cinode->lock_mutex); 839 mutex_lock(&cinode->lock_mutex);
839 if (!cinode->can_cache_brlcks) { 840 if (!cinode->can_cache_brlcks) {
840 mutex_unlock(&cinode->lock_mutex); 841 mutex_unlock(&cinode->lock_mutex);
841 return rc; 842 return rc;
842 } 843 }
843 rc = posix_lock_file_wait(file, flock); 844
845 rc = posix_lock_file(file, flock, NULL);
844 mutex_unlock(&cinode->lock_mutex); 846 mutex_unlock(&cinode->lock_mutex);
847 if (rc == FILE_LOCK_DEFERRED) {
848 rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
849 if (!rc)
850 goto try_again;
851 locks_delete_block(flock);
852 }
845 return rc; 853 return rc;
846} 854}
847 855
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)
510 510
511/* 511/*
512 */ 512 */
513static void locks_delete_block(struct file_lock *waiter) 513void locks_delete_block(struct file_lock *waiter)
514{ 514{
515 lock_flocks(); 515 lock_flocks();
516 __locks_delete_block(waiter); 516 __locks_delete_block(waiter);
517 unlock_flocks(); 517 unlock_flocks();
518} 518}
519EXPORT_SYMBOL(locks_delete_block);
519 520
520/* Insert waiter into blocker's block list. 521/* Insert waiter into blocker's block list.
521 * We use a circular list so that processes can be easily woken up in 522 * We use a circular list so that processes can be easily woken up in
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 135693e79f2b..528611843ba0 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1215,6 +1215,7 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
1215extern int lease_modify(struct file_lock **, int); 1215extern int lease_modify(struct file_lock **, int);
1216extern int lock_may_read(struct inode *, loff_t start, unsigned long count); 1216extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
1217extern int lock_may_write(struct inode *, loff_t start, unsigned long count); 1217extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
1218extern void locks_delete_block(struct file_lock *waiter);
1218extern void lock_flocks(void); 1219extern void lock_flocks(void);
1219extern void unlock_flocks(void); 1220extern void unlock_flocks(void);
1220#else /* !CONFIG_FILE_LOCKING */ 1221#else /* !CONFIG_FILE_LOCKING */
@@ -1359,6 +1360,10 @@ static inline int lock_may_write(struct inode *inode, loff_t start,
1359 return 1; 1360 return 1;
1360} 1361}
1361 1362
1363static inline void locks_delete_block(struct file_lock *waiter)
1364{
1365}
1366
1362static inline void lock_flocks(void) 1367static inline void lock_flocks(void)
1363{ 1368{
1364} 1369}