From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934933AbcCPHA5 (ORCPT ); Wed, 16 Mar 2016 03:00:57 -0400 Received: from LGEAMRELO11.lge.com ([156.147.23.51]:38205 "EHLO lgeamrelo11.lge.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932575AbcCPHAz (ORCPT ); Wed, 16 Mar 2016 03:00:55 -0400 X-Original-SENDERIP: 156.147.1.121 X-Original-MAILFROM: byungchul.park@lge.com X-Original-SENDERIP: 10.177.222.33 X-Original-MAILFROM: byungchul.park@lge.com Date: Wed, 16 Mar 2016 16:00:44 +0900 From: Byungchul Park To: Sergey Senozhatsky Cc: Jan Kara , Andrew Morton , Jan Kara , Petr Mladek , Tejun Heo , Tetsuo Handa , linux-kernel@vger.kernel.org, Sergey Senozhatsky Subject: Re: [RFC][PATCH v4 1/2] printk: Make printk() completely async Message-ID: <20160316070044.GK5220@X58A-UD3R> References: <1457964820-4642-1-git-send-email-sergey.senozhatsky@gmail.com> <1457964820-4642-2-git-send-email-sergey.senozhatsky@gmail.com> <20160315100323.GF17942@quack.suse.cz> <20160315140738.GA773@swordfish> <20160316053944.GJ5220@X58A-UD3R> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20160316053944.GJ5220@X58A-UD3R> User-Agent: Mutt/1.5.21 (2010-09-15) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Mar 16, 2016 at 02:39:44PM +0900, Byungchul Park wrote: > On Tue, Mar 15, 2016 at 11:07:38PM +0900, Sergey Senozhatsky wrote: > > > > something like this (*minimally tested so far*). > > > > -- move wake_up() and friends under the logbuf section; so we can detect > ^^^^^^^^^^^^^^ > section protected by logbuf_lock? I am afraid that I mis-interpreted the meaning of *under*. :-( You may mean *below*, but I interpreted it as *within*. I am sorry for that caused by my poor english. I absolutely agree with your mention, if it mean *below*. > > > printk() recursion from wake_up() > > Excuse me, but I fear that it can cause an unnecessary deadlock. > Furthermore it cannot be handled if it is caused by logbuf_lock. IMHO, > nothing including synced printk can help us in this case. Is there > something I missed? I'am sorry if I did, but could you let me know if so? > > I mean that it would be better to keep the wake_up and friend out of the > critical section by logbuf_lock. > > Thanks, > Byungchul > > > > > -- in recursion_bug branch switch to sync printk. we don't know why did we > > recurse, may be because of wake_up()->spin_lock(). doing > > kthread_stop()->wake_up_process() can be unsafe, I guess, just set > > `printk_sync' to true. > > > > > > Signed-off-by: Jan Kara > > Signed-off-by: Sergey Senozhatsky > > --- > > Documentation/kernel-parameters.txt | 10 ++ > > kernel/printk/printk.c | 202 +++++++++++++++++++++++++----------- > > 2 files changed, 154 insertions(+), 58 deletions(-) > > > > diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt > > index 1e58ae9..454999e 100644 > > --- a/Documentation/kernel-parameters.txt > > +++ b/Documentation/kernel-parameters.txt > > @@ -3114,6 +3114,16 @@ bytes respectively. Such letter suffixes can also be entirely omitted. > > printk.time= Show timing data prefixed to each printk message line > > Format: (1/Y/y=enable, 0/N/n=disable) > > > > + printk.synchronous= > > + By default kernel messages are printed to console > > + asynchronously (except during early boot or when oops > > + is happening). That avoids kernel stalling behind slow > > + serial console and thus avoids softlockups, interrupt > > + timeouts, or userspace timing out during heavy printing. > > + However for debugging problems, printing messages to > > + console immediately may be desirable. This option > > + enables such behavior. > > + > > processor.max_cstate= [HW,ACPI] > > Limit processor to maximum C-state > > max_cstate=9 overrides any DMI blacklist limit. > > diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c > > index d5fd844..38baed1 100644 > > --- a/kernel/printk/printk.c > > +++ b/kernel/printk/printk.c > > @@ -46,6 +46,7 @@ > > #include > > #include > > #include > > +#include > > > > #include > > #include > > @@ -284,6 +285,105 @@ static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); > > static char *log_buf = __log_buf; > > static u32 log_buf_len = __LOG_BUF_LEN; > > > > +/* > > + * When true, printing to console will happen synchronously unless someone else > > + * is already printing messages. > > + * > > + * The default value on UP systems is 'true'. > > + */ > > +static bool __read_mostly printk_sync = !IS_ENABLED(CONFIG_SMP); > > +module_param_named(synchronous, printk_sync, bool, S_IRUGO | S_IWUSR); > > +MODULE_PARM_DESC(synchronous, "make printing to console synchronous"); > > + > > +/* Printing kthread for async vprintk_emit() */ > > +static struct task_struct *printk_thread; > > +/* Wait for printing wakeups from async vprintk_emit() */ > > +static DECLARE_WAIT_QUEUE_HEAD(printing_wait); > > + > > +static int printing_func(void *data) > > +{ > > + while (1) { > > + DECLARE_WAITQUEUE(wait, current); > > + set_current_state(TASK_INTERRUPTIBLE); > > + add_wait_queue(&printing_wait, &wait); > > + > > + schedule(); > > + remove_wait_queue(&printing_wait, &wait); > > + > > + console_lock(); > > + console_unlock(); > > + } > > + > > + return 0; > > +} > > + > > +static int __init init_printk_thread(void) > > +{ > > + if (printk_sync) > > + return 0; > > + > > + printk_thread = kthread_run(printing_func, NULL, "printk"); > > + BUG_ON(IS_ERR(printk_thread)); > > + return 0; > > +} > > +late_initcall(init_printk_thread); > > + > > +/* > > + * Delayed printk version, for scheduler-internal messages: > > + */ > > +#define PRINTK_PENDING_WAKEUP (1<<0) > > +#define PRINTK_PENDING_OUTPUT (1<<1) > > + > > +static DEFINE_PER_CPU(int, printk_pending); > > + > > +static void wake_up_klogd_work_func(struct irq_work *irq_work) > > +{ > > + int pending = __this_cpu_xchg(printk_pending, 0); > > + > > + if (pending & PRINTK_PENDING_OUTPUT) { > > + if (!printk_sync && printk_thread) { > > + wake_up(&printing_wait); > > + } else { > > + /* > > + * If trylock fails, someone else is doing > > + * the printing > > + */ > > + if (console_trylock()) > > + console_unlock(); > > + } > > + } > > + > > + if (pending & PRINTK_PENDING_WAKEUP) > > + wake_up_interruptible(&log_wait); > > +} > > + > > +static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { > > + .func = wake_up_klogd_work_func, > > + .flags = IRQ_WORK_LAZY, > > +}; > > + > > +void wake_up_klogd(void) > > +{ > > + preempt_disable(); > > + if (waitqueue_active(&log_wait)) { > > + this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); > > + irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); > > + } > > + preempt_enable(); > > +} > > + > > +int printk_deferred(const char *fmt, ...) > > +{ > > + va_list args; > > + int r; > > + > > + va_start(args, fmt); > > + r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args); > > + va_end(args); > > + > > + return r; > > +} > > + > > /* Return log buffer address */ > > char *log_buf_addr_get(void) > > { > > @@ -1609,6 +1709,8 @@ asmlinkage int vprintk_emit(int facility, int level, > > const char *dict, size_t dictlen, > > const char *fmt, va_list args) > > { > > + /* cpu currently holding logbuf_lock in this function */ > > + static unsigned int logbuf_cpu = UINT_MAX; > > static bool recursion_bug; > > static char textbuf[LOG_LINE_MAX]; > > char *text = textbuf; > > @@ -1618,12 +1720,17 @@ asmlinkage int vprintk_emit(int facility, int level, > > int this_cpu; > > int printed_len = 0; > > bool in_sched = false; > > - /* cpu currently holding logbuf_lock in this function */ > > - static unsigned int logbuf_cpu = UINT_MAX; > > + bool in_panic = console_loglevel == CONSOLE_LOGLEVEL_MOTORMOUTH; > > + bool sync_print = printk_sync; > > > > if (level == LOGLEVEL_SCHED) { > > level = LOGLEVEL_DEFAULT; > > + /* > > + * Deferred sched messages must not be printed > > + * synchronously regardless the @printk_sync or @in_panic. > > + */ > > in_sched = true; > > + sync_print = false; > > } > > > > boot_delay_msec(level); > > @@ -1660,6 +1767,7 @@ asmlinkage int vprintk_emit(int facility, int level, > > static const char recursion_msg[] = > > "BUG: recent printk recursion!"; > > > > + printk_sync = true; > > recursion_bug = false; > > /* emit KERN_CRIT message */ > > printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0, > > @@ -1749,13 +1857,45 @@ asmlinkage int vprintk_emit(int facility, int level, > > dict, dictlen, text, text_len); > > } > > > > + /* > > + * By default we print message to console asynchronously so that kernel > > + * doesn't get stalled due to slow serial console. That can lead to > > + * softlockups, lost interrupts, or userspace timing out under heavy > > + * printing load. > > + * > > + * However we resort to synchronous printing of messages during early > > + * boot, when synchronous printing was explicitly requested by > > + * kernel parameter, or when console_verbose() was called to print > > + * everything during panic / oops. > > + */ > > + if (!sync_print) { > > + if (in_sched) { > > + /* > > + * @in_sched messages may come too early, when we don't > > + * yet have @printk_thread. We can't print deferred > > + * messages directly, because this may deadlock, route > > + * them via IRQ context. > > + */ > > + __this_cpu_or(printk_pending, > > + PRINTK_PENDING_OUTPUT); > > + irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); > > + } else if (printk_thread && !in_panic) { > > + /* > > + * This will wakeup the printing kthread and offload > > + * printing to a schedulable context. > > + */ > > + wake_up(&printing_wait); > > + } else { > > + sync_print = true; > > + } > > + } > > + > > logbuf_cpu = UINT_MAX; > > raw_spin_unlock(&logbuf_lock); > > lockdep_on(); > > local_irq_restore(flags); > > > > - /* If called from the scheduler, we can not call up(). */ > > - if (!in_sched) { > > + if (sync_print) { > > lockdep_off(); > > /* > > * Try to acquire and then immediately release the console > > @@ -2724,60 +2864,6 @@ late_initcall(printk_late_init); > > > > #if defined CONFIG_PRINTK > > /* > > - * Delayed printk version, for scheduler-internal messages: > > - */ > > -#define PRINTK_PENDING_WAKEUP 0x01 > > -#define PRINTK_PENDING_OUTPUT 0x02 > > - > > -static DEFINE_PER_CPU(int, printk_pending); > > - > > -static void wake_up_klogd_work_func(struct irq_work *irq_work) > > -{ > > - int pending = __this_cpu_xchg(printk_pending, 0); > > - > > - if (pending & PRINTK_PENDING_OUTPUT) { > > - /* If trylock fails, someone else is doing the printing */ > > - if (console_trylock()) > > - console_unlock(); > > - } > > - > > - if (pending & PRINTK_PENDING_WAKEUP) > > - wake_up_interruptible(&log_wait); > > -} > > - > > -static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { > > - .func = wake_up_klogd_work_func, > > - .flags = IRQ_WORK_LAZY, > > -}; > > - > > -void wake_up_klogd(void) > > -{ > > - preempt_disable(); > > - if (waitqueue_active(&log_wait)) { > > - this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); > > - irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); > > - } > > - preempt_enable(); > > -} > > - > > -int printk_deferred(const char *fmt, ...) > > -{ > > - va_list args; > > - int r; > > - > > - preempt_disable(); > > - va_start(args, fmt); > > - r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args); > > - va_end(args); > > - > > - __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT); > > - irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); > > - preempt_enable(); > > - > > - return r; > > -} > > - > > -/* > > * printk rate limiting, lifted from the networking subsystem. > > * > > * This enforces a rate limit: not more than 10 kernel messages > > -- > > 2.8.0.rc0