aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jeff.layton@primarydata.com>2016-01-07 16:38:10 -0500
committerJeff Layton <jeff.layton@primarydata.com>2016-01-07 20:32:48 -0500
commit7f3697e24dc3820b10f445a4a7d914fc356012d1 (patch)
treed938dbcb5d130e9ba32c713a5953243c81932658
parent9189922675ecca0fab38931d86b676e9d79602dc (diff)
locks: fix unlock when fcntl_setlk races with a close
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> Cc: <stable@vger.kernel.org> 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>
-rw-r--r--fs/locks.c51
1 files changed, 30 insertions, 21 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 593dca300b29..c263aff793bc 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2181,7 +2181,6 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
2181 goto out; 2181 goto out;
2182 } 2182 }
2183 2183
2184again:
2185 error = flock_to_posix_lock(filp, file_lock, &flock); 2184 error = flock_to_posix_lock(filp, file_lock, &flock);
2186 if (error) 2185 if (error)
2187 goto out; 2186 goto out;
@@ -2223,19 +2222,22 @@ again:
2223 * Attempt to detect a close/fcntl race and recover by 2222 * Attempt to detect a close/fcntl race and recover by
2224 * releasing the lock that was just acquired. 2223 * releasing the lock that was just acquired.
2225 */ 2224 */
2226 /* 2225 if (!error && file_lock->fl_type != F_UNLCK) {
2227 * we need that spin_lock here - it prevents reordering between 2226 /*
2228 * update of i_flctx->flc_posix and check for it done in close(). 2227 * We need that spin_lock here - it prevents reordering between
2229 * rcu_read_lock() wouldn't do. 2228 * update of i_flctx->flc_posix and check for it done in
2230 */ 2229 * close(). rcu_read_lock() wouldn't do.
2231 spin_lock(&current->files->file_lock); 2230 */
2232 f = fcheck(fd); 2231 spin_lock(&current->files->file_lock);
2233 spin_unlock(&current->files->file_lock); 2232 f = fcheck(fd);
2234 if (!error && f != filp && flock.l_type != F_UNLCK) { 2233 spin_unlock(&current->files->file_lock);
2235 flock.l_type = F_UNLCK; 2234 if (f != filp) {
2236 goto again; 2235 file_lock->fl_type = F_UNLCK;
2236 error = do_lock_file_wait(filp, cmd, file_lock);
2237 WARN_ON_ONCE(error);
2238 error = -EBADF;
2239 }
2237 } 2240 }
2238
2239out: 2241out:
2240 locks_free_lock(file_lock); 2242 locks_free_lock(file_lock);
2241 return error; 2243 return error;
@@ -2321,7 +2323,6 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
2321 goto out; 2323 goto out;
2322 } 2324 }
2323 2325
2324again:
2325 error = flock64_to_posix_lock(filp, file_lock, &flock); 2326 error = flock64_to_posix_lock(filp, file_lock, &flock);
2326 if (error) 2327 if (error)
2327 goto out; 2328 goto out;
@@ -2363,14 +2364,22 @@ again:
2363 * Attempt to detect a close/fcntl race and recover by 2364 * Attempt to detect a close/fcntl race and recover by
2364 * releasing the lock that was just acquired. 2365 * releasing the lock that was just acquired.
2365 */ 2366 */
2366 spin_lock(&current->files->file_lock); 2367 if (!error && file_lock->fl_type != F_UNLCK) {
2367 f = fcheck(fd); 2368 /*
2368 spin_unlock(&current->files->file_lock); 2369 * We need that spin_lock here - it prevents reordering between
2369 if (!error && f != filp && flock.l_type != F_UNLCK) { 2370 * update of i_flctx->flc_posix and check for it done in
2370 flock.l_type = F_UNLCK; 2371 * close(). rcu_read_lock() wouldn't do.
2371 goto again; 2372 */
2373 spin_lock(&current->files->file_lock);
2374 f = fcheck(fd);
2375 spin_unlock(&current->files->file_lock);
2376 if (f != filp) {
2377 file_lock->fl_type = F_UNLCK;
2378 error = do_lock_file_wait(filp, cmd, file_lock);
2379 WARN_ON_ONCE(error);
2380 error = -EBADF;
2381 }
2372 } 2382 }
2373
2374out: 2383out:
2375 locks_free_lock(file_lock); 2384 locks_free_lock(file_lock);
2376 return error; 2385 return error;