Skip to content

Commit bf52b1a

Browse files
committed
async: Use a dedicated unbound workqueue with raised min_active
Async can schedule a number of interdependent work items. However, since 5797b1c ("workqueue: Implement system-wide nr_active enforcement for unbound workqueues"), unbound workqueues have separate min_active which sets the number of interdependent work items that can be handled. This default value is 8 which isn't sufficient for async and can lead to stalls during resume from suspend in some cases. Let's use a dedicated unbound workqueue with raised min_active. Link: http://lkml.kernel.org/r/[email protected] Reported-by: Marek Szyprowski <[email protected]> Cc: Rafael J. Wysocki <[email protected]> Tested-by: Marek Szyprowski <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent 8f17218 commit bf52b1a

File tree

3 files changed

+18
-1
lines changed

3 files changed

+18
-1
lines changed

include/linux/async.h

+1
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,5 @@ extern void async_synchronize_cookie(async_cookie_t cookie);
120120
extern void async_synchronize_cookie_domain(async_cookie_t cookie,
121121
struct async_domain *domain);
122122
extern bool current_is_async(void);
123+
extern void async_init(void);
123124
#endif

init/main.c

+1
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,7 @@ static noinline void __init kernel_init_freeable(void)
15451545
sched_init_smp();
15461546

15471547
workqueue_init_topology();
1548+
async_init();
15481549
padata_init();
15491550
page_alloc_init_late();
15501551

kernel/async.c

+16-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ static async_cookie_t next_cookie = 1;
6464
static LIST_HEAD(async_global_pending); /* pending from all registered doms */
6565
static ASYNC_DOMAIN(async_dfl_domain);
6666
static DEFINE_SPINLOCK(async_lock);
67+
static struct workqueue_struct *async_wq;
6768

6869
struct async_entry {
6970
struct list_head domain_list;
@@ -174,7 +175,7 @@ static async_cookie_t __async_schedule_node_domain(async_func_t func,
174175
spin_unlock_irqrestore(&async_lock, flags);
175176

176177
/* schedule for execution */
177-
queue_work_node(node, system_unbound_wq, &entry->work);
178+
queue_work_node(node, async_wq, &entry->work);
178179

179180
return newcookie;
180181
}
@@ -345,3 +346,17 @@ bool current_is_async(void)
345346
return worker && worker->current_func == async_run_entry_fn;
346347
}
347348
EXPORT_SYMBOL_GPL(current_is_async);
349+
350+
void __init async_init(void)
351+
{
352+
/*
353+
* Async can schedule a number of interdependent work items. However,
354+
* unbound workqueues can handle only upto min_active interdependent
355+
* work items. The default min_active of 8 isn't sufficient for async
356+
* and can lead to stalls. Let's use a dedicated workqueue with raised
357+
* min_active.
358+
*/
359+
async_wq = alloc_workqueue("async", WQ_UNBOUND, 0);
360+
BUG_ON(!async_wq);
361+
workqueue_set_min_active(async_wq, WQ_DFL_ACTIVE);
362+
}

0 commit comments

Comments
 (0)