mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Petr Mladek <pmladek@suse.com>
To: Aaron Tomlin <atomlin@atomlin.com>
Cc: akpm@linux-foundation.org, lance.yang@linux.dev,
	mhiramat@kernel.org, linux-kernel@vger.kernel.org,
	david.laight.linux@gmail.com, neelx@suse.com, sean@ashe.io,
	chjohnst@gmail.com, steve@abita.co, mproche@gmail.com,
	nick.lange@gmail.com
Subject: Re: [PATCH v9 1/2] hung_task: Reset warning budget when problem gets resolved
Date: Wed, 26 Aug 2026 13:17:47 +0200	[thread overview]
Message-ID: <ao7LW7-3GjJzKNp0@pathway.suse.cz> (raw)
In-Reply-To: <20260814135718.494513-2-atomlin@atomlin.com>

Hi,

first, I am sorry for so late review. I had vacation, many
things accumulated, ...

On Fri 2026-08-14 09:57:17, Aaron Tomlin wrote:
> The sysctl hung_task_warnings currently holds both the configured warning
> limit and the remaining budget. Each detailed report decrements the
> sysctl, so once it reaches zero, the configured limit is lost and cannot
> be restored automatically.
> 
> Keep sysctl hung_task_warnings unchanged and track the remaining budget
> in hung_task_warnings_printed. Reset the runtime budget via an atomic flag
> when a watchdog check sees no hung tasks or when userspace writes a new
> sysctl value.
> 
> --- a/kernel/hung_task.c
> +++ b/kernel/hung_task.c
> @@ -59,6 +59,9 @@ static unsigned long __read_mostly sysctl_hung_task_check_interval_secs;
>  
>  static int __read_mostly sysctl_hung_task_warnings = 10;
>  
> +static int hung_task_warnings_printed = 10;

Nit: The name of the variable is a bit misleading in this final
     version. It does not longer count the number of printed
     messages.

     A better name might be "hung_task_warnings_budget" or so.

     It would be nice to change it if we need another version.
     And I am afraid that we would need it, see below.

     If we change it then I would also add comments explaining
     the difference between the two values, something like:

<proposal>
/*
 * Limit the number of printed hung tasks to prevent printing
 * the same or similar backtraces repeatedly.
 */
static int __read_mostly sysctl_hung_task_warnings = 10;
/*
 * The number of hung tasks which still can be reported.
 * The budget gets restored to the original limit when
 * the previous stall is resolved.
 */
static int hung_task_warnings_budget = 10;
</proposal>

