aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/percpu-refcount.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index ebeaac274cb9..8bf9e719cca0 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -118,6 +118,10 @@ static void percpu_ref_kill_rcu(struct rcu_head *rcu)
118 118
119 atomic_add((int) count - PCPU_COUNT_BIAS, &ref->count); 119 atomic_add((int) count - PCPU_COUNT_BIAS, &ref->count);
120 120
121 /* @ref is viewed as dead on all CPUs, send out kill confirmation */
122 if (ref->confirm_kill)
123 ref->confirm_kill(ref);
124
121 /* 125 /*
122 * Now we're in single atomic_t mode with a consistent refcount, so it's 126 * Now we're in single atomic_t mode with a consistent refcount, so it's
123 * safe to drop our initial ref: 127 * safe to drop our initial ref:
@@ -126,22 +130,29 @@ static void percpu_ref_kill_rcu(struct rcu_head *rcu)
126} 130}
127 131
128/** 132/**
129 * percpu_ref_kill - safely drop initial ref 133 * percpu_ref_kill_and_confirm - drop the initial ref and schedule confirmation
130 * @ref: percpu_ref to kill 134 * @ref: percpu_ref to kill
135 * @confirm_kill: optional confirmation callback
131 * 136 *
132 * Must be used to drop the initial ref on a percpu refcount; must be called 137 * Equivalent to percpu_ref_kill() but also schedules kill confirmation if
133 * precisely once before shutdown. 138 * @confirm_kill is not NULL. @confirm_kill, which may not block, will be
139 * called after @ref is seen as dead from all CPUs - all further
140 * invocations of percpu_ref_tryget() will fail. See percpu_ref_tryget()
141 * for more details.
134 * 142 *
135 * Puts @ref in non percpu mode, then does a call_rcu() before gathering up the 143 * Due to the way percpu_ref is implemented, @confirm_kill will be called
136 * percpu counters and dropping the initial ref. 144 * after at least one full RCU grace period has passed but this is an
145 * implementation detail and callers must not depend on it.
137 */ 146 */
138void percpu_ref_kill(struct percpu_ref *ref) 147void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
148 percpu_ref_func_t *confirm_kill)
139{ 149{
140 WARN_ONCE(REF_STATUS(ref->pcpu_count) == PCPU_REF_DEAD, 150 WARN_ONCE(REF_STATUS(ref->pcpu_count) == PCPU_REF_DEAD,
141 "percpu_ref_kill() called more than once!\n"); 151 "percpu_ref_kill() called more than once!\n");
142 152
143 ref->pcpu_count = (unsigned __percpu *) 153 ref->pcpu_count = (unsigned __percpu *)
144 (((unsigned long) ref->pcpu_count)|PCPU_REF_DEAD); 154 (((unsigned long) ref->pcpu_count)|PCPU_REF_DEAD);
155 ref->confirm_kill = confirm_kill;
145 156
146 call_rcu(&ref->rcu, percpu_ref_kill_rcu); 157 call_rcu(&ref->rcu, percpu_ref_kill_rcu);
147} 158}