Existing documentation has a write of "1" to clear/reset all the
WARN_ONCE and similar to the as-booted state, so they can possibly
be re-triggered again during debugging/testing.

But having them auto-reset once a day, or once a week, might shed
valuable information to a sysadmin on what the system is doing while
trying to debug an issue.

Here we extend the existing debugfs variable to bind a timer to the
written value N, so that it will reset every N minutes, for N>1.
Writing a zero will clear any previously set timer value.

The pre-existing behaviour of writing N=1 will do a one-shot clear.

Link: 
https://lore.kernel.org/r/[email protected]
Signed-off-by: Paul Gortmaker <[email protected]>
---
 .../admin-guide/clearing-warn-once.rst        |  9 ++++++
 kernel/panic.c                                | 32 +++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/Documentation/admin-guide/clearing-warn-once.rst 
b/Documentation/admin-guide/clearing-warn-once.rst
index 211fd926cf00..8d058bbc0859 100644
--- a/Documentation/admin-guide/clearing-warn-once.rst
+++ b/Documentation/admin-guide/clearing-warn-once.rst
@@ -7,3 +7,12 @@ echo 1 > /sys/kernel/debug/clear_warn_once
 
 clears the state and allows the warnings to print once again.
 This can be useful after test suite runs to reproduce problems.
+
+Values greater than one set a timer for a periodic state reset; e.g.
+
+echo 60 > /sys/kernel/debug/clear_warn_once
+
+will establish an hourly state reset, effectively turning WARN_ONCE
+into a long period rate-limited warning.
+
+Writing a value of zero (or one) will remove any previously set timer.
diff --git a/kernel/panic.c b/kernel/panic.c
index 53088219d7df..e3a462e39062 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -636,6 +636,7 @@ EXPORT_SYMBOL(__warn_printk);
 /* Support resetting WARN*_ONCE state */
 
 static u64 clear_warn_once;
+static bool warn_timer_active;
 
 static void do_clear_warn_once(void)
 {
@@ -643,6 +644,14 @@ static void do_clear_warn_once(void)
        memset(__start_once, 0, __end_once - __start_once);
 }
 
+static void timer_warn_once(struct timer_list *timer)
+{
+       do_clear_warn_once();
+       timer->expires = jiffies + clear_warn_once * HZ * 60;
+       add_timer(timer);
+}
+static DEFINE_TIMER(warn_reset_timer, timer_warn_once);
+
 static int warn_once_get(void *data, u64 *val)
 {
        *val = clear_warn_once;
@@ -653,6 +662,29 @@ static int warn_once_set(void *data, u64 val)
 {
        clear_warn_once = val;
 
+       if (val > 1) {          /* set/reset new timer */
+               unsigned long expires = jiffies + val * HZ * 60;
+
+               if (warn_timer_active) {
+                       mod_timer(&warn_reset_timer, expires);
+               } else {
+                       warn_timer_active = 1;
+                       warn_reset_timer.expires = expires;
+                       add_timer(&warn_reset_timer);
+               }
+               return 0;
+       }
+
+       if (warn_timer_active) {
+               del_timer_sync(&warn_reset_timer);
+               warn_timer_active = 0;
+       }
+       clear_warn_once = 0;
+
+       if (val == 0)           /* cleared timer, we are done */
+               return 0;
+
+       /* Getting here means val == 1  --->  so clear existing data */
        do_clear_warn_once();
        return 0;
 }
-- 
2.17.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#9277): 
https://lists.yoctoproject.org/g/linux-yocto/message/9277
Mute This Topic: https://lists.yoctoproject.org/mt/79006235/21656
Group Owner: [email protected]
Unsubscribe: https://lists.yoctoproject.org/g/linux-yocto/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to