> +static atomic_t reset_hung_task_warnings = ATOMIC_INIT(0);
> +
>  static int __read_mostly did_panic;
>  static bool hung_task_call_panic;
>  
> @@ -245,11 +248,11 @@ static void hung_task_info(struct task_struct *t, unsigned long timeout,
>  	/*
>  	 * The given task did not get scheduled for more than
>  	 * CONFIG_DEFAULT_HUNG_TASK_TIMEOUT. Therefore, complain
> -	 * accordingly
> +	 * accordingly with full details if the budget is not exhausted.
>  	 */
> -	if (sysctl_hung_task_warnings || hung_task_call_panic) {
> -		if (sysctl_hung_task_warnings > 0)
> -			sysctl_hung_task_warnings--;
> +	if (hung_task_warnings_printed || hung_task_call_panic) {
> +		if (hung_task_warnings_printed > 0)
> +			hung_task_warnings_printed--;
>  		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" : "",
>  		       (jiffies - t->last_switch_time) / HZ);
> @@ -264,7 +267,7 @@ static void hung_task_info(struct task_struct *t, unsigned long timeout,
>  		sched_show_task(t);
>  		debug_show_blocker(t, timeout);
>  
> -		if (!sysctl_hung_task_warnings)
> +		if (!hung_task_warnings_printed)
>  			pr_info("Future hung task reports are suppressed, see sysctl kernel.hung_task_warnings\n");
>  	}
>  
> @@ -304,7 +307,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
>  	unsigned long last_break = jiffies;
>  	struct task_struct *g, *t;
>  	unsigned long this_round_count;
> -	int need_warning = sysctl_hung_task_warnings;
> +	int need_warning;
>  	unsigned long si_mask = hung_task_si_mask;
>  
>  	/*
> @@ -314,6 +317,11 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
>  	if (test_taint(TAINT_DIE) || did_panic)
>  		return;
>  
> +	if (atomic_xchg(&reset_hung_task_warnings, 0))

I would use here atomic_xchg_acquire(). It serializes the ordering
of reset_hung_task_warnings vs sysctl_hung_task_warnings.
It would make it symetric with the barrier in the sysctl handler.

> +		hung_task_warnings_printed =
> +			READ_ONCE(sysctl_hung_task_warnings);

This would work only when "sysctl_hung_task_warnings"
is updated using WRITE_ONCE(). But it seems that this
is not the case. My understading is that it is updated by:

   + proc_dointvec_minmax()
     + do_proc_vec()
       + proc_get_long()
	 + strtoul_lenient()

which does a plain assigment:

static int strtoul_lenient(const char *cp, char **endp, unsigned int base,
			   unsigned long *res)
{
[...]
	*res = (unsigned long)result;
[...]
}

It can be solved by using temporary variable in proc_dointvec_minmax().
We have a custom proc_dohung_task_warnings() handler anyway.
See below.

> +	need_warning = hung_task_warnings_printed;
> +
>  	this_round_count = 0;
>  	rcu_read_lock();
>  	for_each_process_thread(g, t) {
> @@ -340,8 +348,11 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
>   unlock:
>  	rcu_read_unlock();
>  
> -	if (!this_round_count)
> +	if (!this_round_count) {
> +		hung_task_warnings_printed =
> +			READ_ONCE(sysctl_hung_task_warnings);
>  		return;
> +	}
>  
>  	if (need_warning || hung_task_call_panic) {
>  		si_mask |= SYS_INFO_LOCKS;
> @@ -425,6 +436,19 @@ static int proc_dohung_task_timeout_secs(const struct ctl_table *table, int writ
>  	return ret;
>  }
>  
> +static int proc_dohung_task_warnings(const struct ctl_table *table, int write,
> +				     void *buffer,
> +				     size_t *lenp, loff_t *ppos)
> +{
> +	int ret;
> +
> +	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
> +	if (!ret && write)
> +		atomic_set_release(&reset_hung_task_warnings, 1);
> +
> +	return ret;
> +}

We should use WRITE_ONCE() when updating proc_dohung_task_warnings.
So, we need similar trick with proxy_table like in
proc_dohung_task_detect_count. Something like, on top of this patch:

--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -444,13 +444,26 @@ static int proc_dohung_task_warnings(const struct ctl_table *table, int write,
 				     void *buffer,
 				     size_t *lenp, loff_t *ppos)
 {
+	struct ctl_table proxy_table;
+	int warnings;
 	int ret;
 
-	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
-	if (!ret && write)
-		atomic_set_release(&reset_hung_task_warnings, 1);
+	proxy_table = *table;
+	proxy_table.data = &warnings;
 
-	return ret;
+	if (SYSCTL_KERN_TO_USER(write))
+		warnings = READ_ONCE(sysctl_hung_task_warnings);
+
+	ret = proc_dointvec_minmax(&proxy_table, write, buffer, lenp, ppos);
+	if (ret < 0)
+		return ret;
+
+	if (SYSCTL_USER_TO_KERN(write)) {
+		WRITE_ONCE(sysctl_hung_task_warnings, warnings);
+		atomic_set_release(&reset_hung_task_warnings, 1);
+	}
+
+	return 0;
 }
 
 /*

Otherwise, it looks good to me.

Best Regards,
Petr

  parent reply	other threads:[~2026-08-26 11:17 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-14 13:57 [PATCH v9 0/2] hung_task: Improve warning budget handling and task reporting Aaron Tomlin
2026-08-14 13:57 ` [PATCH v9 1/2] hung_task: Reset warning budget when problem gets resolved Aaron Tomlin
2026-08-14 15:58   ` Lance Yang
2026-08-14 17:22     ` Aaron Tomlin
2026-08-26 11:17   ` Petr Mladek [this message]
2026-08-27 15:30     ` Lance Yang
2026-08-28  9:05       ` Petr Mladek
2026-08-28  9:22         ` Lance Yang
2026-08-29 13:54           ` Aaron Tomlin
2026-08-14 13:57 ` [PATCH v9 2/2] hung_task: Log summary line when warning budget is exhausted Aaron Tomlin
2026-08-14 16:27   ` Lance Yang
2026-08-14 17:26     ` Aaron Tomlin
2026-08-26 11:31     ` Petr Mladek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ao7LW7-3GjJzKNp0@pathway.suse.cz \
    --to=pmladek@suse.com \
    --cc=akpm@linux-foundation.org \
    --cc=atomlin@atomlin.com \
    --cc=chjohnst@gmail.com \
    --cc=david.laight.linux@gmail.com \
    --cc=lance.yang@linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mhiramat@kernel.org \
    --cc=mproche@gmail.com \
    --cc=neelx@suse.com \
    --cc=nick.lange@gmail.com \
    --cc=sean@ashe.io \
    --cc=steve@abita.co \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®