* [PATCH v4] hung_task: Deduplicate identical hang reports using explicit blocker tracking
@ 2026-06-27 20:57 Aaron Tomlin
2026-06-28 4:47 ` Lance Yang
0 siblings, 1 reply; 6+ messages in thread
From: Aaron Tomlin @ 2026-06-27 20:57 UTC (permalink / raw)
To: akpm, lance.yang, mhiramat, pmladek
Cc: linux-kernel, david.laight.linux, atomlin, neelx, sean, chjohnst,
steve, mproche, nick.lange
Currently, during severe lock contention, multiple tasks can hang while
waiting on the exact same resource. The khungtaskd kthread
indiscriminately reports every single instance with a stack trace.
This can roll the kernel ring buffer and prematurely exhaust the
kernel.hung_task_warnings budget. Consequently, the kernel is left
entirely blind to subsequent, unrelated deadlocks.
To preserve the warning budget and ring buffer without sacrificing
observability, this patch introduces a two-tier deduplication mechanism:
1. Introduces a hung_task_reported in task_struct. If a task remains
hung across multiple check intervals, khungtaskd suppresses
redundant stack traces for that specific task until it makes
progress (verified via context switch counters). Furthermore, it
is packed into an existing compiler alignment hole, consuming
zero additional memory
2. For tasks detected in the same scan, we leverage the existing
CONFIG_DETECT_HUNG_TASK_BLOCKER infrastructure. By hashing the
exact memory address of the lock causing the block, extracted
from t->blocker, the kernel deterministically groups tasks
waiting on the identical resource
3. For duplicate tasks, we still print the single-line "INFO: task
..." message and trigger tracepoint trace_sched_process_hang().
It merely skips calling sched_show_task() and
debug_show_blocker(), printing a concise suppression notice
instead
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
Changes since v3:
- Deduct from the global budget if printing a full stack trace
- Pivoted from heuristic Wait Channel hashing to deterministic
blocker address hashing via CONFIG_DETECT_HUNG_TASK_BLOCKER
- Replaced the hung_task_reported bit-field with a standalone u8 byte.
Move hung_task_reported into an existing structural alignment hole
within task_struct following blocked_lock, resulting in zero overall
memory footprint increase and optimal cacheline grouping
- Linked to v3: https://lore.kernel.org/lkml/20260621213756.43225-1-atomlin@atomlin.com/
Changes since v2:
- Replaced the per-round cache flush with a task_struct bit-field for
persistent cross-scan tracking, mitigating delayed budget exhaustion
- Abandoned exact-stack hashing in favour of Wait Channel hashing
- Transitioned from jhash() to hash_long() to optimise single-pointer
hashing, and relocated the hash map to the local stack
- Linked to v2: https://lore.kernel.org/lkml/20260620013559.1537893-1-atomlin@atomlin.com/
Changes since v1:
- Preserve "INFO:" headers for all hung tasks; suppress only the stack
dumps for duplicates (Masami Hiramatsu)
- Print a clear notification when a trace is explicitly suppressed
- Add #ifdef CONFIG_STACKTRACE guards to prevent Kconfig build errors
- Optimise overhead by unwinding the stack only if a warning is
actually going to be printed
- Linked to v1: https://lore.kernel.org/lkml/20260617184841.1447955-1-atomlin@atomlin.com/
---
include/linux/hung_task.h | 1 +
include/linux/sched.h | 3 +++
kernel/hung_task.c | 43 ++++++++++++++++++++++++++++++++++-----
3 files changed, 42 insertions(+), 5 deletions(-)
diff --git a/include/linux/hung_task.h b/include/linux/hung_task.h
index c4403eeb7144..3b161f284a7b 100644
--- a/include/linux/hung_task.h
+++ b/include/linux/hung_task.h
@@ -36,6 +36,7 @@
#define BLOCKER_TYPE_RWSEM_WRITER 0x03UL
#define BLOCKER_TYPE_MASK 0x03UL
+#define BLOCKER_HASH_BITS 6
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
static inline void hung_task_set_blocker(void *lock, unsigned long type)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index b3204a15d512..deb092ff8a9a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1252,6 +1252,9 @@ struct task_struct {
struct mutex *blocked_on; /* lock we're blocked on */
raw_spinlock_t blocked_lock;
+#ifdef CONFIG_DETECT_HUNG_TASK
+ u8 hung_task_reported;
+#endif
/*
* The task that is boosting this task; a back link for the current
* donor stack. Set in schedule() -> find_proxy_task() and only stable
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index 6fcc94ce4ca9..a94f570b33d5 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -25,6 +25,7 @@
#include <linux/hung_task.h>
#include <linux/rwsem.h>
#include <linux/sys_info.h>
+#include <linux/hash.h>
#include <trace/events/sched.h>
@@ -125,6 +126,7 @@ static bool task_is_hung(struct task_struct *t, unsigned long timeout)
if (switch_count != t->last_switch_count) {
t->last_switch_count = switch_count;
t->last_switch_time = jiffies;
+ t->hung_task_reported = 0;
return false;
}
if (time_is_after_jiffies(t->last_switch_time + timeout * HZ))
@@ -228,12 +230,14 @@ static inline void debug_show_blocker(struct task_struct *task, unsigned long ti
* @t: Pointer to the detected hung task.
* @timeout: Timeout threshold for detecting hung tasks
* @this_round_count: Count of hung tasks detected in the current iteration
+ * @skip_show_task: Indicating if stack trace should be skipped
*
* Print structured information about the specified hung task, if warnings
* are enabled or if the panic batch threshold is exceeded.
*/
static void hung_task_info(struct task_struct *t, unsigned long timeout,
- unsigned long this_round_count)
+ unsigned long this_round_count,
+ unsigned int skip_show_task)
{
trace_sched_process_hang(t);
@@ -248,7 +252,11 @@ static void hung_task_info(struct task_struct *t, unsigned long timeout,
* accordingly
*/
if (sysctl_hung_task_warnings || hung_task_call_panic) {
- if (sysctl_hung_task_warnings > 0)
+ /*
+ * Do not exhaust the global warning budget for duplicates;
+ * only decrement if a full stack trace is being printed.
+ */
+ if (!skip_show_task && sysctl_hung_task_warnings > 0)
sysctl_hung_task_warnings--;
pr_err("INFO: task %s:%d blocked%s for more than %ld seconds.\n",
t->comm, t->pid, t->in_iowait ? " in I/O wait" : "",
@@ -261,8 +269,12 @@ static void hung_task_info(struct task_struct *t, unsigned long timeout,
pr_err(" Blocked by coredump.\n");
pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
" disables this message.\n");
- sched_show_task(t);
- debug_show_blocker(t, timeout);
+ if (!skip_show_task) {
+ sched_show_task(t);
+ debug_show_blocker(t, timeout);
+ } else {
+ pr_err(" Stack trace suppressed. Already reported or duplicate\n");
+ }
if (!sysctl_hung_task_warnings)
pr_info("Future hung task reports are suppressed, see sysctl kernel.hung_task_warnings\n");
@@ -306,6 +318,11 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
unsigned long this_round_count;
int need_warning = sysctl_hung_task_warnings;
unsigned long si_mask = hung_task_si_mask;
+ unsigned int skip_show_task;
+#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
+ unsigned long blocker, blocker_hash[1 << BLOCKER_HASH_BITS] = { 0 };
+ unsigned int hash;
+#endif
/*
* If the system crashed already then all bets are off,
@@ -326,6 +343,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
}
if (task_is_hung(t, timeout)) {
+ skip_show_task = t->hung_task_reported;
/*
* Increment the global counter so that userspace could
* start migrating tasks ASAP. But count the current
@@ -334,7 +352,22 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
*/
atomic_long_inc(&sysctl_hung_task_detect_count);
this_round_count++;
- hung_task_info(t, timeout, this_round_count);
+
+#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
+ blocker = READ_ONCE(t->blocker);
+ if (blocker) {
+ blocker &= ~BLOCKER_TYPE_MASK;
+ hash = hash_long(blocker, BLOCKER_HASH_BITS);
+ if (blocker_hash[hash] == blocker)
+ skip_show_task = 1;
+ else
+ blocker_hash[hash] = blocker;
+ }
+#endif
+
+ hung_task_info(t, timeout, this_round_count,
+ skip_show_task);
+ t->hung_task_reported = 1;
}
}
unlock:
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v4] hung_task: Deduplicate identical hang reports using explicit blocker tracking
2026-06-27 20:57 [PATCH v4] hung_task: Deduplicate identical hang reports using explicit blocker tracking Aaron Tomlin
@ 2026-06-28 4:47 ` Lance Yang
2026-06-28 20:56 ` Aaron Tomlin
0 siblings, 1 reply; 6+ messages in thread
From: Lance Yang @ 2026-06-28 4:47 UTC (permalink / raw)
To: atomlin
Cc: akpm, lance.yang, mhiramat, pmladek, linux-kernel,
david.laight.linux, neelx, sean, chjohnst, steve, mproche,
nick.lange
Sorry, but NACK from me.
Aaron, please slow down a bit here!
I already said in v2 that the discussion didn't feel settled, and asked
you to wait before another spin. v3 didn't settle it either ...
Replying to comments is *not* the same as settling review ... If any
reviewer/maintainer still doesn't agree this should go in, please read
the room a bit and stop spining new versions until we agree on the next
move.
If v3 didn't settle it (i.e. we didn't agree on the next move), please
don't just spin v4. Step back first: what real problem does this solve?
If this isn't really a real-world problem at all, why keep spinning it?
At that point it starts looking less like review and more like patch
churn. That usually doesnt land, it just *burns* reviewer time ...
I'd rather spend review time on patches where we at least agree the
problem is real. I assume you'd prefer that too :)
So yeah, still a NACK from me. If new versions keep coming before the
discussion settles, I'll keep NACKing them ...
Thanks, Lance
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4] hung_task: Deduplicate identical hang reports using explicit blocker tracking
2026-06-28 4:47 ` Lance Yang
@ 2026-06-28 20:56 ` Aaron Tomlin
2026-07-02 13:19 ` Petr Mladek
0 siblings, 1 reply; 6+ messages in thread
From: Aaron Tomlin @ 2026-06-28 20:56 UTC (permalink / raw)
To: Lance Yang
Cc: akpm, mhiramat, pmladek, linux-kernel, david.laight.linux, neelx,
sean, chjohnst, steve, mproche, nick.lange
On Sun, Jun 28, 2026 at 12:47:50PM +0800, Lance Yang wrote:
> Sorry, but NACK from me.
>
> Aaron, please slow down a bit here!
>
> I already said in v2 that the discussion didn't feel settled, and asked
> you to wait before another spin. v3 didn't settle it either ...
>
> Replying to comments is *not* the same as settling review ... If any
> reviewer/maintainer still doesn't agree this should go in, please read
> the room a bit and stop spining new versions until we agree on the next
> move.
>
> If v3 didn't settle it (i.e. we didn't agree on the next move), please
> don't just spin v4. Step back first: what real problem does this solve?
> If this isn't really a real-world problem at all, why keep spinning it?
>
> At that point it starts looking less like review and more like patch
> churn. That usually doesnt land, it just *burns* reviewer time ...
>
> I'd rather spend review time on patches where we at least agree the
> problem is real. I assume you'd prefer that too :)
>
> So yeah, still a NACK from me. If new versions keep coming before the
> discussion settles, I'll keep NACKing them ...
>
> Thanks, Lance
Hi Lance,
I completely understand your frustration, and I am sorry for rushing out
the revisions too quickly. I will certainly hold off on sending any further
versions until we have reached a collective agreement on the path forward.
To step back and address your question directly regarding the real-world
problem this patch aims to solve:
In large-scale, multi-tenant, production environments, lock contention is a
frequent reality. When a core resource (e.g., a heavily contended rwsem or
mutex) blocks, it does not just hang one task; it causes a cascading
failure that halts hundreds of tasks simultaneously.
When khungtaskd runs its scan during such an outage, it often reports
identical stack traces into the kernel ring buffer, which is not entirely
useful.
The global sysctl_hung_task_warnings budget is instantly exhausted by a
single lock storm. Consequently, the kernel is left entirely blind to
subsequent, completely unrelated deadlocks occurring elsewhere in the
system hours later.
The changes introduced to date, moving away from the heuristic wchan
approach to a more deterministic t->blocker tracking as per Petr's
feedback, were an attempt to solve this without introducing complex
heuristics or dangerous blind spots.
Kind regards,
--
Aaron Tomlin
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4] hung_task: Deduplicate identical hang reports using explicit blocker tracking
2026-06-28 20:56 ` Aaron Tomlin
@ 2026-07-02 13:19 ` Petr Mladek
2026-07-04 21:35 ` Aaron Tomlin
0 siblings, 1 reply; 6+ messages in thread
From: Petr Mladek @ 2026-07-02 13:19 UTC (permalink / raw)
To: Aaron Tomlin
Cc: Lance Yang, akpm, mhiramat, linux-kernel, david.laight.linux,
neelx, sean, chjohnst, steve, mproche, nick.lange
On Sun 2026-06-28 16:56:39, Aaron Tomlin wrote:
> On Sun, Jun 28, 2026 at 12:47:50PM +0800, Lance Yang wrote:
> To step back and address your question directly regarding the real-world
> problem this patch aims to solve:
Thanks a lot for slowing down. It allows people to think more about
the problem and get feedback from more poeple. And it reduces the risk
of burn out of maintainers and reviewers.
> In large-scale, multi-tenant, production environments, lock contention is a
> frequent reality. When a core resource (e.g., a heavily contended rwsem or
> mutex) blocks, it does not just hang one task; it causes a cascading
> failure that halts hundreds of tasks simultaneously.
>
> When khungtaskd runs its scan during such an outage, it often reports
> identical stack traces into the kernel ring buffer, which is not entirely
> useful.
>
> The global sysctl_hung_task_warnings budget is instantly exhausted by a
> single lock storm. Consequently, the kernel is left entirely blind to
> subsequent, completely unrelated deadlocks occurring elsewhere in the
> system hours later.
>
> The changes introduced to date, moving away from the heuristic wchan
> approach to a more deterministic t->blocker tracking as per Petr's
> feedback, were an attempt to solve this without introducing complex
> heuristics or dangerous blind spots.
I would split this into two problems:
1. A single lock contention might trigger hung_report for many tasks
waiting for the same lock. It bloats the kernel log and messages
might even get lost.
2. The number of printed backtraces can be reduced by a global limit.
But the limit silences the hung task detector and system
administrators are blind once the limit is reached.
IMHO, the global limit "sysctl_hung_task_warnings" has been introduced
because of the 1st problem but it caused the 2nd problem.
My proposal:
------------
a) We could Change the semantic of "sysctl_hung_task_warnings". It could newly
limit the number of printed backtraces in a single hung-system
situations. I mean to reset it when the check_hung_uninterruptible_tasks()
does not detect any blocked tasks.
We could even print a message in this case. Something like:
if (atomic_long_read(&sysctl_hung_task_detect_count) && !this_round_count) {
pr_err("INFO: Tasks are not blocked by sleeping locks any longer.\n");
atomic_long_set(&sysctl_hung_task_detect_count, 0);
}
This would keep it working for 1st problem and solve the 2nd problem.
b) I like the check of task->blocker when it is available. But it
depends on CONFIG_DETECT_HUNG_TASK_BLOCKER. Also the hash array
looks like an overkill to me.
I would replace the hash array with a simple array[10]. It
should be enough in practice. Also it would be much easier
to clear it when the hung situation has gone.
That said, I am not sure if it is worth it.
c) Also storing the info about printed backtraces into struct
task_struct is interesting idea.
But again, I am not sure if it is worth it.
My opinion:
-----------
I would start with a). It is trivial. It solves the regression caused
by the current global limit. And the message about that
the hung-situation has been resolved is useful. So it
looks like win-win solution.
I would do b) and/or c) only when a) is not enough in practice.
That said:
----------
IMHO, CONFIG_DETECT_HUNG_TASK_BLOCKER is a rather cheap feature.
I believe that the overhead is small especially when we are
talking about sleeping locks. It is even enabled by default.
Adding the filtering by the blocker might be more effective
in practice than the "sysctl_hung_task_warnings" global
limit.
Best Regards,
Petr
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4] hung_task: Deduplicate identical hang reports using explicit blocker tracking
2026-07-02 13:19 ` Petr Mladek
@ 2026-07-04 21:35 ` Aaron Tomlin
2026-07-07 12:43 ` Petr Mladek
0 siblings, 1 reply; 6+ messages in thread
From: Aaron Tomlin @ 2026-07-04 21:35 UTC (permalink / raw)
To: Petr Mladek
Cc: Lance Yang, akpm, mhiramat, linux-kernel, david.laight.linux,
neelx, sean, chjohnst, steve, mproche, nick.lange
On Thu, Jul 02, 2026 at 03:19:18PM +0200, Petr Mladek wrote:
> On Sun 2026-06-28 16:56:39, Aaron Tomlin wrote:
> > On Sun, Jun 28, 2026 at 12:47:50PM +0800, Lance Yang wrote:
> > To step back and address your question directly regarding the real-world
> > problem this patch aims to solve:
>
> Thanks a lot for slowing down. It allows people to think more about
> the problem and get feedback from more poeple. And it reduces the risk
> of burn out of maintainers and reviewers.
>
> > In large-scale, multi-tenant, production environments, lock contention is a
> > frequent reality. When a core resource (e.g., a heavily contended rwsem or
> > mutex) blocks, it does not just hang one task; it causes a cascading
> > failure that halts hundreds of tasks simultaneously.
> >
> > When khungtaskd runs its scan during such an outage, it often reports
> > identical stack traces into the kernel ring buffer, which is not entirely
> > useful.
> >
> > The global sysctl_hung_task_warnings budget is instantly exhausted by a
> > single lock storm. Consequently, the kernel is left entirely blind to
> > subsequent, completely unrelated deadlocks occurring elsewhere in the
> > system hours later.
> >
> > The changes introduced to date, moving away from the heuristic wchan
> > approach to a more deterministic t->blocker tracking as per Petr's
> > feedback, were an attempt to solve this without introducing complex
> > heuristics or dangerous blind spots.
>
> I would split this into two problems:
>
> 1. A single lock contention might trigger hung_report for many tasks
> waiting for the same lock. It bloats the kernel log and messages
> might even get lost.
>
> 2. The number of printed backtraces can be reduced by a global limit.
> But the limit silences the hung task detector and system
> administrators are blind once the limit is reached.
>
> IMHO, the global limit "sysctl_hung_task_warnings" has been introduced
> because of the 1st problem but it caused the 2nd problem.
>
> My proposal:
> ------------
>
> a) We could Change the semantic of "sysctl_hung_task_warnings". It could newly
> limit the number of printed backtraces in a single hung-system
> situations. I mean to reset it when the check_hung_uninterruptible_tasks()
> does not detect any blocked tasks.
>
> We could even print a message in this case. Something like:
>
> if (atomic_long_read(&sysctl_hung_task_detect_count) && !this_round_count) {
> pr_err("INFO: Tasks are not blocked by sleeping locks any longer.\n");
> atomic_long_set(&sysctl_hung_task_detect_count, 0);
> }
>
> This would keep it working for 1st problem and solve the 2nd problem.
>
>
> b) I like the check of task->blocker when it is available. But it
> depends on CONFIG_DETECT_HUNG_TASK_BLOCKER. Also the hash array
> looks like an overkill to me.
>
> I would replace the hash array with a simple array[10]. It
> should be enough in practice. Also it would be much easier
> to clear it when the hung situation has gone.
>
> That said, I am not sure if it is worth it.
>
>
> c) Also storing the info about printed backtraces into struct
> task_struct is interesting idea.
>
> But again, I am not sure if it is worth it.
>
>
> My opinion:
> -----------
>
> I would start with a). It is trivial. It solves the regression caused
> by the current global limit. And the message about that
> the hung-situation has been resolved is useful. So it
> looks like win-win solution.
>
> I would do b) and/or c) only when a) is not enough in practice.
>
> That said:
> ----------
>
> IMHO, CONFIG_DETECT_HUNG_TASK_BLOCKER is a rather cheap feature.
> I believe that the overhead is small especially when we are
> talking about sleeping locks. It is even enabled by default.
>
> Adding the filtering by the blocker might be more effective
> in practice than the "sysctl_hung_task_warnings" global
> limit.
>
> Best Regards,
Hi Petr,
Thank you for the detailed breakdown and for taking the time to review the
underlying issues. I appreciate the advice regarding the development
cadence; taking a step back to consider broader feedback is certainly
prudent, and I am grateful for your perspective.
Your proposal (a) is indeed elegant. Resetting sysctl_hung_task_warnings
when check_hung_uninterruptible_tasks() detects zero blocked tasks provides
a clean, deterministic way to recover from the "blind spot" regression
without adding architectural complexity.
Regarding the blocker tracking, I take your point that a hash array is
likely overkill for the common scenarios encountered in production. I
suggest we combine your proposal (a) with a simplified version of (b):
implementing a fixed-size array (e.g., array[10]) to track unique blockers.
This hybrid approach would function as follows:
1. When khungtaskd identifies a hung task, it compares the blocker
against the array. If the blocker is already tracked, we suppress
the warning, which keeps our sysctl_hung_task_warnings budget
intact. If the blocker is new, we print the warning, add it to the
array, and decrement the budget.
2. As you suggested, we reset the budget and clear the array[10] once
the hang resolves, accompanied by your proposed recovery message in
the ring buffer.
This seems to offer the best of both worlds: it provides the necessary
filtering to prevent log bloat during lock storms while ensuring the system
remains observable once the contention clears. It also adheres to the
principle of addressing the primary regression while keeping the
implementation overhead minimal.
Regarding the size of the array, I initially considered a size of 10 to
keep the footprint minimal. However, I am happy to increase this to 32 to
ensure we have sufficient coverage for complex multi-lock contention
scenarios without incurring significant cache overhead. Does 32 strike you
as a reasonable middle ground, or would you prefer I stick to a smaller
fixed size?
I am happy to draft a v5 patch that combines these elements, should you
agree that this remains a sensible direction.
Kind regards,
--
Aaron Tomlin
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4] hung_task: Deduplicate identical hang reports using explicit blocker tracking
2026-07-04 21:35 ` Aaron Tomlin
@ 2026-07-07 12:43 ` Petr Mladek
0 siblings, 0 replies; 6+ messages in thread
From: Petr Mladek @ 2026-07-07 12:43 UTC (permalink / raw)
To: Aaron Tomlin
Cc: Lance Yang, akpm, mhiramat, linux-kernel, david.laight.linux,
neelx, sean, chjohnst, steve, mproche, nick.lange
On Sat 2026-07-04 17:35:29, Aaron Tomlin wrote:
> On Thu, Jul 02, 2026 at 03:19:18PM +0200, Petr Mladek wrote:
> > On Sun 2026-06-28 16:56:39, Aaron Tomlin wrote:
> > > On Sun, Jun 28, 2026 at 12:47:50PM +0800, Lance Yang wrote:
> > > To step back and address your question directly regarding the real-world
> > > problem this patch aims to solve:
> >
> > Thanks a lot for slowing down. It allows people to think more about
> > the problem and get feedback from more poeple. And it reduces the risk
> > of burn out of maintainers and reviewers.
> >
> > > In large-scale, multi-tenant, production environments, lock contention is a
> > > frequent reality. When a core resource (e.g., a heavily contended rwsem or
> > > mutex) blocks, it does not just hang one task; it causes a cascading
> > > failure that halts hundreds of tasks simultaneously.
> > >
> > > When khungtaskd runs its scan during such an outage, it often reports
> > > identical stack traces into the kernel ring buffer, which is not entirely
> > > useful.
> > >
> > > The global sysctl_hung_task_warnings budget is instantly exhausted by a
> > > single lock storm. Consequently, the kernel is left entirely blind to
> > > subsequent, completely unrelated deadlocks occurring elsewhere in the
> > > system hours later.
> > >
> > > The changes introduced to date, moving away from the heuristic wchan
> > > approach to a more deterministic t->blocker tracking as per Petr's
> > > feedback, were an attempt to solve this without introducing complex
> > > heuristics or dangerous blind spots.
> >
> > I would split this into two problems:
> >
> > 1. A single lock contention might trigger hung_report for many tasks
> > waiting for the same lock. It bloats the kernel log and messages
> > might even get lost.
> >
> > 2. The number of printed backtraces can be reduced by a global limit.
> > But the limit silences the hung task detector and system
> > administrators are blind once the limit is reached.
> >
> > IMHO, the global limit "sysctl_hung_task_warnings" has been introduced
> > because of the 1st problem but it caused the 2nd problem.
> >
> > My proposal:
> > ------------
> >
> > a) We could Change the semantic of "sysctl_hung_task_warnings". It could newly
> > limit the number of printed backtraces in a single hung-system
> > situations. I mean to reset it when the check_hung_uninterruptible_tasks()
> > does not detect any blocked tasks.
> >
> > We could even print a message in this case. Something like:
> >
> > if (atomic_long_read(&sysctl_hung_task_detect_count) && !this_round_count) {
> > pr_err("INFO: Tasks are not blocked by sleeping locks any longer.\n");
> > atomic_long_set(&sysctl_hung_task_detect_count, 0);
> > }
> >
> > This would keep it working for 1st problem and solve the 2nd problem.
> >
> >
> > b) I like the check of task->blocker when it is available. But it
> > depends on CONFIG_DETECT_HUNG_TASK_BLOCKER. Also the hash array
> > looks like an overkill to me.
> >
> > I would replace the hash array with a simple array[10]. It
> > should be enough in practice. Also it would be much easier
> > to clear it when the hung situation has gone.
> >
> > That said, I am not sure if it is worth it.
> >
> >
> > c) Also storing the info about printed backtraces into struct
> > task_struct is interesting idea.
> >
> > But again, I am not sure if it is worth it.
> >
> >
> > My opinion:
> > -----------
> >
> > I would start with a). It is trivial. It solves the regression caused
> > by the current global limit. And the message about that
> > the hung-situation has been resolved is useful. So it
> > looks like win-win solution.
> >
> > I would do b) and/or c) only when a) is not enough in practice.
> >
> > That said:
> > ----------
> >
> > IMHO, CONFIG_DETECT_HUNG_TASK_BLOCKER is a rather cheap feature.
> > I believe that the overhead is small especially when we are
> > talking about sleeping locks. It is even enabled by default.
> >
> > Adding the filtering by the blocker might be more effective
> > in practice than the "sysctl_hung_task_warnings" global
> > limit.
> >
> > Best Regards,
>
> Hi Petr,
>
> Thank you for the detailed breakdown and for taking the time to review the
> underlying issues. I appreciate the advice regarding the development
> cadence; taking a step back to consider broader feedback is certainly
> prudent, and I am grateful for your perspective.
>
> Your proposal (a) is indeed elegant. Resetting sysctl_hung_task_warnings
> when check_hung_uninterruptible_tasks() detects zero blocked tasks provides
> a clean, deterministic way to recover from the "blind spot" regression
> without adding architectural complexity.
>
> Regarding the blocker tracking, I take your point that a hash array is
> likely overkill for the common scenarios encountered in production. I
> suggest we combine your proposal (a) with a simplified version of (b):
> implementing a fixed-size array (e.g., array[10]) to track unique blockers.
>
> This hybrid approach would function as follows:
>
> 1. When khungtaskd identifies a hung task, it compares the blocker
> against the array. If the blocker is already tracked, we suppress
> the warning, which keeps our sysctl_hung_task_warnings budget
> intact. If the blocker is new, we print the warning, add it to the
> array, and decrement the budget.
>
> 2. As you suggested, we reset the budget and clear the array[10] once
> the hang resolves, accompanied by your proposed recovery message in
> the ring buffer.
>
> This seems to offer the best of both worlds: it provides the necessary
> filtering to prevent log bloat during lock storms while ensuring the system
> remains observable once the contention clears. It also adheres to the
> principle of addressing the primary regression while keeping the
> implementation overhead minimal.
I agree.
> Regarding the size of the array, I initially considered a size of 10 to
> keep the footprint minimal. However, I am happy to increase this to 32 to
> ensure we have sufficient coverage for complex multi-lock contention
> scenarios without incurring significant cache overhead. Does 32 strike you
> as a reasonable middle ground, or would you prefer I stick to a smaller
> fixed size?
32 sounds like a good compromise. We should print a warning when
it gets full. Let's see how it works in practice.
> I am happy to draft a v5 patch that combines these elements, should you
> agree that this remains a sensible direction.
Sounds reasonable from my POV.
Best Regards,
Petr
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-07-07 12:43 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-27 20:57 [PATCH v4] hung_task: Deduplicate identical hang reports using explicit blocker tracking Aaron Tomlin
2026-06-28 4:47 ` Lance Yang
2026-06-28 20:56 ` Aaron Tomlin
2026-07-02 13:19 ` Petr Mladek
2026-07-04 21:35 ` Aaron Tomlin
2026-07-07 12:43 ` Petr Mladek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox