rcu: Introduce raw SRCU read-side primitives
The RCU implementations, including SRCU, are designed to be used in a lock-like fashion, so that the read-side lock and unlock primitives must execute in the same context for any given read-side critical section. This constraint is enforced by lockdep-RCU. However, there is a need to enter an SRCU read-side critical section within the context of an exception and then exit in the context of the task that encountered the exception. The cost of this capability is that the read-side operations incur the overhead of disabling interrupts. Note that although the current implementation allows a given read-side critical section to be entered by one task and then exited by another, all known possible implementations that allow this have scalability problems. Therefore, a given read-side critical section must be exited by the same task that entered it, though perhaps from an interrupt or exception handler running within that task's context. But if you are thinking in terms of interrupt handlers, make sure that you have considered the possibility of threaded interrupt handlers. Credit goes to Peter Zijlstra for suggesting use of the existing _raw suffix to indicate disabling lockdep over the earlier "bulkref" names. Requested-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Tested-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
This commit is contained in:
Родитель
a7b152d534
Коммит
0c53dd8b31
|
@ -181,4 +181,47 @@ static inline void srcu_read_unlock(struct srcu_struct *sp, int idx)
|
|||
__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
|
||||
|
|
Загрузка…
Ссылка в новой задаче