aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2009-05-24 16:03:43 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-05-24 16:38:41 -0400
commitd5a877e8dd409d8c702986d06485c374b705d340 (patch)
treeece6d685c074c6823d31b7db99a52134866fd1a7
parent657cafa6b0f5296424d6f43f6f6eeb4a3222117e (diff)
async: make sure independent async domains can't accidentally entangle
The problem occurs when async_synchronize_full_domain() is called when the async_pending list is not empty. This will cause lowest_running() to return the cookie of the first entry on the async_pending list, which might be nothing at all to do with the domain being asked for and thus cause the domain synchronization to wait for an unrelated domain. This can cause a deadlock if domain synchronization is used from one domain to wait for another. Fix by running over the async_pending list to see if any pending items actually belong to our domain (and return their cookies if they do). Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/async.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/kernel/async.c b/kernel/async.c
index 968ef9457d4e..50540301ed0f 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -92,19 +92,23 @@ extern int initcall_debug;
92static async_cookie_t __lowest_in_progress(struct list_head *running) 92static async_cookie_t __lowest_in_progress(struct list_head *running)
93{ 93{
94 struct async_entry *entry; 94 struct async_entry *entry;
95 async_cookie_t ret = next_cookie; /* begin with "infinity" value */
96
95 if (!list_empty(running)) { 97 if (!list_empty(running)) {
96 entry = list_first_entry(running, 98 entry = list_first_entry(running,
97 struct async_entry, list); 99 struct async_entry, list);
98 return entry->cookie; 100 ret = entry->cookie;
99 } else if (!list_empty(&async_pending)) {
100 entry = list_first_entry(&async_pending,
101 struct async_entry, list);
102 return entry->cookie;
103 } else {
104 /* nothing in progress... next_cookie is "infinity" */
105 return next_cookie;
106 } 101 }
107 102
103 if (!list_empty(&async_pending)) {
104 list_for_each_entry(entry, &async_pending, list)
105 if (entry->running == running) {
106 ret = entry->cookie;
107 break;
108 }
109 }
110
111 return ret;
108} 112}
109 113
110static async_cookie_t lowest_in_progress(struct list_head *running) 114static async_cookie_t lowest_in_progress(struct list_head *running)