aboutsummaryrefslogtreecommitdiffstats
path: root/lib/percpu-refcount.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-09-24 13:31:49 -0400
committerTejun Heo <tj@kernel.org>2014-09-24 13:31:49 -0400
commit27344a9017cdaff82a167827da3001a0918afdc3 (patch)
tree025e5eb1351f394a83e3400e221bd3149b6eb6a4 /lib/percpu-refcount.c
parent9e804d1f58da1eca079f796347c1cf1d1df564e2 (diff)
percpu_ref: add PCPU_REF_DEAD
percpu_ref will be restructured so that percpu/atomic mode switching and reference killing are dedoupled. In preparation, add PCPU_REF_DEAD and PCPU_REF_ATOMIC_DEAD which is OR of ATOMIC and DEAD. For now, ATOMIC and DEAD are changed together and all PCPU_REF_ATOMIC uses are converted to PCPU_REF_ATOMIC_DEAD without causing any behavior changes. percpu_ref_init() now specifies an explicit alignment when allocating the percpu counters so that the pointer has enough unused low bits to accomodate the flags. Note that one flag was fine as min alignment for percpu memory is 2 bytes but two flags are already too many for the natural alignment of unsigned longs on archs like cris and m68k. v2: The original patch had BUILD_BUG_ON() which triggers if unsigned long's alignment isn't enough to accomodate the flags, which triggered on cris and m64k. percpu_ref_init() updated to specify the required alignment explicitly. Reported by Fengguang. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Kent Overstreet <kmo@daterainc.com> Cc: kbuild test robot <fengguang.wu@intel.com>
Diffstat (limited to 'lib/percpu-refcount.c')
-rw-r--r--lib/percpu-refcount.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index 7aef590c1ef8..e2ff19f970cf 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -34,7 +34,7 @@
34static unsigned long __percpu *percpu_count_ptr(struct percpu_ref *ref) 34static unsigned long __percpu *percpu_count_ptr(struct percpu_ref *ref)
35{ 35{
36 return (unsigned long __percpu *) 36 return (unsigned long __percpu *)
37 (ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC); 37 (ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC_DEAD);
38} 38}
39 39
40/** 40/**
@@ -52,10 +52,13 @@ static unsigned long __percpu *percpu_count_ptr(struct percpu_ref *ref)
52int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release, 52int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release,
53 gfp_t gfp) 53 gfp_t gfp)
54{ 54{
55 size_t align = max_t(size_t, 1 << __PERCPU_REF_FLAG_BITS,
56 __alignof__(unsigned long));
57
55 atomic_long_set(&ref->count, 1 + PERCPU_COUNT_BIAS); 58 atomic_long_set(&ref->count, 1 + PERCPU_COUNT_BIAS);
56 59
57 ref->percpu_count_ptr = 60 ref->percpu_count_ptr = (unsigned long)
58 (unsigned long)alloc_percpu_gfp(unsigned long, gfp); 61 __alloc_percpu_gfp(sizeof(unsigned long), align, gfp);
59 if (!ref->percpu_count_ptr) 62 if (!ref->percpu_count_ptr)
60 return -ENOMEM; 63 return -ENOMEM;
61 64
@@ -80,7 +83,7 @@ void percpu_ref_exit(struct percpu_ref *ref)
80 83
81 if (percpu_count) { 84 if (percpu_count) {
82 free_percpu(percpu_count); 85 free_percpu(percpu_count);
83 ref->percpu_count_ptr = __PERCPU_REF_ATOMIC; 86 ref->percpu_count_ptr = __PERCPU_REF_ATOMIC_DEAD;
84 } 87 }
85} 88}
86EXPORT_SYMBOL_GPL(percpu_ref_exit); 89EXPORT_SYMBOL_GPL(percpu_ref_exit);
@@ -145,10 +148,10 @@ static void percpu_ref_kill_rcu(struct rcu_head *rcu)
145void percpu_ref_kill_and_confirm(struct percpu_ref *ref, 148void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
146 percpu_ref_func_t *confirm_kill) 149 percpu_ref_func_t *confirm_kill)
147{ 150{
148 WARN_ONCE(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC, 151 WARN_ONCE(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC_DEAD,
149 "%s called more than once on %pf!", __func__, ref->release); 152 "%s called more than once on %pf!", __func__, ref->release);
150 153
151 ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; 154 ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC_DEAD;
152 ref->confirm_switch = confirm_kill; 155 ref->confirm_switch = confirm_kill;
153 156
154 call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu); 157 call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu);
@@ -180,12 +183,12 @@ void percpu_ref_reinit(struct percpu_ref *ref)
180 * Restore per-cpu operation. smp_store_release() is paired with 183 * Restore per-cpu operation. smp_store_release() is paired with
181 * smp_read_barrier_depends() in __ref_is_percpu() and guarantees 184 * smp_read_barrier_depends() in __ref_is_percpu() and guarantees
182 * that the zeroing is visible to all percpu accesses which can see 185 * that the zeroing is visible to all percpu accesses which can see
183 * the following __PERCPU_REF_ATOMIC clearing. 186 * the following __PERCPU_REF_ATOMIC_DEAD clearing.
184 */ 187 */
185 for_each_possible_cpu(cpu) 188 for_each_possible_cpu(cpu)
186 *per_cpu_ptr(percpu_count, cpu) = 0; 189 *per_cpu_ptr(percpu_count, cpu) = 0;
187 190
188 smp_store_release(&ref->percpu_count_ptr, 191 smp_store_release(&ref->percpu_count_ptr,
189 ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC); 192 ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC_DEAD);
190} 193}
191EXPORT_SYMBOL_GPL(percpu_ref_reinit); 194EXPORT_SYMBOL_GPL(percpu_ref_reinit);