diff options
Diffstat (limited to 'kernel/rcupdate.c')
| -rw-r--r-- | kernel/rcupdate.c | 44 | 
1 files changed, 44 insertions, 0 deletions
| diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 95cba41ce1e9..4e6a61b15e86 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c | |||
| @@ -54,6 +54,50 @@ | |||
| 54 | #ifdef CONFIG_PREEMPT_RCU | 54 | #ifdef CONFIG_PREEMPT_RCU | 
| 55 | 55 | ||
| 56 | /* | 56 | /* | 
| 57 | * Preemptible RCU implementation for rcu_read_lock(). | ||
| 58 | * Just increment ->rcu_read_lock_nesting, shared state will be updated | ||
| 59 | * if we block. | ||
| 60 | */ | ||
| 61 | void __rcu_read_lock(void) | ||
| 62 | { | ||
| 63 | current->rcu_read_lock_nesting++; | ||
| 64 | barrier(); /* critical section after entry code. */ | ||
| 65 | } | ||
| 66 | EXPORT_SYMBOL_GPL(__rcu_read_lock); | ||
| 67 | |||
| 68 | /* | ||
| 69 | * Preemptible RCU implementation for rcu_read_unlock(). | ||
| 70 | * Decrement ->rcu_read_lock_nesting. If the result is zero (outermost | ||
| 71 | * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then | ||
| 72 | * invoke rcu_read_unlock_special() to clean up after a context switch | ||
| 73 | * in an RCU read-side critical section and other special cases. | ||
| 74 | */ | ||
| 75 | void __rcu_read_unlock(void) | ||
| 76 | { | ||
| 77 | struct task_struct *t = current; | ||
| 78 | |||
| 79 | if (t->rcu_read_lock_nesting != 1) { | ||
| 80 | --t->rcu_read_lock_nesting; | ||
| 81 | } else { | ||
| 82 | barrier(); /* critical section before exit code. */ | ||
| 83 | t->rcu_read_lock_nesting = INT_MIN; | ||
| 84 | barrier(); /* assign before ->rcu_read_unlock_special load */ | ||
| 85 | if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special))) | ||
| 86 | rcu_read_unlock_special(t); | ||
| 87 | barrier(); /* ->rcu_read_unlock_special load before assign */ | ||
| 88 | t->rcu_read_lock_nesting = 0; | ||
| 89 | } | ||
| 90 | #ifdef CONFIG_PROVE_LOCKING | ||
| 91 | { | ||
| 92 | int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting); | ||
| 93 | |||
| 94 | WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2); | ||
| 95 | } | ||
| 96 | #endif /* #ifdef CONFIG_PROVE_LOCKING */ | ||
| 97 | } | ||
| 98 | EXPORT_SYMBOL_GPL(__rcu_read_unlock); | ||
| 99 | |||
| 100 | /* | ||
| 57 | * Check for a task exiting while in a preemptible-RCU read-side | 101 | * Check for a task exiting while in a preemptible-RCU read-side | 
| 58 | * critical section, clean up if so. No need to issue warnings, | 102 | * critical section, clean up if so. No need to issue warnings, | 
| 59 | * as debug_check_no_locks_held() already does this if lockdep | 103 | * as debug_check_no_locks_held() already does this if lockdep | 
