diff options
author | Olaf Faaland <[email protected]> | 2015-10-13 16:56:51 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2015-12-11 16:19:56 -0800 |
commit | 326172d8549e0a34a8e4ef4665d8bdfcf7aeda6e (patch) | |
tree | a2f510e287126a137fa81d24c2c4f926a4f28740 /include | |
parent | 628fc52137fc14377eba46c66b57d8d094e88507 (diff) |
Subclass tq_lock to eliminate a lockdep warning
When taskq_dispatch() calls taskq_thread_spawn() to create a new thread
for a taskq, linux lockdep warns of possible recursive locking. This is
a false positive.
One such call chain is as follows, when a taskq needs more threads:
taskq_dispatch->taskq_thread_spawn->taskq_dispatch
The initial taskq_dispatch() holds tq_lock on the taskq that needed more
worker threads. The later call into taskq_dispatch() takes
dynamic_taskq->tq_lock. Without subclassing, lockdep believes these
could potentially be the same lock and complains. A similar case occurs
when taskq_dispatch() then calls task_alloc().
This patch uses spin_lock_irqsave_nested() when taking tq_lock, with one
of two new lock subclasses:
subclass taskq
TQ_LOCK_DYNAMIC dynamic_taskq
TQ_LOCK_GENERAL any other
Signed-off-by: Olaf Faaland <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Issue #480
Diffstat (limited to 'include')
-rw-r--r-- | include/sys/taskq.h | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/include/sys/taskq.h b/include/sys/taskq.h index a43a86da6..5830fe2dd 100644 --- a/include/sys/taskq.h +++ b/include/sys/taskq.h @@ -55,6 +55,14 @@ #define TQ_NEW 0x04000000 #define TQ_FRONT 0x08000000 +/* spin_lock(lock) and spin_lock_nested(lock,0) are equivalent, + * so TQ_LOCK_DYNAMIC must not evaluate to 0 + */ +typedef enum tq_lock_role { + TQ_LOCK_GENERAL = 0, + TQ_LOCK_DYNAMIC = 1, +} tq_lock_role_t; + typedef unsigned long taskqid_t; typedef void (task_func_t)(void *); @@ -81,6 +89,7 @@ typedef struct taskq { struct list_head tq_delay_list; /* delayed task_t's */ wait_queue_head_t tq_work_waitq; /* new work waitq */ wait_queue_head_t tq_wait_waitq; /* wait waitq */ + tq_lock_role_t tq_lock_class; /* class used when taking tq_lock */ } taskq_t; typedef struct taskq_ent { |