lkml.org 
[lkml]   [2022]   [Feb]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH printk v1 08/13] printk: add pr_flush()
    Date
    Provide a might-sleep function to allow waiting for threaded console
    printers to catch up to the latest logged message.

    Use pr_flush() whenever it is desirable to get buffered messages
    printed before continuing: suspend_console(), resume_console(),
    console_stop(), console_start(), console_unblank().

    Signed-off-by: John Ogness <john.ogness@linutronix.de>
    ---
    include/linux/printk.h | 7 ++++
    kernel/printk/printk.c | 73 +++++++++++++++++++++++++++++++++++++++++-
    2 files changed, 79 insertions(+), 1 deletion(-)

    diff --git a/include/linux/printk.h b/include/linux/printk.h
    index cd8192e611a1..6596f02d1f05 100644
    --- a/include/linux/printk.h
    +++ b/include/linux/printk.h
    @@ -170,6 +170,8 @@ extern void __printk_safe_exit(void);
    #define printk_deferred_enter __printk_safe_enter
    #define printk_deferred_exit __printk_safe_exit

    +extern bool pr_flush(int timeout_ms, bool reset_on_progress);
    +
    /*
    * Please don't use printk_ratelimit(), because it shares ratelimiting state
    * with all other unrelated printk_ratelimit() callsites. Instead use
    @@ -224,6 +226,11 @@ static inline void printk_deferred_exit(void)
    {
    }

    +static inline bool pr_flush(int timeout_ms, bool reset_on_progress)
    +{
    + return true;
    +}
    +
    static inline int printk_ratelimit(void)
    {
    return 0;
    diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
    index 02bde45c1149..1e80fd052bd5 100644
    --- a/kernel/printk/printk.c
    +++ b/kernel/printk/printk.c
    @@ -2449,6 +2449,7 @@ void suspend_console(void)
    if (!console_suspend_enabled)
    return;
    pr_info("Suspending console(s) (use no_console_suspend to debug)\n");
    + pr_flush(1000, true);
    console_lock();
    console_suspended = 1;
    up_console_sem();
    @@ -2461,6 +2462,7 @@ void resume_console(void)
    down_console_sem();
    console_suspended = 0;
    console_unlock();
    + pr_flush(1000, true);
    }

    /**
    @@ -2802,8 +2804,10 @@ void console_unblank(void)
    if (oops_in_progress) {
    if (down_trylock_console_sem() != 0)
    return;
    - } else
    + } else {
    + pr_flush(1000, true);
    console_lock();
    + }

    console_locked = 1;
    console_may_schedule = 0;
    @@ -2869,6 +2873,7 @@ struct tty_driver *console_device(int *index)
    */
    void console_stop(struct console *console)
    {
    + pr_flush(1000, true);
    console_lock();
    console->flags &= ~CON_ENABLED;
    console_unlock();
    @@ -2880,6 +2885,7 @@ void console_start(struct console *console)
    console_lock();
    console->flags |= CON_ENABLED;
    console_unlock();
    + pr_flush(1000, true);
    }
    EXPORT_SYMBOL(console_start);

    @@ -3249,6 +3255,71 @@ static int __init printk_late_init(void)
    late_initcall(printk_late_init);

    #if defined CONFIG_PRINTK
    +/**
    + * pr_flush() - Wait for printing threads to catch up.
    + *
    + * @timeout_ms: The maximum time (in ms) to wait.
    + * @reset_on_progress: Reset the timeout if forward progress is seen.
    + *
    + * A value of 0 for @timeout_ms means no waiting will occur. A value of -1
    + * represents infinite waiting.
    + *
    + * If @reset_on_progress is true, the timeout will be reset whenever any
    + * printer has been seen to make some forward progress.
    + *
    + * Context: Process context. May sleep while acquiring console lock.
    + * Return: true if all enabled printers are caught up.
    + */
    +bool pr_flush(int timeout_ms, bool reset_on_progress)
    +{
    + int remaining = timeout_ms;
    + struct console *con;
    + u64 last_diff = 0;
    + u64 printk_seq;
    + u64 diff;
    + u64 seq;
    +
    + might_sleep();
    +
    + seq = prb_next_seq(prb);
    +
    + for (;;) {
    + diff = 0;
    +
    + console_lock();
    + for_each_console(con) {
    + if (!console_is_usable(con))
    + continue;
    + printk_seq = con->seq;
    + if (printk_seq < seq)
    + diff += seq - printk_seq;
    + }
    + console_unlock();
    +
    + if (diff != last_diff && reset_on_progress)
    + remaining = timeout_ms;
    +
    + if (diff == 0 || remaining == 0)
    + break;
    +
    + if (remaining < 0) {
    + /* no timeout limit */
    + msleep(100);
    + } else if (remaining < 100) {
    + msleep(remaining);
    + remaining = 0;
    + } else {
    + msleep(100);
    + remaining -= 100;
    + }
    +
    + last_diff = diff;
    + }
    +
    + return (diff == 0);
    +}
    +EXPORT_SYMBOL(pr_flush);
    +
    /*
    * Delayed printk version, for scheduler-internal messages:
    */
    --
    2.30.2
    \
     
     \ /
      Last update: 2022-02-07 20:47    [W:3.836 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site