Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15100df8 authored by Paul E. McKenney's avatar Paul E. McKenney
Browse files

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: default avatarPaul 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: default avatarSedat Dilek <sedat.dilek@gmail.com>
Reviewed-by: default avatarJosh Triplett <josh@joshtriplett.org>
parent d1d74d14
Loading
Loading
Loading
Loading
+0 −100
Original line number Diff line number Diff line
@@ -211,43 +211,6 @@ static inline void debug_rcu_head_free(struct rcu_head *head)
	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:
 * - 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_activate(head, &rcuhead_debug_descr);
		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:
		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;
	default:
		return 0;
	}
}

@@ -369,9 +271,7 @@ EXPORT_SYMBOL_GPL(destroy_rcu_head_on_stack);

struct debug_obj_descr rcuhead_debug_descr = {
	.name = "rcu_head",
	.fixup_init = rcuhead_fixup_init,
	.fixup_activate = rcuhead_fixup_activate,
	.fixup_free = rcuhead_fixup_free,
};
EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */