diff options
author | Jeff Layton <jlayton@redhat.com> | 2014-03-10 09:54:19 -0400 |
---|---|---|
committer | Jeff Layton <jlayton@redhat.com> | 2014-03-31 08:24:43 -0400 |
commit | 29723adee11804b548903ddb1db666cf4a60f60e (patch) | |
tree | 15ffb52af6c920d52cb53b970c9d6a21fe6cc2b1 | |
parent | d7a06983a01a33605191c0766857b832ac32a2b6 (diff) |
locks: make locks_mandatory_area check for file-private locks
Allow locks_mandatory_area() to handle file-private locks correctly.
If there is a file-private lock set on an open file and we're doing I/O
via the same, then that should not cause anything to block.
Handle this by first doing a non-blocking FL_ACCESS check for a
file-private lock, and then fall back to checking for a classic POSIX
lock (and possibly blocking).
Note that this approach is subject to the same races that have always
plagued mandatory locking on Linux.
Reported-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
-rw-r--r-- | fs/locks.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/fs/locks.c b/fs/locks.c index d82c51c4fcd2..13fc7a6d380a 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1199,19 +1199,30 @@ int locks_mandatory_area(int read_write, struct inode *inode, | |||
1199 | { | 1199 | { |
1200 | struct file_lock fl; | 1200 | struct file_lock fl; |
1201 | int error; | 1201 | int error; |
1202 | bool sleep = false; | ||
1202 | 1203 | ||
1203 | locks_init_lock(&fl); | 1204 | locks_init_lock(&fl); |
1204 | fl.fl_owner = current->files; | ||
1205 | fl.fl_pid = current->tgid; | 1205 | fl.fl_pid = current->tgid; |
1206 | fl.fl_file = filp; | 1206 | fl.fl_file = filp; |
1207 | fl.fl_flags = FL_POSIX | FL_ACCESS; | 1207 | fl.fl_flags = FL_POSIX | FL_ACCESS; |
1208 | if (filp && !(filp->f_flags & O_NONBLOCK)) | 1208 | if (filp && !(filp->f_flags & O_NONBLOCK)) |
1209 | fl.fl_flags |= FL_SLEEP; | 1209 | sleep = true; |
1210 | fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK; | 1210 | fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK; |
1211 | fl.fl_start = offset; | 1211 | fl.fl_start = offset; |
1212 | fl.fl_end = offset + count - 1; | 1212 | fl.fl_end = offset + count - 1; |
1213 | 1213 | ||
1214 | for (;;) { | 1214 | for (;;) { |
1215 | if (filp) { | ||
1216 | fl.fl_owner = (fl_owner_t)filp; | ||
1217 | fl.fl_flags &= ~FL_SLEEP; | ||
1218 | error = __posix_lock_file(inode, &fl, NULL); | ||
1219 | if (!error) | ||
1220 | break; | ||
1221 | } | ||
1222 | |||
1223 | if (sleep) | ||
1224 | fl.fl_flags |= FL_SLEEP; | ||
1225 | fl.fl_owner = current->files; | ||
1215 | error = __posix_lock_file(inode, &fl, NULL); | 1226 | error = __posix_lock_file(inode, &fl, NULL); |
1216 | if (error != FILE_LOCK_DEFERRED) | 1227 | if (error != FILE_LOCK_DEFERRED) |
1217 | break; | 1228 | break; |