Commit f9a60d34 authored by Xuewen Yan's avatar Xuewen Yan Committed by Wen Zhiwei
Browse files

workqueue: Add rcu lock check at the end of work item execution

stable inclusion
from stable-v6.6.72
commit 2717b5e55a9fb099a20eac6ab997e90261de72ae
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IBQN9L

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=2717b5e55a9fb099a20eac6ab997e90261de72ae



--------------------------------

[ Upstream commit 1a65a6d17cbc58e1aeffb2be962acce49efbef9c ]

Currently the workqueue just checks the atomic and locking states after work
execution ends. However, sometimes, a work item may not unlock rcu after
acquiring rcu_read_lock(). And as a result, it would cause rcu stall, but
the rcu stall warning can not dump the work func, because the work has
finished.

In order to quickly discover those works that do not call rcu_read_unlock()
after rcu_read_lock(), add the rcu lock check.

Use rcu_preempt_depth() to check the work's rcu status. Normally, this value
is 0. If this value is bigger than 0, it means the work are still holding
rcu lock. If so, print err info and the work func.

tj: Reworded the description for clarity. Minor formatting tweak.

Signed-off-by: default avatarXuewen Yan <xuewen.yan@unisoc.com>
Reviewed-by: default avatarLai Jiangshan <jiangshanlai@gmail.com>
Reviewed-by: default avatarWaiman Long <longman@redhat.com>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Stable-dep-of: de35994ecd2d ("workqueue: Do not warn when cancelling WQ_MEM_RECLAIM work from !WQ_MEM_RECLAIM worker")
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarWen Zhiwei <wenzhiwei@kylinos.cn>
parent 00dd0099
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -2638,11 +2638,12 @@ __acquires(&pool->lock)
	lock_map_release(&lockdep_map);
	lock_map_release(&pwq->wq->lockdep_map);

	if (unlikely(in_atomic() || lockdep_depth(current) > 0)) {
		pr_err("BUG: workqueue leaked lock or atomic: %s/0x%08x/%d\n"
	if (unlikely(in_atomic() || lockdep_depth(current) > 0 ||
		     rcu_preempt_depth() > 0)) {
		pr_err("BUG: workqueue leaked lock or atomic: %s/0x%08x/%d/%d\n"
		       "     last function: %ps\n",
		       current->comm, preempt_count(), task_pid_nr(current),
		       worker->current_func);
		       current->comm, preempt_count(), rcu_preempt_depth(),
		       task_pid_nr(current), worker->current_func);
		debug_show_held_locks(current);
		dump_stack();
	}