瀏覽代碼

lockdep: fix workqueue creation API lockdep interaction
Dave Young reported warnings from lockdep that the workqueue API
can sometimes try to register lockdep classes with the same key
but different names. This is not permitted in lockdep.

Unfortunately, I was unaware of that restriction when I wrote
the code to debug workqueue problems with lockdep and used the
workqueue name as the lockdep class name. This can obviously
lead to the problem if the workqueue name is dynamic.

This patch solves the problem by always using a constant name
for the workqueue's lockdep class, namely either the constant
name that was passed in or a string consisting of the variable
name.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>

Johannes Berg 17 年之前
父節點
當前提交
eb13ba8738
共有 2 個文件被更改,包括 14 次插入5 次删除
  1. 11 3
      include/linux/workqueue.h
  2. 3 2
      kernel/workqueue.c

+ 11 - 3
include/linux/workqueue.h

@@ -149,19 +149,27 @@ struct execute_work {
 
 
 extern struct workqueue_struct *
 extern struct workqueue_struct *
 __create_workqueue_key(const char *name, int singlethread,
 __create_workqueue_key(const char *name, int singlethread,
-		       int freezeable, struct lock_class_key *key);
+		       int freezeable, struct lock_class_key *key,
+		       const char *lock_name);
 
 
 #ifdef CONFIG_LOCKDEP
 #ifdef CONFIG_LOCKDEP
 #define __create_workqueue(name, singlethread, freezeable)	\
 #define __create_workqueue(name, singlethread, freezeable)	\
 ({								\
 ({								\
 	static struct lock_class_key __key;			\
 	static struct lock_class_key __key;			\
+	const char *__lock_name;				\
+								\
+	if (__builtin_constant_p(name))				\
+		__lock_name = (name);				\
+	else							\
+		__lock_name = #name;				\
 								\
 								\
 	__create_workqueue_key((name), (singlethread),		\
 	__create_workqueue_key((name), (singlethread),		\
-			       (freezeable), &__key);		\
+			       (freezeable), &__key,		\
+			       __lock_name);			\
 })
 })
 #else
 #else
 #define __create_workqueue(name, singlethread, freezeable)	\
 #define __create_workqueue(name, singlethread, freezeable)	\
-	__create_workqueue_key((name), (singlethread), (freezeable), NULL)
+	__create_workqueue_key((name), (singlethread), (freezeable), NULL, NULL)
 #endif
 #endif
 
 
 #define create_workqueue(name) __create_workqueue((name), 0, 0)
 #define create_workqueue(name) __create_workqueue((name), 0, 0)

+ 3 - 2
kernel/workqueue.c

@@ -722,7 +722,8 @@ static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
 struct workqueue_struct *__create_workqueue_key(const char *name,
 struct workqueue_struct *__create_workqueue_key(const char *name,
 						int singlethread,
 						int singlethread,
 						int freezeable,
 						int freezeable,
-						struct lock_class_key *key)
+						struct lock_class_key *key,
+						const char *lock_name)
 {
 {
 	struct workqueue_struct *wq;
 	struct workqueue_struct *wq;
 	struct cpu_workqueue_struct *cwq;
 	struct cpu_workqueue_struct *cwq;
@@ -739,7 +740,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
 	}
 	}
 
 
 	wq->name = name;
 	wq->name = name;
-	lockdep_init_map(&wq->lockdep_map, name, key, 0);
+	lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
 	wq->singlethread = singlethread;
 	wq->singlethread = singlethread;
 	wq->freezeable = freezeable;
 	wq->freezeable = freezeable;
 	INIT_LIST_HEAD(&wq->list);
 	INIT_LIST_HEAD(&wq->list);