Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'wq-for-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq

Pull workqueue updates from Tejun Heo:
"Nothing major:

- workqueue.panic_on_stall boot param added

- alloc_workqueue_lockdep_map() added (used by DRM)

- Other cleanusp and doc updates"

* tag 'wq-for-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
kernel/workqueue.c: fix DEFINE_PER_CPU_SHARED_ALIGNED expansion
workqueue: Fix another htmldocs build warning
workqueue: fix null-ptr-deref on __alloc_workqueue() error
workqueue: Don't call va_start / va_end twice
workqueue: Fix htmldocs build warning
workqueue: Add interface for user-defined workqueue lockdep map
workqueue: Change workqueue lockdep map to pointer
workqueue: Split alloc_workqueue into internal function and lockdep init
Documentation: kernel-parameters: add workqueue.panic_on_stall
workqueue: add cmdline parameter workqueue.panic_on_stall

+130 -25
+7
Documentation/admin-guide/kernel-parameters.txt
··· 7386 7386 it can be updated at runtime by writing to the 7387 7387 corresponding sysfs file. 7388 7388 7389 + workqueue.panic_on_stall=<uint> 7390 + Panic when workqueue stall is detected by 7391 + CONFIG_WQ_WATCHDOG. It sets the number times of the 7392 + stall to trigger panic. 7393 + 7394 + The default is 0, which disables the panic on stall. 7395 + 7389 7396 workqueue.cpu_intensive_thresh_us= 7390 7397 Per-cpu work items which run for longer than this 7391 7398 threshold are automatically considered CPU intensive
+41
include/linux/workqueue.h
··· 507 507 __printf(1, 4) struct workqueue_struct * 508 508 alloc_workqueue(const char *fmt, unsigned int flags, int max_active, ...); 509 509 510 + #ifdef CONFIG_LOCKDEP 511 + /** 512 + * alloc_workqueue_lockdep_map - allocate a workqueue with user-defined lockdep_map 513 + * @fmt: printf format for the name of the workqueue 514 + * @flags: WQ_* flags 515 + * @max_active: max in-flight work items, 0 for default 516 + * @lockdep_map: user-defined lockdep_map 517 + * @...: args for @fmt 518 + * 519 + * Same as alloc_workqueue but with the a user-define lockdep_map. Useful for 520 + * workqueues created with the same purpose and to avoid leaking a lockdep_map 521 + * on each workqueue creation. 522 + * 523 + * RETURNS: 524 + * Pointer to the allocated workqueue on success, %NULL on failure. 525 + */ 526 + __printf(1, 5) struct workqueue_struct * 527 + alloc_workqueue_lockdep_map(const char *fmt, unsigned int flags, int max_active, 528 + struct lockdep_map *lockdep_map, ...); 529 + 530 + /** 531 + * alloc_ordered_workqueue_lockdep_map - allocate an ordered workqueue with 532 + * user-defined lockdep_map 533 + * 534 + * @fmt: printf format for the name of the workqueue 535 + * @flags: WQ_* flags (only WQ_FREEZABLE and WQ_MEM_RECLAIM are meaningful) 536 + * @lockdep_map: user-defined lockdep_map 537 + * @args: args for @fmt 538 + * 539 + * Same as alloc_ordered_workqueue but with the a user-define lockdep_map. 540 + * Useful for workqueues created with the same purpose and to avoid leaking a 541 + * lockdep_map on each workqueue creation. 542 + * 543 + * RETURNS: 544 + * Pointer to the allocated workqueue on success, %NULL on failure. 545 + */ 546 + #define alloc_ordered_workqueue_lockdep_map(fmt, flags, lockdep_map, args...) \ 547 + alloc_workqueue_lockdep_map(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), \ 548 + 1, lockdep_map, ##args) 549 + #endif 550 + 510 551 /** 511 552 * alloc_ordered_workqueue - allocate an ordered workqueue 512 553 * @fmt: printf format for the name of the workqueue
+82 -25
kernel/workqueue.c
··· 364 364 #ifdef CONFIG_LOCKDEP 365 365 char *lock_name; 366 366 struct lock_class_key key; 367 - struct lockdep_map lockdep_map; 367 + struct lockdep_map __lockdep_map; 368 + struct lockdep_map *lockdep_map; 368 369 #endif 369 370 char name[WQ_NAME_LEN]; /* I: workqueue name */ 370 371 ··· 477 476 module_param_named(debug_force_rr_cpu, wq_debug_force_rr_cpu, bool, 0644); 478 477 479 478 /* to raise softirq for the BH worker pools on other CPUs */ 480 - static DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_work [NR_STD_WORKER_POOLS], 481 - bh_pool_irq_works); 479 + static DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_work [NR_STD_WORKER_POOLS], bh_pool_irq_works); 482 480 483 481 /* the BH worker pools */ 484 - static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS], 485 - bh_worker_pools); 482 + static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS], bh_worker_pools); 486 483 487 484 /* the per-cpu worker pools */ 488 - static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS], 489 - cpu_worker_pools); 485 + static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS], cpu_worker_pools); 490 486 491 487 static DEFINE_IDR(worker_pool_idr); /* PR: idr of all pools */ 492 488 ··· 3201 3203 lockdep_start_depth = lockdep_depth(current); 3202 3204 /* see drain_dead_softirq_workfn() */ 3203 3205 if (!bh_draining) 3204 - lock_map_acquire(&pwq->wq->lockdep_map); 3206 + lock_map_acquire(pwq->wq->lockdep_map); 3205 3207 lock_map_acquire(&lockdep_map); 3206 3208 /* 3207 3209 * Strictly speaking we should mark the invariant state without holding ··· 3235 3237 pwq->stats[PWQ_STAT_COMPLETED]++; 3236 3238 lock_map_release(&lockdep_map); 3237 3239 if (!bh_draining) 3238 - lock_map_release(&pwq->wq->lockdep_map); 3240 + lock_map_release(pwq->wq->lockdep_map); 3239 3241 3240 3242 if (unlikely((worker->task && in_atomic()) || 3241 3243 lockdep_depth(current) != lockdep_start_depth || ··· 3871 3873 static void touch_wq_lockdep_map(struct workqueue_struct *wq) 3872 3874 { 3873 3875 #ifdef CONFIG_LOCKDEP 3876 + if (unlikely(!wq->lockdep_map)) 3877 + return; 3878 + 3874 3879 if (wq->flags & WQ_BH) 3875 3880 local_bh_disable(); 3876 3881 3877 - lock_map_acquire(&wq->lockdep_map); 3878 - lock_map_release(&wq->lockdep_map); 3882 + lock_map_acquire(wq->lockdep_map); 3883 + lock_map_release(wq->lockdep_map); 3879 3884 3880 3885 if (wq->flags & WQ_BH) 3881 3886 local_bh_enable(); ··· 3912 3911 struct wq_flusher this_flusher = { 3913 3912 .list = LIST_HEAD_INIT(this_flusher.list), 3914 3913 .flush_color = -1, 3915 - .done = COMPLETION_INITIALIZER_ONSTACK_MAP(this_flusher.done, wq->lockdep_map), 3914 + .done = COMPLETION_INITIALIZER_ONSTACK_MAP(this_flusher.done, (*wq->lockdep_map)), 3916 3915 }; 3917 3916 int next_color; 3918 3917 ··· 4777 4776 lock_name = wq->name; 4778 4777 4779 4778 wq->lock_name = lock_name; 4780 - lockdep_init_map(&wq->lockdep_map, lock_name, &wq->key, 0); 4779 + wq->lockdep_map = &wq->__lockdep_map; 4780 + lockdep_init_map(wq->lockdep_map, lock_name, &wq->key, 0); 4781 4781 } 4782 4782 4783 4783 static void wq_unregister_lockdep(struct workqueue_struct *wq) 4784 4784 { 4785 + if (wq->lockdep_map != &wq->__lockdep_map) 4786 + return; 4787 + 4785 4788 lockdep_unregister_key(&wq->key); 4786 4789 } 4787 4790 4788 4791 static void wq_free_lockdep(struct workqueue_struct *wq) 4789 4792 { 4793 + if (wq->lockdep_map != &wq->__lockdep_map) 4794 + return; 4795 + 4790 4796 if (wq->lock_name != wq->name) 4791 4797 kfree(wq->lock_name); 4792 4798 } ··· 5627 5619 } while (activated); 5628 5620 } 5629 5621 5630 - __printf(1, 4) 5631 - struct workqueue_struct *alloc_workqueue(const char *fmt, 5632 - unsigned int flags, 5633 - int max_active, ...) 5622 + static struct workqueue_struct *__alloc_workqueue(const char *fmt, 5623 + unsigned int flags, 5624 + int max_active, va_list args) 5634 5625 { 5635 - va_list args; 5636 5626 struct workqueue_struct *wq; 5637 5627 size_t wq_size; 5638 5628 int name_len; ··· 5662 5656 goto err_free_wq; 5663 5657 } 5664 5658 5665 - va_start(args, max_active); 5666 5659 name_len = vsnprintf(wq->name, sizeof(wq->name), fmt, args); 5667 - va_end(args); 5668 5660 5669 5661 if (name_len >= WQ_NAME_LEN) 5670 5662 pr_warn_once("workqueue: name exceeds WQ_NAME_LEN. Truncating to: %s\n", ··· 5692 5688 INIT_LIST_HEAD(&wq->flusher_overflow); 5693 5689 INIT_LIST_HEAD(&wq->maydays); 5694 5690 5695 - wq_init_lockdep(wq); 5696 5691 INIT_LIST_HEAD(&wq->list); 5697 5692 5698 5693 if (flags & WQ_UNBOUND) { 5699 5694 if (alloc_node_nr_active(wq->node_nr_active) < 0) 5700 - goto err_unreg_lockdep; 5695 + goto err_free_wq; 5701 5696 } 5702 5697 5703 5698 /* ··· 5735 5732 kthread_flush_worker(pwq_release_worker); 5736 5733 free_node_nr_active(wq->node_nr_active); 5737 5734 } 5738 - err_unreg_lockdep: 5739 - wq_unregister_lockdep(wq); 5740 - wq_free_lockdep(wq); 5741 5735 err_free_wq: 5742 5736 free_workqueue_attrs(wq->unbound_attrs); 5743 5737 kfree(wq); ··· 5745 5745 destroy_workqueue(wq); 5746 5746 return NULL; 5747 5747 } 5748 + 5749 + __printf(1, 4) 5750 + struct workqueue_struct *alloc_workqueue(const char *fmt, 5751 + unsigned int flags, 5752 + int max_active, ...) 5753 + { 5754 + struct workqueue_struct *wq; 5755 + va_list args; 5756 + 5757 + va_start(args, max_active); 5758 + wq = __alloc_workqueue(fmt, flags, max_active, args); 5759 + va_end(args); 5760 + if (!wq) 5761 + return NULL; 5762 + 5763 + wq_init_lockdep(wq); 5764 + 5765 + return wq; 5766 + } 5748 5767 EXPORT_SYMBOL_GPL(alloc_workqueue); 5768 + 5769 + #ifdef CONFIG_LOCKDEP 5770 + __printf(1, 5) 5771 + struct workqueue_struct * 5772 + alloc_workqueue_lockdep_map(const char *fmt, unsigned int flags, 5773 + int max_active, struct lockdep_map *lockdep_map, ...) 5774 + { 5775 + struct workqueue_struct *wq; 5776 + va_list args; 5777 + 5778 + va_start(args, lockdep_map); 5779 + wq = __alloc_workqueue(fmt, flags, max_active, args); 5780 + va_end(args); 5781 + if (!wq) 5782 + return NULL; 5783 + 5784 + wq->lockdep_map = lockdep_map; 5785 + 5786 + return wq; 5787 + } 5788 + EXPORT_SYMBOL_GPL(alloc_workqueue_lockdep_map); 5789 + #endif 5749 5790 5750 5791 static bool pwq_busy(struct pool_workqueue *pwq) 5751 5792 { ··· 7447 7406 static unsigned long wq_watchdog_touched = INITIAL_JIFFIES; 7448 7407 static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES; 7449 7408 7409 + static unsigned int wq_panic_on_stall; 7410 + module_param_named(panic_on_stall, wq_panic_on_stall, uint, 0644); 7411 + 7450 7412 /* 7451 7413 * Show workers that might prevent the processing of pending work items. 7452 7414 * The only candidates are CPU-bound workers in the running state. ··· 7499 7455 } 7500 7456 7501 7457 rcu_read_unlock(); 7458 + } 7459 + 7460 + static void panic_on_wq_watchdog(void) 7461 + { 7462 + static unsigned int wq_stall; 7463 + 7464 + if (wq_panic_on_stall) { 7465 + wq_stall++; 7466 + BUG_ON(wq_stall >= wq_panic_on_stall); 7467 + } 7502 7468 } 7503 7469 7504 7470 static void wq_watchdog_reset_touched(void) ··· 7582 7528 7583 7529 if (cpu_pool_stall) 7584 7530 show_cpu_pools_hogs(); 7531 + 7532 + if (lockup_detected) 7533 + panic_on_wq_watchdog(); 7585 7534 7586 7535 wq_watchdog_reset_touched(); 7587 7536 mod_timer(&wq_watchdog_timer, jiffies + thresh);