aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/printk
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2016-01-15 19:58:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-16 14:17:25 -0500
commit8d91f8b15361dfb438ab6eb3b319e2ded43458ff (patch)
tree2462bccec78ae730a5e0801dbb636cb0710a6c88 /kernel/printk
parent81cc26f2bd11ba4421a17a2d5cebe4bba206c239 (diff)
printk: do cond_resched() between lines while outputting to consoles
@console_may_schedule tracks whether console_sem was acquired through lock or trylock. If the former, we're inside a sleepable context and console_conditional_schedule() performs cond_resched(). This allows console drivers which use console_lock for synchronization to yield while performing time-consuming operations such as scrolling. However, the actual console outputting is performed while holding irq-safe logbuf_lock, so console_unlock() clears @console_may_schedule before starting outputting lines. Also, only a few drivers call console_conditional_schedule() to begin with. This means that when a lot of lines need to be output by console_unlock(), for example on a console registration, the task doing console_unlock() may not yield for a long time on a non-preemptible kernel. If this happens with a slow console devices, for example a serial console, the outputting task may occupy the cpu for a very long time. Long enough to trigger softlockup and/or RCU stall warnings, which in turn pile more messages, sometimes enough to trigger the next cycle of warnings incapacitating the system. Fix it by making console_unlock() insert cond_resched() between lines if @console_may_schedule. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Calvin Owens <calvinowens@fb.com> Acked-by: Jan Kara <jack@suse.com> Cc: Dave Jones <davej@codemonkey.org.uk> Cc: Kyle McMartin <kyle@kernel.org> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/printk')
-rw-r--r--kernel/printk/printk.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 0c9f02506169..08934a395c1a 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2234,13 +2234,24 @@ void console_unlock(void)
2234 static u64 seen_seq; 2234 static u64 seen_seq;
2235 unsigned long flags; 2235 unsigned long flags;
2236 bool wake_klogd = false; 2236 bool wake_klogd = false;
2237 bool retry; 2237 bool do_cond_resched, retry;
2238 2238
2239 if (console_suspended) { 2239 if (console_suspended) {
2240 up_console_sem(); 2240 up_console_sem();
2241 return; 2241 return;
2242 } 2242 }
2243 2243
2244 /*
2245 * Console drivers are called under logbuf_lock, so
2246 * @console_may_schedule should be cleared before; however, we may
2247 * end up dumping a lot of lines, for example, if called from
2248 * console registration path, and should invoke cond_resched()
2249 * between lines if allowable. Not doing so can cause a very long
2250 * scheduling stall on a slow console leading to RCU stall and
2251 * softlockup warnings which exacerbate the issue with more
2252 * messages practically incapacitating the system.
2253 */
2254 do_cond_resched = console_may_schedule;
2244 console_may_schedule = 0; 2255 console_may_schedule = 0;
2245 2256
2246 /* flush buffered message fragment immediately to console */ 2257 /* flush buffered message fragment immediately to console */
@@ -2312,6 +2323,9 @@ skip:
2312 call_console_drivers(level, ext_text, ext_len, text, len); 2323 call_console_drivers(level, ext_text, ext_len, text, len);
2313 start_critical_timings(); 2324 start_critical_timings();
2314 local_irq_restore(flags); 2325 local_irq_restore(flags);
2326
2327 if (do_cond_resched)
2328 cond_resched();
2315 } 2329 }
2316 console_locked = 0; 2330 console_locked = 0;
2317 2331
@@ -2379,6 +2393,25 @@ void console_unblank(void)
2379 console_unlock(); 2393 console_unlock();
2380} 2394}
2381 2395
2396/**
2397 * console_flush_on_panic - flush console content on panic
2398 *
2399 * Immediately output all pending messages no matter what.
2400 */
2401void console_flush_on_panic(void)
2402{
2403 /*
2404 * If someone else is holding the console lock, trylock will fail
2405 * and may_schedule may be set. Ignore and proceed to unlock so
2406 * that messages are flushed out. As this can be called from any
2407 * context and we don't want to get preempted while flushing,
2408 * ensure may_schedule is cleared.
2409 */
2410 console_trylock();
2411 console_may_schedule = 0;
2412 console_unlock();
2413}
2414
2382/* 2415/*
2383 * Return the console tty driver structure and its associated index 2416 * Return the console tty driver structure and its associated index
2384 */ 2417 */