* Patch "locks: fix unlock when fcntl_setlk races with a close" has been added to the 3.14-stable tree
@ 2016-03-05 19:42 gregkh
0 siblings, 0 replies; only message in thread
From: gregkh @ 2016-03-05 19:42 UTC (permalink / raw)
To: jeff.layton, bfields, dvyukov, gregkh, viro; +Cc: stable, stable-commits
This is a note to let you know that I've just added the patch titled
locks: fix unlock when fcntl_setlk races with a close
to the 3.14-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
locks-fix-unlock-when-fcntl_setlk-races-with-a-close.patch
and it can be found in the queue-3.14 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.
>From 7f3697e24dc3820b10f445a4a7d914fc356012d1 Mon Sep 17 00:00:00 2001
From: Jeff Layton <jeff.layton@primarydata.com>
Date: Thu, 7 Jan 2016 16:38:10 -0500
Subject: locks: fix unlock when fcntl_setlk races with a close
From: Jeff Layton <jeff.layton@primarydata.com>
commit 7f3697e24dc3820b10f445a4a7d914fc356012d1 upstream.
Dmitry reported that he was able to reproduce the WARN_ON_ONCE that
fires in locks_free_lock_context when the flc_posix list isn't empty.
The problem turns out to be that we're basically rebuilding the
file_lock from scratch in fcntl_setlk when we discover that the setlk
has raced with a close. If the l_whence field is SEEK_CUR or SEEK_END,
then we may end up with fl_start and fl_end values that differ from
when the lock was initially set, if the file position or length of the
file has changed in the interim.
Fix this by just reusing the same lock request structure, and simply
override fl_type value with F_UNLCK as appropriate. That ensures that
we really are unlocking the lock that was initially set.
While we're there, make sure that we do pop a WARN_ON_ONCE if the
removal ever fails. Also return -EBADF in this event, since that's
what we would have returned if the close had happened earlier.
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Fixes: c293621bbf67 (stale POSIX lock handling)
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Jeff Layton <jeff.layton@primarydata.com>
Acked-by: "J. Bruce Fields" <bfields@fieldses.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/locks.c | 51 ++++++++++++++++++++++++++++++---------------------
1 file changed, 30 insertions(+), 21 deletions(-)
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2007,7 +2007,6 @@ int fcntl_setlk(unsigned int fd, struct
goto out;
}
-again:
error = flock_to_posix_lock(filp, file_lock, &flock);
if (error)
goto out;
@@ -2038,19 +2037,22 @@ again:
* Attempt to detect a close/fcntl race and recover by
* releasing the lock that was just acquired.
*/
- /*
- * we need that spin_lock here - it prevents reordering between
- * update of inode->i_flock and check for it done in close().
- * rcu_read_lock() wouldn't do.
- */
- spin_lock(¤t->files->file_lock);
- f = fcheck(fd);
- spin_unlock(¤t->files->file_lock);
- if (!error && f != filp && flock.l_type != F_UNLCK) {
- flock.l_type = F_UNLCK;
- goto again;
+ if (!error && file_lock->fl_type != F_UNLCK) {
+ /*
+ * We need that spin_lock here - it prevents reordering between
+ * update of inode->i_flock and check for it done in
+ * close(). rcu_read_lock() wouldn't do.
+ */
+ spin_lock(¤t->files->file_lock);
+ f = fcheck(fd);
+ spin_unlock(¤t->files->file_lock);
+ if (f != filp) {
+ file_lock->fl_type = F_UNLCK;
+ error = do_lock_file_wait(filp, cmd, file_lock);
+ WARN_ON_ONCE(error);
+ error = -EBADF;
+ }
}
-
out:
locks_free_lock(file_lock);
return error;
@@ -2125,7 +2127,6 @@ int fcntl_setlk64(unsigned int fd, struc
goto out;
}
-again:
error = flock64_to_posix_lock(filp, file_lock, &flock);
if (error)
goto out;
@@ -2156,14 +2157,22 @@ again:
* Attempt to detect a close/fcntl race and recover by
* releasing the lock that was just acquired.
*/
- spin_lock(¤t->files->file_lock);
- f = fcheck(fd);
- spin_unlock(¤t->files->file_lock);
- if (!error && f != filp && flock.l_type != F_UNLCK) {
- flock.l_type = F_UNLCK;
- goto again;
+ if (!error && file_lock->fl_type != F_UNLCK) {
+ /*
+ * We need that spin_lock here - it prevents reordering between
+ * update of inode->i_flock and check for it done in
+ * close(). rcu_read_lock() wouldn't do.
+ */
+ spin_lock(¤t->files->file_lock);
+ f = fcheck(fd);
+ spin_unlock(¤t->files->file_lock);
+ if (f != filp) {
+ file_lock->fl_type = F_UNLCK;
+ error = do_lock_file_wait(filp, cmd, file_lock);
+ WARN_ON_ONCE(error);
+ error = -EBADF;
+ }
}
-
out:
locks_free_lock(file_lock);
return error;
Patches currently in stable-queue which might be from jeff.layton@primarydata.com are
queue-3.14/locks-fix-unlock-when-fcntl_setlk-races-with-a-close.patch
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2016-03-05 19:42 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-03-05 19:42 Patch "locks: fix unlock when fcntl_setlk races with a close" has been added to the 3.14-stable tree gregkh
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).