Commit 97855b49 authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Linus Torvalds

locks: fix possible infinite loop in posix deadlock detection

It's currently possible to send posix_locks_deadlock() into an infinite
loop (under the BKL).

For now, fix this just by bailing out after a few iterations.  We may
want to fix this in a way that better clarifies the semantics of
deadlock detection.  But that will take more time, and this minimal fix
is probably adequate for any realistic scenario, and is simple enough to
be appropriate for applying to stable kernels now.

Thanks to George Davis for reporting the problem.

Cc: "George G. Davis" <gdavis@mvista.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Acked-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fb7267ac
...@@ -696,17 +696,28 @@ EXPORT_SYMBOL(posix_test_lock); ...@@ -696,17 +696,28 @@ EXPORT_SYMBOL(posix_test_lock);
* Note: the above assumption may not be true when handling lock requests * Note: the above assumption may not be true when handling lock requests
* from a broken NFS client. But broken NFS clients have a lot more to * from a broken NFS client. But broken NFS clients have a lot more to
* worry about than proper deadlock detection anyway... --okir * worry about than proper deadlock detection anyway... --okir
*
* However, the failure of this assumption (also possible in the case of
* multiple tasks sharing the same open file table) also means there's no
* guarantee that the loop below will terminate. As a hack, we give up
* after a few iterations.
*/ */
#define MAX_DEADLK_ITERATIONS 10
static int posix_locks_deadlock(struct file_lock *caller_fl, static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl) struct file_lock *block_fl)
{ {
struct file_lock *fl; struct file_lock *fl;
int i = 0;
next_task: next_task:
if (posix_same_owner(caller_fl, block_fl)) if (posix_same_owner(caller_fl, block_fl))
return 1; return 1;
list_for_each_entry(fl, &blocked_list, fl_link) { list_for_each_entry(fl, &blocked_list, fl_link) {
if (posix_same_owner(fl, block_fl)) { if (posix_same_owner(fl, block_fl)) {
if (i++ > MAX_DEADLK_ITERATIONS)
return 0;
fl = fl->fl_next; fl = fl->fl_next;
block_fl = fl; block_fl = fl;
goto next_task; goto next_task;
......
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