summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorOlaf Faaland <[email protected]>2015-10-13 16:56:51 -0700
committerBrian Behlendorf <[email protected]>2015-12-11 16:19:56 -0800
commit326172d8549e0a34a8e4ef4665d8bdfcf7aeda6e (patch)
treea2f510e287126a137fa81d24c2c4f926a4f28740 /include
parent628fc52137fc14377eba46c66b57d8d094e88507 (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.h9
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 {