rcu: Deinline rcu_read_lock_sched_held() if DEBUG_LOCK_ALLOC
DEBUG_LOCK_ALLOC=y is not a production setting, but it is not very unusual either. Many developers routinely use kernels built with it enabled. Apart from being selected by hand, it is also auto-selected by PROVE_LOCKING "Lock debugging: prove locking correctness" and LOCK_STAT "Lock usage statistics" config options. LOCK STAT is necessary for "perf lock" to work. I wouldn't spend too much time optimizing it, but this particular function has a very large cost in code size: when it is deinlined, code size decreases by 830,000 bytes: text data bss dec hex filename 85674192 22294776 20627456 128596424 7aa39c8 vmlinux.before 84837612 22294424 20627456 127759492 79d7484 vmlinux (with this config: http://busybox.net/~vda/kernel_config) Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com> CC: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> CC: Josh Triplett <josh@joshtriplett.org> CC: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> CC: Lai Jiangshan <laijs@cn.fujitsu.com> CC: Tejun Heo <tj@kernel.org> CC: Oleg Nesterov <oleg@redhat.com> CC: linux-kernel@vger.kernel.org Reviewed-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
This commit is contained in:
parent
d1ec4c34c7
commit
d5671f6bf2
|
@ -469,46 +469,10 @@ int rcu_read_lock_bh_held(void);
|
||||||
* If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an
|
* If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an
|
||||||
* RCU-sched read-side critical section. In absence of
|
* RCU-sched read-side critical section. In absence of
|
||||||
* CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side
|
* CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side
|
||||||
* critical section unless it can prove otherwise. Note that disabling
|
* critical section unless it can prove otherwise.
|
||||||
* of preemption (including disabling irqs) counts as an RCU-sched
|
|
||||||
* read-side critical section. This is useful for debug checks in functions
|
|
||||||
* that required that they be called within an RCU-sched read-side
|
|
||||||
* critical section.
|
|
||||||
*
|
|
||||||
* Check debug_lockdep_rcu_enabled() to prevent false positives during boot
|
|
||||||
* and while lockdep is disabled.
|
|
||||||
*
|
|
||||||
* Note that if the CPU is in the idle loop from an RCU point of
|
|
||||||
* view (ie: that we are in the section between rcu_idle_enter() and
|
|
||||||
* rcu_idle_exit()) then rcu_read_lock_held() returns false even if the CPU
|
|
||||||
* did an rcu_read_lock(). The reason for this is that RCU ignores CPUs
|
|
||||||
* that are in such a section, considering these as in extended quiescent
|
|
||||||
* state, so such a CPU is effectively never in an RCU read-side critical
|
|
||||||
* section regardless of what RCU primitives it invokes. This state of
|
|
||||||
* affairs is required --- we need to keep an RCU-free window in idle
|
|
||||||
* where the CPU may possibly enter into low power mode. This way we can
|
|
||||||
* notice an extended quiescent state to other CPUs that started a grace
|
|
||||||
* period. Otherwise we would delay any grace period as long as we run in
|
|
||||||
* the idle task.
|
|
||||||
*
|
|
||||||
* Similarly, we avoid claiming an SRCU read lock held if the current
|
|
||||||
* CPU is offline.
|
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_PREEMPT_COUNT
|
#ifdef CONFIG_PREEMPT_COUNT
|
||||||
static inline int rcu_read_lock_sched_held(void)
|
int rcu_read_lock_sched_held(void);
|
||||||
{
|
|
||||||
int lockdep_opinion = 0;
|
|
||||||
|
|
||||||
if (!debug_lockdep_rcu_enabled())
|
|
||||||
return 1;
|
|
||||||
if (!rcu_is_watching())
|
|
||||||
return 0;
|
|
||||||
if (!rcu_lockdep_current_cpu_online())
|
|
||||||
return 0;
|
|
||||||
if (debug_locks)
|
|
||||||
lockdep_opinion = lock_is_held(&rcu_sched_lock_map);
|
|
||||||
return lockdep_opinion || preempt_count() != 0 || irqs_disabled();
|
|
||||||
}
|
|
||||||
#else /* #ifdef CONFIG_PREEMPT_COUNT */
|
#else /* #ifdef CONFIG_PREEMPT_COUNT */
|
||||||
static inline int rcu_read_lock_sched_held(void)
|
static inline int rcu_read_lock_sched_held(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,6 +62,55 @@ MODULE_ALIAS("rcupdate");
|
||||||
|
|
||||||
module_param(rcu_expedited, int, 0);
|
module_param(rcu_expedited, int, 0);
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEBUG_LOCK_ALLOC) && defined(CONFIG_PREEMPT_COUNT)
|
||||||
|
/**
|
||||||
|
* rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section?
|
||||||
|
*
|
||||||
|
* If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an
|
||||||
|
* RCU-sched read-side critical section. In absence of
|
||||||
|
* CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side
|
||||||
|
* critical section unless it can prove otherwise. Note that disabling
|
||||||
|
* of preemption (including disabling irqs) counts as an RCU-sched
|
||||||
|
* read-side critical section. This is useful for debug checks in functions
|
||||||
|
* that required that they be called within an RCU-sched read-side
|
||||||
|
* critical section.
|
||||||
|
*
|
||||||
|
* Check debug_lockdep_rcu_enabled() to prevent false positives during boot
|
||||||
|
* and while lockdep is disabled.
|
||||||
|
*
|
||||||
|
* Note that if the CPU is in the idle loop from an RCU point of
|
||||||
|
* view (ie: that we are in the section between rcu_idle_enter() and
|
||||||
|
* rcu_idle_exit()) then rcu_read_lock_held() returns false even if the CPU
|
||||||
|
* did an rcu_read_lock(). The reason for this is that RCU ignores CPUs
|
||||||
|
* that are in such a section, considering these as in extended quiescent
|
||||||
|
* state, so such a CPU is effectively never in an RCU read-side critical
|
||||||
|
* section regardless of what RCU primitives it invokes. This state of
|
||||||
|
* affairs is required --- we need to keep an RCU-free window in idle
|
||||||
|
* where the CPU may possibly enter into low power mode. This way we can
|
||||||
|
* notice an extended quiescent state to other CPUs that started a grace
|
||||||
|
* period. Otherwise we would delay any grace period as long as we run in
|
||||||
|
* the idle task.
|
||||||
|
*
|
||||||
|
* Similarly, we avoid claiming an SRCU read lock held if the current
|
||||||
|
* CPU is offline.
|
||||||
|
*/
|
||||||
|
int rcu_read_lock_sched_held(void)
|
||||||
|
{
|
||||||
|
int lockdep_opinion = 0;
|
||||||
|
|
||||||
|
if (!debug_lockdep_rcu_enabled())
|
||||||
|
return 1;
|
||||||
|
if (!rcu_is_watching())
|
||||||
|
return 0;
|
||||||
|
if (!rcu_lockdep_current_cpu_online())
|
||||||
|
return 0;
|
||||||
|
if (debug_locks)
|
||||||
|
lockdep_opinion = lock_is_held(&rcu_sched_lock_map);
|
||||||
|
return lockdep_opinion || preempt_count() != 0 || irqs_disabled();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rcu_read_lock_sched_held);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_TINY_RCU
|
#ifndef CONFIG_TINY_RCU
|
||||||
|
|
||||||
static atomic_t rcu_expedited_nesting =
|
static atomic_t rcu_expedited_nesting =
|
||||||
|
|
Loading…
Reference in New Issue