Commit 16306a61 authored by NeilBrown's avatar NeilBrown Committed by Jeff Layton

fs/locks: always delete_block after waiting.

Now that requests can block other requests, we
need to be careful to always clean up those blocked
requests.
Any time that we wait for a request, we might have
other requests attached, and when we stop waiting,
we must clean them up.
If the lock was granted, the requests might have been
moved to the new lock, though when merged with a
pre-exiting lock, this might not happen.
In all cases we don't want blocked locks to remain
attached, so we remove them to be safe.
Signed-off-by: default avatarNeilBrown <neilb@suse.com>
Reviewed-by: default avatarJ. Bruce Fields <bfields@redhat.com>
Tested-by: syzbot+a4a3d526b4157113ec6a@syzkaller.appspotmail.com
Tested-by: default avatarkernel test robot <rong.a.chen@intel.com>
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
parent 5946c431
......@@ -710,6 +710,20 @@ static void __locks_wake_up_blocks(struct file_lock *blocker)
static void locks_delete_block(struct file_lock *waiter)
{
/*
* If fl_blocker is NULL, it won't be set again as this thread
* "owns" the lock and is the only one that might try to claim
* the lock. So it is safe to test fl_blocker locklessly.
* Also if fl_blocker is NULL, this waiter is not listed on
* fl_blocked_requests for some lock, so no other request can
* be added to the list of fl_blocked_requests for this
* request. So if fl_blocker is NULL, it is safe to
* locklessly check if fl_blocked_requests is empty. If both
* of these checks succeed, there is no need to take the lock.
*/
if (waiter->fl_blocker == NULL &&
list_empty(&waiter->fl_blocked_requests))
return;
spin_lock(&blocked_lock_lock);
__locks_wake_up_blocks(waiter);
__locks_delete_block(waiter);
......@@ -1279,12 +1293,10 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
if (error != FILE_LOCK_DEFERRED)
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_blocker);
if (!error)
continue;
locks_delete_block(fl);
break;
if (error)
break;
}
locks_delete_block(fl);
return error;
}
......@@ -1375,9 +1387,9 @@ int locks_mandatory_area(struct inode *inode, struct file *filp, loff_t start,
continue;
}
locks_delete_block(&fl);
break;
}
locks_delete_block(&fl);
return error;
}
......@@ -1973,12 +1985,10 @@ static int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
if (error != FILE_LOCK_DEFERRED)
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_blocker);
if (!error)
continue;
locks_delete_block(fl);
break;
if (error)
break;
}
locks_delete_block(fl);
return error;
}
......@@ -2252,12 +2262,10 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd,
if (error != FILE_LOCK_DEFERRED)
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_blocker);
if (!error)
continue;
locks_delete_block(fl);
break;
if (error)
break;
}
locks_delete_block(fl);
return error;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment