rcu: Simplify debug-objects fixups
The current debug-objects fixups are complex and heavyweight, and the fixups are not complete: Even with the fixups, RCU's callback lists can still be corrupted. This commit therefore strips the fixups down to their minimal form, eliminating two of the three. It would be even better if (for example) call_rcu() simply leaked any problematic callbacks, but for that to happen, the debug-objects system would need to inform its caller of suspicious situations. This is the subject of a later commit in this series. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Sedat Dilek <sedat.dilek@gmail.com> Cc: Davidlohr Bueso <davidlohr.bueso@hp.com> Cc: Rik van Riel <riel@surriel.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Tested-by: Sedat Dilek <sedat.dilek@gmail.com> Reviewed-by: Josh Triplett <josh@joshtriplett.org>
This commit is contained in:
Родитель
d1d74d14e9
Коммит
15100df81f
|
@ -211,43 +211,6 @@ static inline void debug_rcu_head_free(struct rcu_head *head)
|
||||||
debug_object_free(head, &rcuhead_debug_descr);
|
debug_object_free(head, &rcuhead_debug_descr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* fixup_init is called when:
|
|
||||||
* - an active object is initialized
|
|
||||||
*/
|
|
||||||
static int rcuhead_fixup_init(void *addr, enum debug_obj_state state)
|
|
||||||
{
|
|
||||||
struct rcu_head *head = addr;
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case ODEBUG_STATE_ACTIVE:
|
|
||||||
/*
|
|
||||||
* Ensure that queued callbacks are all executed.
|
|
||||||
* If we detect that we are nested in a RCU read-side critical
|
|
||||||
* section, we should simply fail, otherwise we would deadlock.
|
|
||||||
* In !PREEMPT configurations, there is no way to tell if we are
|
|
||||||
* in a RCU read-side critical section or not, so we never
|
|
||||||
* attempt any fixup and just print a warning.
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_PREEMPT
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
|
|
||||||
irqs_disabled()) {
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
rcu_barrier();
|
|
||||||
rcu_barrier_sched();
|
|
||||||
rcu_barrier_bh();
|
|
||||||
debug_object_init(head, &rcuhead_debug_descr);
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fixup_activate is called when:
|
* fixup_activate is called when:
|
||||||
* - an active object is activated
|
* - an active object is activated
|
||||||
|
@ -268,69 +231,8 @@ static int rcuhead_fixup_activate(void *addr, enum debug_obj_state state)
|
||||||
debug_object_init(head, &rcuhead_debug_descr);
|
debug_object_init(head, &rcuhead_debug_descr);
|
||||||
debug_object_activate(head, &rcuhead_debug_descr);
|
debug_object_activate(head, &rcuhead_debug_descr);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case ODEBUG_STATE_ACTIVE:
|
|
||||||
/*
|
|
||||||
* Ensure that queued callbacks are all executed.
|
|
||||||
* If we detect that we are nested in a RCU read-side critical
|
|
||||||
* section, we should simply fail, otherwise we would deadlock.
|
|
||||||
* In !PREEMPT configurations, there is no way to tell if we are
|
|
||||||
* in a RCU read-side critical section or not, so we never
|
|
||||||
* attempt any fixup and just print a warning.
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_PREEMPT
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
|
|
||||||
irqs_disabled()) {
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
rcu_barrier();
|
|
||||||
rcu_barrier_sched();
|
|
||||||
rcu_barrier_bh();
|
|
||||||
debug_object_activate(head, &rcuhead_debug_descr);
|
|
||||||
return 1;
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* fixup_free is called when:
|
|
||||||
* - an active object is freed
|
|
||||||
*/
|
|
||||||
static int rcuhead_fixup_free(void *addr, enum debug_obj_state state)
|
|
||||||
{
|
|
||||||
struct rcu_head *head = addr;
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case ODEBUG_STATE_ACTIVE:
|
|
||||||
/*
|
|
||||||
* Ensure that queued callbacks are all executed.
|
|
||||||
* If we detect that we are nested in a RCU read-side critical
|
|
||||||
* section, we should simply fail, otherwise we would deadlock.
|
|
||||||
* In !PREEMPT configurations, there is no way to tell if we are
|
|
||||||
* in a RCU read-side critical section or not, so we never
|
|
||||||
* attempt any fixup and just print a warning.
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_PREEMPT
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
|
|
||||||
irqs_disabled()) {
|
|
||||||
WARN_ON_ONCE(1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
rcu_barrier();
|
|
||||||
rcu_barrier_sched();
|
|
||||||
rcu_barrier_bh();
|
|
||||||
debug_object_free(head, &rcuhead_debug_descr);
|
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,9 +271,7 @@ EXPORT_SYMBOL_GPL(destroy_rcu_head_on_stack);
|
||||||
|
|
||||||
struct debug_obj_descr rcuhead_debug_descr = {
|
struct debug_obj_descr rcuhead_debug_descr = {
|
||||||
.name = "rcu_head",
|
.name = "rcu_head",
|
||||||
.fixup_init = rcuhead_fixup_init,
|
|
||||||
.fixup_activate = rcuhead_fixup_activate,
|
.fixup_activate = rcuhead_fixup_activate,
|
||||||
.fixup_free = rcuhead_fixup_free,
|
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
|
EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
|
||||||
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
|
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче