Merge tag 'wq-for-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 Oct 2023 06:45:29 +0000 (20:45 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 Oct 2023 06:45:29 +0000 (20:45 -1000)
Pull workqueue update from Tejun Heo:
 "Just one commit to improve lockdep annotation for work_on_cpu() to
  avoid spurious warnings"

* tag 'wq-for-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
  workqueue: Provide one lock class key per work_on_cpu() callsite

include/linux/workqueue.h
kernel/workqueue.c

index 1c1d068..24b1e50 100644 (file)
@@ -274,18 +274,16 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
  * to generate better code.
  */
 #ifdef CONFIG_LOCKDEP
-#define __INIT_WORK(_work, _func, _onstack)                            \
+#define __INIT_WORK_KEY(_work, _func, _onstack, _key)                  \
        do {                                                            \
-               static struct lock_class_key __key;                     \
-                                                                       \
                __init_work((_work), _onstack);                         \
                (_work)->data = (atomic_long_t) WORK_DATA_INIT();       \
-               lockdep_init_map(&(_work)->lockdep_map, "(work_completion)"#_work, &__key, 0); \
+               lockdep_init_map(&(_work)->lockdep_map, "(work_completion)"#_work, (_key), 0); \
                INIT_LIST_HEAD(&(_work)->entry);                        \
                (_work)->func = (_func);                                \
        } while (0)
 #else
-#define __INIT_WORK(_work, _func, _onstack)                            \
+#define __INIT_WORK_KEY(_work, _func, _onstack, _key)                  \
        do {                                                            \
                __init_work((_work), _onstack);                         \
                (_work)->data = (atomic_long_t) WORK_DATA_INIT();       \
@@ -294,12 +292,22 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
        } while (0)
 #endif
 
+#define __INIT_WORK(_work, _func, _onstack)                            \
+       do {                                                            \
+               static __maybe_unused struct lock_class_key __key;      \
+                                                                       \
+               __INIT_WORK_KEY(_work, _func, _onstack, &__key);        \
+       } while (0)
+
 #define INIT_WORK(_work, _func)                                                \
        __INIT_WORK((_work), (_func), 0)
 
 #define INIT_WORK_ONSTACK(_work, _func)                                        \
        __INIT_WORK((_work), (_func), 1)
 
+#define INIT_WORK_ONSTACK_KEY(_work, _func, _key)                      \
+       __INIT_WORK_KEY((_work), (_func), 1, _key)
+
 #define __INIT_DELAYED_WORK(_work, _func, _tflags)                     \
        do {                                                            \
                INIT_WORK(&(_work)->work, (_func));                     \
@@ -693,8 +701,32 @@ static inline long work_on_cpu_safe(int cpu, long (*fn)(void *), void *arg)
        return fn(arg);
 }
 #else
-long work_on_cpu(int cpu, long (*fn)(void *), void *arg);
-long work_on_cpu_safe(int cpu, long (*fn)(void *), void *arg);
+long work_on_cpu_key(int cpu, long (*fn)(void *),
+                    void *arg, struct lock_class_key *key);
+/*
+ * A new key is defined for each caller to make sure the work
+ * associated with the function doesn't share its locking class.
+ */
+#define work_on_cpu(_cpu, _fn, _arg)                   \
+({                                                     \
+       static struct lock_class_key __key;             \
+                                                       \
+       work_on_cpu_key(_cpu, _fn, _arg, &__key);       \
+})
+
+long work_on_cpu_safe_key(int cpu, long (*fn)(void *),
+                         void *arg, struct lock_class_key *key);
+
+/*
+ * A new key is defined for each caller to make sure the work
+ * associated with the function doesn't share its locking class.
+ */
+#define work_on_cpu_safe(_cpu, _fn, _arg)              \
+({                                                     \
+       static struct lock_class_key __key;             \
+                                                       \
+       work_on_cpu_safe_key(_cpu, _fn, _arg, &__key);  \
+})
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_FREEZER
index a3522b7..0f682da 100644 (file)
@@ -5622,50 +5622,54 @@ static void work_for_cpu_fn(struct work_struct *work)
 }
 
 /**
- * work_on_cpu - run a function in thread context on a particular cpu
+ * work_on_cpu_key - run a function in thread context on a particular cpu
  * @cpu: the cpu to run on
  * @fn: the function to run
  * @arg: the function arg
+ * @key: The lock class key for lock debugging purposes
  *
  * It is up to the caller to ensure that the cpu doesn't go offline.
  * The caller must not hold any locks which would prevent @fn from completing.
  *
  * Return: The value @fn returns.
  */
-long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
+long work_on_cpu_key(int cpu, long (*fn)(void *),
+                    void *arg, struct lock_class_key *key)
 {
        struct work_for_cpu wfc = { .fn = fn, .arg = arg };
 
-       INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
+       INIT_WORK_ONSTACK_KEY(&wfc.work, work_for_cpu_fn, key);
        schedule_work_on(cpu, &wfc.work);
        flush_work(&wfc.work);
        destroy_work_on_stack(&wfc.work);
        return wfc.ret;
 }
-EXPORT_SYMBOL_GPL(work_on_cpu);
+EXPORT_SYMBOL_GPL(work_on_cpu_key);
 
 /**
- * work_on_cpu_safe - run a function in thread context on a particular cpu
+ * work_on_cpu_safe_key - run a function in thread context on a particular cpu
  * @cpu: the cpu to run on
  * @fn:  the function to run
  * @arg: the function argument
+ * @key: The lock class key for lock debugging purposes
  *
  * Disables CPU hotplug and calls work_on_cpu(). The caller must not hold
  * any locks which would prevent @fn from completing.
  *
  * Return: The value @fn returns.
  */
-long work_on_cpu_safe(int cpu, long (*fn)(void *), void *arg)
+long work_on_cpu_safe_key(int cpu, long (*fn)(void *),
+                         void *arg, struct lock_class_key *key)
 {
        long ret = -ENODEV;
 
        cpus_read_lock();
        if (cpu_online(cpu))
-               ret = work_on_cpu(cpu, fn, arg);
+               ret = work_on_cpu_key(cpu, fn, arg, key);
        cpus_read_unlock();
        return ret;
 }
-EXPORT_SYMBOL_GPL(work_on_cpu_safe);
+EXPORT_SYMBOL_GPL(work_on_cpu_safe_key);
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_FREEZER