Skip to content

Commit 0b1182b

Browse files
committed
rcu: Add srcu_down_read() and srcu_up_read()
A pair of matching srcu_read_lock() and srcu_read_unlock() invocations must take place within the same context, for example, within the same task. Otherwise, lockdep complains, as is the right thing to do for most use cases. However, there are use cases involving asynchronous I/O where the SRCU reader needs to begin on one task and end on another. This commit therefore supplies the semaphore-like srcu_down_read() and srcu_up_read(), which act like srcu_read_lock() and srcu_read_unlock(), but permitting srcu_up_read() to be invoked in a different context than was the matching srcu_down_read(). Neither srcu_down_read() nor srcu_up_read() may be invoked from an NMI handler. Reported-by: Jan Kara <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]> Tested-by: Amir Goldstein <[email protected]>
1 parent 50be0c0 commit 0b1182b

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

include/linux/srcu.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,34 @@ srcu_read_lock_notrace(struct srcu_struct *ssp) __acquires(ssp)
214214
return retval;
215215
}
216216

217+
/**
218+
* srcu_down_read - register a new reader for an SRCU-protected structure.
219+
* @ssp: srcu_struct in which to register the new reader.
220+
*
221+
* Enter a semaphore-like SRCU read-side critical section. Note that
222+
* SRCU read-side critical sections may be nested. However, it is
223+
* illegal to call anything that waits on an SRCU grace period for the
224+
* same srcu_struct, whether directly or indirectly. Please note that
225+
* one way to indirectly wait on an SRCU grace period is to acquire
226+
* a mutex that is held elsewhere while calling synchronize_srcu() or
227+
* synchronize_srcu_expedited(). But if you want lockdep to help you
228+
* keep this stuff straight, you should instead use srcu_read_lock().
229+
*
230+
* The semaphore-like nature of srcu_down_read() means that the matching
231+
* srcu_up_read() can be invoked from some other context, for example,
232+
* from some other task or from an irq handler. However, neither
233+
* srcu_down_read() nor srcu_up_read() may be invoked from an NMI handler.
234+
*
235+
* Calls to srcu_down_read() may be nested, similar to the manner in
236+
* which calls to down_read() may be nested.
237+
*/
238+
static inline int srcu_down_read(struct srcu_struct *ssp) __acquires(ssp)
239+
{
240+
WARN_ON_ONCE(in_nmi());
241+
srcu_check_nmi_safety(ssp, false);
242+
return __srcu_read_lock(ssp);
243+
}
244+
217245
/**
218246
* srcu_read_unlock - unregister a old reader from an SRCU-protected structure.
219247
* @ssp: srcu_struct in which to unregister the old reader.
@@ -254,6 +282,23 @@ srcu_read_unlock_notrace(struct srcu_struct *ssp, int idx) __releases(ssp)
254282
__srcu_read_unlock(ssp, idx);
255283
}
256284

285+
/**
286+
* srcu_up_read - unregister a old reader from an SRCU-protected structure.
287+
* @ssp: srcu_struct in which to unregister the old reader.
288+
* @idx: return value from corresponding srcu_read_lock().
289+
*
290+
* Exit an SRCU read-side critical section, but not necessarily from
291+
* the same context as the maching srcu_down_read().
292+
*/
293+
static inline void srcu_up_read(struct srcu_struct *ssp, int idx)
294+
__releases(ssp)
295+
{
296+
WARN_ON_ONCE(idx & ~0x1);
297+
WARN_ON_ONCE(in_nmi());
298+
srcu_check_nmi_safety(ssp, false);
299+
__srcu_read_unlock(ssp, idx);
300+
}
301+
257302
/**
258303
* smp_mb__after_srcu_read_unlock - ensure full ordering after srcu_read_unlock
259304
*

0 commit comments

Comments
 (0)