Skip to content

Commit

Permalink
CIFS: Fix VFS lock usage for oplocked files
Browse files Browse the repository at this point in the history
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: [email protected]
Acked-by: Jeff Layton <[email protected]>
Signed-off-by: Pavel Shilovsky <[email protected]>
Signed-off-by: Steve French <[email protected]>
  • Loading branch information
piastry authored and Steve French committed Apr 1, 2012
1 parent 9ebb389 commit 66189be
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 2 deletions.
10 changes: 9 additions & 1 deletion fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion fs/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,7 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
extern void locks_delete_block(struct file_lock *waiter);
extern void lock_flocks(void);
extern void unlock_flocks(void);
#else /* !CONFIG_FILE_LOCKING */
Expand Down Expand Up @@ -1359,6 +1360,10 @@ static inline int lock_may_write(struct inode *inode, loff_t start,
return 1;
}

static inline void locks_delete_block(struct file_lock *waiter)
{
}

static inline void lock_flocks(void)
{
}
Expand Down

0 comments on commit 66189be

Please sign in to comment.