diff options
Diffstat (limited to 'include/linux/srcu.h')
| -rw-r--r-- | include/linux/srcu.h | 87 | 
1 files changed, 74 insertions, 13 deletions
diff --git a/include/linux/srcu.h b/include/linux/srcu.h index 58971e891f4..e1b005918bb 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -28,6 +28,7 @@  #define _LINUX_SRCU_H  #include <linux/mutex.h> +#include <linux/rcupdate.h>  struct srcu_struct_array {  	int c[2]; @@ -60,18 +61,10 @@ int __init_srcu_struct(struct srcu_struct *sp, const char *name,  	__init_srcu_struct((sp), #sp, &__srcu_key); \  }) -# define srcu_read_acquire(sp) \ -		lock_acquire(&(sp)->dep_map, 0, 0, 2, 1, NULL, _THIS_IP_) -# define srcu_read_release(sp) \ -		lock_release(&(sp)->dep_map, 1, _THIS_IP_) -  #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */  int init_srcu_struct(struct srcu_struct *sp); -# define srcu_read_acquire(sp)  do { } while (0) -# define srcu_read_release(sp)  do { } while (0) -  #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */  void cleanup_srcu_struct(struct srcu_struct *sp); @@ -90,12 +83,32 @@ long srcu_batches_completed(struct srcu_struct *sp);   * read-side critical section.  In absence of CONFIG_DEBUG_LOCK_ALLOC,   * this assumes we are in an SRCU read-side critical section unless it can   * prove otherwise. + * + * Checks 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 srcu_read_lock_held() returns false even if + * the CPU did an srcu_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.   */  static inline int srcu_read_lock_held(struct srcu_struct *sp)  { -	if (debug_locks) -		return lock_is_held(&sp->dep_map); -	return 1; +	if (rcu_is_cpu_idle()) +		return 0; + +	if (!debug_lockdep_rcu_enabled()) +		return 1; + +	return lock_is_held(&sp->dep_map);  }  #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ @@ -145,12 +158,17 @@ static inline int srcu_read_lock_held(struct srcu_struct *sp)   * one way to indirectly wait on an SRCU grace period is to acquire   * a mutex that is held elsewhere while calling synchronize_srcu() or   * synchronize_srcu_expedited(). + * + * Note that srcu_read_lock() and the matching srcu_read_unlock() must + * occur in the same context, for example, it is illegal to invoke + * srcu_read_unlock() in an irq handler if the matching srcu_read_lock() + * was invoked in process context.   */  static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp)  {  	int retval = __srcu_read_lock(sp); -	srcu_read_acquire(sp); +	rcu_lock_acquire(&(sp)->dep_map);  	return retval;  } @@ -164,8 +182,51 @@ static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp)  static inline void srcu_read_unlock(struct srcu_struct *sp, int idx)  	__releases(sp)  { -	srcu_read_release(sp); +	rcu_lock_release(&(sp)->dep_map); +	__srcu_read_unlock(sp, idx); +} + +/** + * srcu_read_lock_raw - register a new reader for an SRCU-protected structure. + * @sp: srcu_struct in which to register the new reader. + * + * Enter an SRCU read-side critical section.  Similar to srcu_read_lock(), + * but avoids the RCU-lockdep checking.  This means that it is legal to + * use srcu_read_lock_raw() in one context, for example, in an exception + * handler, and then have the matching srcu_read_unlock_raw() in another + * context, for example in the task that took the exception. + * + * However, the entire SRCU read-side critical section must reside within a + * single task.  For example, beware of using srcu_read_lock_raw() in + * a device interrupt handler and srcu_read_unlock() in the interrupted + * task:  This will not work if interrupts are threaded. + */ +static inline int srcu_read_lock_raw(struct srcu_struct *sp) +{ +	unsigned long flags; +	int ret; + +	local_irq_save(flags); +	ret =  __srcu_read_lock(sp); +	local_irq_restore(flags); +	return ret; +} + +/** + * srcu_read_unlock_raw - unregister reader from an SRCU-protected structure. + * @sp: srcu_struct in which to unregister the old reader. + * @idx: return value from corresponding srcu_read_lock_raw(). + * + * Exit an SRCU read-side critical section without lockdep-RCU checking. + * See srcu_read_lock_raw() for more details. + */ +static inline void srcu_read_unlock_raw(struct srcu_struct *sp, int idx) +{ +	unsigned long flags; + +	local_irq_save(flags);  	__srcu_read_unlock(sp, idx); +	local_irq_restore(flags);  }  #endif  |