diff options
Diffstat (limited to 'kernel/async.c')
| -rw-r--r-- | kernel/async.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/kernel/async.c b/kernel/async.c index 9d3118384858..6f34904a0b53 100644 --- a/kernel/async.c +++ b/kernel/async.c | |||
| @@ -86,18 +86,27 @@ static atomic_t entry_count; | |||
| 86 | */ | 86 | */ |
| 87 | static async_cookie_t __lowest_in_progress(struct async_domain *running) | 87 | static async_cookie_t __lowest_in_progress(struct async_domain *running) |
| 88 | { | 88 | { |
| 89 | async_cookie_t first_running = next_cookie; /* infinity value */ | ||
| 90 | async_cookie_t first_pending = next_cookie; /* ditto */ | ||
| 89 | struct async_entry *entry; | 91 | struct async_entry *entry; |
| 90 | 92 | ||
| 93 | /* | ||
| 94 | * Both running and pending lists are sorted but not disjoint. | ||
| 95 | * Take the first cookies from both and return the min. | ||
| 96 | */ | ||
| 91 | if (!list_empty(&running->domain)) { | 97 | if (!list_empty(&running->domain)) { |
| 92 | entry = list_first_entry(&running->domain, typeof(*entry), list); | 98 | entry = list_first_entry(&running->domain, typeof(*entry), list); |
| 93 | return entry->cookie; | 99 | first_running = entry->cookie; |
| 94 | } | 100 | } |
| 95 | 101 | ||
| 96 | list_for_each_entry(entry, &async_pending, list) | 102 | list_for_each_entry(entry, &async_pending, list) { |
| 97 | if (entry->running == running) | 103 | if (entry->running == running) { |
| 98 | return entry->cookie; | 104 | first_pending = entry->cookie; |
| 105 | break; | ||
| 106 | } | ||
| 107 | } | ||
| 99 | 108 | ||
| 100 | return next_cookie; /* "infinity" value */ | 109 | return min(first_running, first_pending); |
| 101 | } | 110 | } |
| 102 | 111 | ||
| 103 | static async_cookie_t lowest_in_progress(struct async_domain *running) | 112 | static async_cookie_t lowest_in_progress(struct async_domain *running) |
| @@ -118,13 +127,17 @@ static void async_run_entry_fn(struct work_struct *work) | |||
| 118 | { | 127 | { |
| 119 | struct async_entry *entry = | 128 | struct async_entry *entry = |
| 120 | container_of(work, struct async_entry, work); | 129 | container_of(work, struct async_entry, work); |
| 130 | struct async_entry *pos; | ||
| 121 | unsigned long flags; | 131 | unsigned long flags; |
| 122 | ktime_t uninitialized_var(calltime), delta, rettime; | 132 | ktime_t uninitialized_var(calltime), delta, rettime; |
| 123 | struct async_domain *running = entry->running; | 133 | struct async_domain *running = entry->running; |
| 124 | 134 | ||
| 125 | /* 1) move self to the running queue */ | 135 | /* 1) move self to the running queue, make sure it stays sorted */ |
| 126 | spin_lock_irqsave(&async_lock, flags); | 136 | spin_lock_irqsave(&async_lock, flags); |
| 127 | list_move_tail(&entry->list, &running->domain); | 137 | list_for_each_entry_reverse(pos, &running->domain, list) |
| 138 | if (entry->cookie < pos->cookie) | ||
| 139 | break; | ||
| 140 | list_move_tail(&entry->list, &pos->list); | ||
| 128 | spin_unlock_irqrestore(&async_lock, flags); | 141 | spin_unlock_irqrestore(&async_lock, flags); |
| 129 | 142 | ||
| 130 | /* 2) run (and print duration) */ | 143 | /* 2) run (and print duration) */ |
| @@ -196,6 +209,9 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct a | |||
| 196 | atomic_inc(&entry_count); | 209 | atomic_inc(&entry_count); |
| 197 | spin_unlock_irqrestore(&async_lock, flags); | 210 | spin_unlock_irqrestore(&async_lock, flags); |
| 198 | 211 | ||
| 212 | /* mark that this task has queued an async job, used by module init */ | ||
| 213 | current->flags |= PF_USED_ASYNC; | ||
| 214 | |||
| 199 | /* schedule for execution */ | 215 | /* schedule for execution */ |
| 200 | queue_work(system_unbound_wq, &entry->work); | 216 | queue_work(system_unbound_wq, &entry->work); |
| 201 | 217 | ||
