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: NeilBrown <neilb@xxxxxxxx> Reviewed-by: J. Bruce Fields <bfields@xxxxxxxxxx> Tested-by: syzbot+a4a3d526b4157113ec6a@xxxxxxxxxxxxxxxxxxxxxxxxx Tested-by: kernel test robot <rong.a.chen@xxxxxxxxx> --- fs/locks.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 1260c265ba62..2814662ecfe6 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -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 status; 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; }