Commit 2d5e264758e31dd1d1e609a5a4d3d6dc693b9d2e

Authored by Pavel Shilovsky
Committed by Greg Kroah-Hartman
1 parent fdf8d98d89

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>

Showing 3 changed files with 16 additions and 2 deletions Side-by-side Diff

... ... @@ -835,13 +835,21 @@
835 835 if ((flock->fl_flags & FL_POSIX) == 0)
836 836 return rc;
837 837  
  838 +try_again:
838 839 mutex_lock(&cinode->lock_mutex);
839 840 if (!cinode->can_cache_brlcks) {
840 841 mutex_unlock(&cinode->lock_mutex);
841 842 return rc;
842 843 }
843   - rc = posix_lock_file_wait(file, flock);
  844 +
  845 + rc = posix_lock_file(file, flock, NULL);
844 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 853 return rc;
846 854 }
847 855  
... ... @@ -510,12 +510,13 @@
510 510  
511 511 /*
512 512 */
513   -static void locks_delete_block(struct file_lock *waiter)
  513 +void locks_delete_block(struct file_lock *waiter)
514 514 {
515 515 lock_flocks();
516 516 __locks_delete_block(waiter);
517 517 unlock_flocks();
518 518 }
  519 +EXPORT_SYMBOL(locks_delete_block);
519 520  
520 521 /* Insert waiter into blocker's block list.
521 522 * We use a circular list so that processes can be easily woken up in
... ... @@ -1203,6 +1203,7 @@
1203 1203 extern int lease_modify(struct file_lock **, int);
1204 1204 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
1205 1205 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
  1206 +extern void locks_delete_block(struct file_lock *waiter);
1206 1207 extern void lock_flocks(void);
1207 1208 extern void unlock_flocks(void);
1208 1209 #else /* !CONFIG_FILE_LOCKING */
... ... @@ -1345,6 +1346,10 @@
1345 1346 unsigned long len)
1346 1347 {
1347 1348 return 1;
  1349 +}
  1350 +
  1351 +static inline void locks_delete_block(struct file_lock *waiter)
  1352 +{
1348 1353 }
1349 1354  
1350 1355 static inline void lock_flocks(void)