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>
This commit is contained in:
parent
d7a06983a0
commit
29723adee1
1 changed files with 13 additions and 2 deletions
15
fs/locks.c
15
fs/locks.c
|
@ -1199,19 +1199,30 @@ int locks_mandatory_area(int read_write, struct inode *inode,
|
|||
{
|
||||
struct file_lock fl;
|
||||
int error;
|
||||
bool sleep = false;
|
||||
|
||||
locks_init_lock(&fl);
|
||||
fl.fl_owner = current->files;
|
||||
fl.fl_pid = current->tgid;
|
||||
fl.fl_file = filp;
|
||||
fl.fl_flags = FL_POSIX | FL_ACCESS;
|
||||
if (filp && !(filp->f_flags & O_NONBLOCK))
|
||||
fl.fl_flags |= FL_SLEEP;
|
||||
sleep = true;
|
||||
fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
|
||||
fl.fl_start = offset;
|
||||
fl.fl_end = offset + count - 1;
|
||||
|
||||
for (;;) {
|
||||
if (filp) {
|
||||
fl.fl_owner = (fl_owner_t)filp;
|
||||
fl.fl_flags &= ~FL_SLEEP;
|
||||
error = __posix_lock_file(inode, &fl, NULL);
|
||||
if (!error)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sleep)
|
||||
fl.fl_flags |= FL_SLEEP;
|
||||
fl.fl_owner = current->files;
|
||||
error = __posix_lock_file(inode, &fl, NULL);
|
||||
if (error != FILE_LOCK_DEFERRED)
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue