diff -urN oldtree/include/linux/rcuclassic.h newtree/include/linux/rcuclassic.h --- oldtree/include/linux/rcuclassic.h 2006-09-26 19:08:59.000000000 -0400 +++ newtree/include/linux/rcuclassic.h 2006-09-26 19:09:46.000000000 -0400 @@ -115,25 +115,37 @@ extern int rcu_pending(int cpu); extern int rcu_needs_cpu(int cpu); +#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP +extern void rcu_add_read_count(void); +extern void rcu_sub_read_count(void); +#else +static inline void rcu_add_read_count(void) {} +static inline void rcu_sub_read_count(void) {} +#endif + #define __rcu_read_lock() \ do { \ preempt_disable(); \ + rcu_add_read_count(); \ __acquire(RCU); \ } while(0) #define __rcu_read_unlock() \ do { \ __release(RCU); \ + rcu_sub_read_count(); \ preempt_enable(); \ } while(0) #define __rcu_read_lock_bh() \ do { \ local_bh_disable(); \ + rcu_add_read_count(); \ __acquire(RCU_BH); \ } while(0) #define __rcu_read_unlock_bh() \ do { \ __release(RCU_BH); \ + rcu_sub_read_count(); \ local_bh_enable(); \ } while(0) diff -urN oldtree/include/linux/rcupdate.h newtree/include/linux/rcupdate.h --- oldtree/include/linux/rcupdate.h 2006-09-26 19:08:59.000000000 -0400 +++ newtree/include/linux/rcupdate.h 2006-09-26 19:09:46.000000000 -0400 @@ -64,6 +64,12 @@ (ptr)->next = NULL; (ptr)->func = NULL; \ } while (0) +#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP +extern int rcu_read_in_atomic(void); +#else +static inline int rcu_read_in_atomic(void) { return 0;} +#endif + /** * rcu_read_lock - mark the beginning of an RCU read-side critical section. * diff -urN oldtree/kernel/rcuclassic.c newtree/kernel/rcuclassic.c --- oldtree/kernel/rcuclassic.c 2006-09-26 19:08:21.000000000 -0400 +++ newtree/kernel/rcuclassic.c 2006-09-26 19:09:46.000000000 -0400 @@ -545,6 +545,39 @@ register_cpu_notifier(&rcu_nb); } +#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP +static DEFINE_PER_CPU(int, rcu_read_count); +int rcu_read_in_atomic(void) +{ + int val; + int cpu = get_cpu(); + val = per_cpu(rcu_read_count, cpu); + put_cpu(); + return val; +} + +void rcu_add_read_count(void) +{ + int cpu, flags; + local_irq_save(flags); + cpu = smp_processor_id(); + per_cpu(rcu_read_count, cpu)++; + local_irq_restore(flags); +} + +void rcu_sub_read_count(void) +{ + int cpu, flags; + local_irq_save(flags); + cpu = smp_processor_id(); + per_cpu(rcu_read_count, cpu)--; + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(rcu_read_in_atomic); +EXPORT_SYMBOL_GPL(rcu_add_read_count); +EXPORT_SYMBOL_GPL(rcu_sub_read_count); +#endif + module_param(blimit, int, 0); module_param(qhimark, int, 0); module_param(qlowmark, int, 0); diff -urN oldtree/kernel/rcupreempt.c newtree/kernel/rcupreempt.c --- oldtree/kernel/rcupreempt.c 2006-09-26 19:09:35.000000000 -0400 +++ newtree/kernel/rcupreempt.c 2006-09-26 19:09:46.000000000 -0400 @@ -424,6 +424,13 @@ #endif /* #ifdef CONFIG_RCU_TRACE */ +#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP +int rcu_read_in_atomic(void) +{ + return current->rcu_read_lock_nesting; +} +#endif + EXPORT_SYMBOL_GPL(call_rcu); EXPORT_SYMBOL_GPL(rcu_batches_completed); EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); diff -urN oldtree/kernel/sched_ingosched.c newtree/kernel/sched_ingosched.c --- oldtree/kernel/sched_ingosched.c 2006-09-26 14:34:25.000000000 -0400 +++ newtree/kernel/sched_ingosched.c 2006-09-26 19:10:17.000000000 -0400 @@ -6968,7 +6968,7 @@ #ifdef in_atomic static unsigned long prev_jiffy; /* ratelimiting */ - if ((in_atomic() || irqs_disabled()) && + if ((in_atomic() || irqs_disabled() || rcu_read_in_atomic()) && system_state == SYSTEM_RUNNING && !oops_in_progress) { if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) return; diff -urN oldtree/kernel/sched_staircase.c newtree/kernel/sched_staircase.c --- oldtree/kernel/sched_staircase.c 2006-09-26 16:09:47.000000000 -0400 +++ newtree/kernel/sched_staircase.c 2006-09-26 19:10:29.000000000 -0400 @@ -6891,7 +6891,7 @@ #ifdef in_atomic static unsigned long prev_jiffy; /* ratelimiting */ - if ((in_atomic() || irqs_disabled()) && + if ((in_atomic() || irqs_disabled() || rcu_read_in_atomic()) && system_state == SYSTEM_RUNNING && !oops_in_progress) { if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) return;