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: NeilBrown <neilb@suse.com> Reviewed-by: J. Bruce Fields <bfields@redhat.com> Tested-by: syzbot+a4a3d526b4157113ec6a@syzkaller.appspotmail.com Tested-by: kernel test robot <rong.a.chen@intel.com> Signed-off-by: Jeff Layton <jlayton@kernel.org>
This commit is contained in:
Родитель
5946c4319e
Коммит
16306a61d3
40
fs/locks.c
40
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;
|
||||
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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче