Commit 391d6276db9fbdedfbc30e1b56390414f0e55988
Exists in
master
and in
38 other branches
Merge branch 'core-printk-for-linus' of git://git.kernel.org/pub/scm/linux/kerne…
…l/git/tip/linux-2.6-tip * 'core-printk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: lockdep: Fix trace_[soft,hard]irqs_[on,off]() recursion printk: Fix console_sem vs logbuf_lock unlock race printk: Release console_sem after logbuf_lock
Showing 2 changed files Side-by-side Diff
kernel/lockdep.c
... | ... | @@ -2481,15 +2481,10 @@ |
2481 | 2481 | /* |
2482 | 2482 | * Hardirqs will be enabled: |
2483 | 2483 | */ |
2484 | -void trace_hardirqs_on_caller(unsigned long ip) | |
2484 | +static void __trace_hardirqs_on_caller(unsigned long ip) | |
2485 | 2485 | { |
2486 | 2486 | struct task_struct *curr = current; |
2487 | 2487 | |
2488 | - time_hardirqs_on(CALLER_ADDR0, ip); | |
2489 | - | |
2490 | - if (unlikely(!debug_locks || current->lockdep_recursion)) | |
2491 | - return; | |
2492 | - | |
2493 | 2488 | if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled))) |
2494 | 2489 | return; |
2495 | 2490 | |
... | ... | @@ -2505,8 +2500,6 @@ |
2505 | 2500 | /* we'll do an OFF -> ON transition: */ |
2506 | 2501 | curr->hardirqs_enabled = 1; |
2507 | 2502 | |
2508 | - if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) | |
2509 | - return; | |
2510 | 2503 | if (DEBUG_LOCKS_WARN_ON(current->hardirq_context)) |
2511 | 2504 | return; |
2512 | 2505 | /* |
... | ... | @@ -2528,6 +2521,21 @@ |
2528 | 2521 | curr->hardirq_enable_event = ++curr->irq_events; |
2529 | 2522 | debug_atomic_inc(hardirqs_on_events); |
2530 | 2523 | } |
2524 | + | |
2525 | +void trace_hardirqs_on_caller(unsigned long ip) | |
2526 | +{ | |
2527 | + time_hardirqs_on(CALLER_ADDR0, ip); | |
2528 | + | |
2529 | + if (unlikely(!debug_locks || current->lockdep_recursion)) | |
2530 | + return; | |
2531 | + | |
2532 | + if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) | |
2533 | + return; | |
2534 | + | |
2535 | + current->lockdep_recursion = 1; | |
2536 | + __trace_hardirqs_on_caller(ip); | |
2537 | + current->lockdep_recursion = 0; | |
2538 | +} | |
2531 | 2539 | EXPORT_SYMBOL(trace_hardirqs_on_caller); |
2532 | 2540 | |
2533 | 2541 | void trace_hardirqs_on(void) |
... | ... | @@ -2577,7 +2585,7 @@ |
2577 | 2585 | { |
2578 | 2586 | struct task_struct *curr = current; |
2579 | 2587 | |
2580 | - if (unlikely(!debug_locks)) | |
2588 | + if (unlikely(!debug_locks || current->lockdep_recursion)) | |
2581 | 2589 | return; |
2582 | 2590 | |
2583 | 2591 | if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) |
... | ... | @@ -2588,6 +2596,7 @@ |
2588 | 2596 | return; |
2589 | 2597 | } |
2590 | 2598 | |
2599 | + current->lockdep_recursion = 1; | |
2591 | 2600 | /* |
2592 | 2601 | * We'll do an OFF -> ON transition: |
2593 | 2602 | */ |
... | ... | @@ -2602,6 +2611,7 @@ |
2602 | 2611 | */ |
2603 | 2612 | if (curr->hardirqs_enabled) |
2604 | 2613 | mark_held_locks(curr, SOFTIRQ); |
2614 | + current->lockdep_recursion = 0; | |
2605 | 2615 | } |
2606 | 2616 | |
2607 | 2617 | /* |
... | ... | @@ -2611,7 +2621,7 @@ |
2611 | 2621 | { |
2612 | 2622 | struct task_struct *curr = current; |
2613 | 2623 | |
2614 | - if (unlikely(!debug_locks)) | |
2624 | + if (unlikely(!debug_locks || current->lockdep_recursion)) | |
2615 | 2625 | return; |
2616 | 2626 | |
2617 | 2627 | if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) |
kernel/printk.c
... | ... | @@ -782,7 +782,7 @@ |
782 | 782 | static int console_trylock_for_printk(unsigned int cpu) |
783 | 783 | __releases(&logbuf_lock) |
784 | 784 | { |
785 | - int retval = 0; | |
785 | + int retval = 0, wake = 0; | |
786 | 786 | |
787 | 787 | if (console_trylock()) { |
788 | 788 | retval = 1; |
789 | 789 | |
... | ... | @@ -795,12 +795,14 @@ |
795 | 795 | */ |
796 | 796 | if (!can_use_console(cpu)) { |
797 | 797 | console_locked = 0; |
798 | - up(&console_sem); | |
798 | + wake = 1; | |
799 | 799 | retval = 0; |
800 | 800 | } |
801 | 801 | } |
802 | 802 | printk_cpu = UINT_MAX; |
803 | 803 | spin_unlock(&logbuf_lock); |
804 | + if (wake) | |
805 | + up(&console_sem); | |
804 | 806 | return retval; |
805 | 807 | } |
806 | 808 | static const char recursion_bug_msg [] = |
... | ... | @@ -1242,7 +1244,7 @@ |
1242 | 1244 | { |
1243 | 1245 | unsigned long flags; |
1244 | 1246 | unsigned _con_start, _log_end; |
1245 | - unsigned wake_klogd = 0; | |
1247 | + unsigned wake_klogd = 0, retry = 0; | |
1246 | 1248 | |
1247 | 1249 | if (console_suspended) { |
1248 | 1250 | up(&console_sem); |
... | ... | @@ -1251,6 +1253,7 @@ |
1251 | 1253 | |
1252 | 1254 | console_may_schedule = 0; |
1253 | 1255 | |
1256 | +again: | |
1254 | 1257 | for ( ; ; ) { |
1255 | 1258 | spin_lock_irqsave(&logbuf_lock, flags); |
1256 | 1259 | wake_klogd |= log_start - log_end; |
1257 | 1260 | |
1258 | 1261 | |
... | ... | @@ -1271,8 +1274,23 @@ |
1271 | 1274 | if (unlikely(exclusive_console)) |
1272 | 1275 | exclusive_console = NULL; |
1273 | 1276 | |
1277 | + spin_unlock(&logbuf_lock); | |
1278 | + | |
1274 | 1279 | up(&console_sem); |
1280 | + | |
1281 | + /* | |
1282 | + * Someone could have filled up the buffer again, so re-check if there's | |
1283 | + * something to flush. In case we cannot trylock the console_sem again, | |
1284 | + * there's a new owner and the console_unlock() from them will do the | |
1285 | + * flush, no worries. | |
1286 | + */ | |
1287 | + spin_lock(&logbuf_lock); | |
1288 | + if (con_start != log_end) | |
1289 | + retry = 1; | |
1275 | 1290 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1291 | + if (retry && console_trylock()) | |
1292 | + goto again; | |
1293 | + | |
1276 | 1294 | if (wake_klogd) |
1277 | 1295 | wake_up_klogd(); |
1278 | 1296 | } |