aboutsummaryrefslogtreecommitdiffstats
path: root/module/spl/spl-taskq.c
diff options
context:
space:
mode:
authorTim Chase <[email protected]>2015-08-27 11:13:20 -0500
committerBrian Behlendorf <[email protected]>2015-08-31 15:52:06 -0700
commit076821eaff146a56aa6a66916d70eda7db3347ed (patch)
treec4ed9065bb4e4270c778ae95baaba4464fc0975b /module/spl/spl-taskq.c
parentae89cf0f34de323c4a7c39bfd9b906acc2635a87 (diff)
Create a new thread during recursive taskq dispatch if necessary
When dynamic taskq is enabled and all threads for a taskq are occupied, a recursive dispatch can cause a deadlock if calling thread depends on the recursively-dispatched thread for its return condition. This patch attempts to create a new thread for recursive dispatch when none are available. Signed-off-by: Tim Chase <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #472
Diffstat (limited to 'module/spl/spl-taskq.c')
-rw-r--r--module/spl/spl-taskq.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/module/spl/spl-taskq.c b/module/spl/spl-taskq.c
index 7a756af37..2202aced7 100644
--- a/module/spl/spl-taskq.c
+++ b/module/spl/spl-taskq.c
@@ -53,6 +53,7 @@ EXPORT_SYMBOL(system_taskq);
/* Private dedicated taskq for creating new taskq threads on demand. */
static taskq_t *dynamic_taskq;
static taskq_thread_t *taskq_thread_create(taskq_t *);
+static int taskq_thread_spawn(taskq_t *tq, int seq_tasks);
static int
task_km_flags(uint_t flags)
@@ -533,6 +534,7 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
{
taskq_ent_t *t;
taskqid_t rc = 0;
+ boolean_t threadlimit = B_FALSE;
ASSERT(tq);
ASSERT(func);
@@ -574,7 +576,13 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
wake_up(&tq->tq_work_waitq);
out:
+ threadlimit = (tq->tq_nactive == tq->tq_nthreads);
spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+ /* Spawn additional taskq threads if required. */
+ if (threadlimit && taskq_member(tq, current))
+ (void) taskq_thread_spawn(tq, spl_taskq_thread_sequential + 1);
+
return (rc);
}
EXPORT_SYMBOL(taskq_dispatch);
@@ -585,6 +593,7 @@ taskq_dispatch_delay(taskq_t *tq, task_func_t func, void *arg,
{
taskqid_t rc = 0;
taskq_ent_t *t;
+ boolean_t threadlimit = B_FALSE;
ASSERT(tq);
ASSERT(func);
@@ -617,7 +626,13 @@ taskq_dispatch_delay(taskq_t *tq, task_func_t func, void *arg,
spin_unlock(&t->tqent_lock);
out:
+ threadlimit = (tq->tq_nactive == tq->tq_nthreads);
spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+ /* Spawn additional taskq threads if required. */
+ if (threadlimit && taskq_member(tq, current))
+ (void) taskq_thread_spawn(tq, spl_taskq_thread_sequential + 1);
+
return (rc);
}
EXPORT_SYMBOL(taskq_dispatch_delay);
@@ -626,6 +641,8 @@ void
taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
taskq_ent_t *t)
{
+ boolean_t threadlimit = B_FALSE;
+
ASSERT(tq);
ASSERT(func);
@@ -661,7 +678,12 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
wake_up(&tq->tq_work_waitq);
out:
+ threadlimit = (tq->tq_nactive == tq->tq_nthreads);
spin_unlock_irqrestore(&tq->tq_lock, tq->tq_lock_flags);
+
+ /* Spawn additional taskq threads if required. */
+ if (threadlimit && taskq_member(tq, current))
+ (void) taskq_thread_spawn(tq, spl_taskq_thread_sequential + 1);
}
EXPORT_SYMBOL(taskq_dispatch_ent);