Commit 391d6276db9fbdedfbc30e1b56390414f0e55988

Authored by Linus Torvalds

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

... ... @@ -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()))
... ... @@ -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 }