aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-04 13:09:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-04 13:09:27 -0400
commitf2a84170ede80e4b80f636e3700ef4d4d5dc7d33 (patch)
tree68a51fd83da747173200e06b046cbeddd80251a4 /lib
parentc4c3f5fba01e189fb3618f09545abdb4cf8ec8ee (diff)
parent2d7227828e1475c7b272e55bd70c4cec8eea219a (diff)
Merge branch 'for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu
Pull percpu updates from Tejun Heo: - Major reorganization of percpu header files which I think makes things a lot more readable and logical than before. - percpu-refcount is updated so that it requires explicit destruction and can be reinitialized if necessary. This was pulled into the block tree to replace the custom percpu refcnting implemented in blk-mq. - In the process, percpu and percpu-refcount got cleaned up a bit * 'for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu: (21 commits) percpu-refcount: implement percpu_ref_reinit() and percpu_ref_is_zero() percpu-refcount: require percpu_ref to be exited explicitly percpu-refcount: use unsigned long for pcpu_count pointer percpu-refcount: add helpers for ->percpu_count accesses percpu-refcount: one bit is enough for REF_STATUS percpu-refcount, aio: use percpu_ref_cancel_init() in ioctx_alloc() workqueue: stronger test in process_one_work() workqueue: clear POOL_DISASSOCIATED in rebind_workers() percpu: Use ALIGN macro instead of hand coding alignment calculation percpu: invoke __verify_pcpu_ptr() from the generic part of accessors and operations percpu: preffity percpu header files percpu: use raw_cpu_*() to define __this_cpu_*() percpu: reorder macros in percpu header files percpu: move {raw|this}_cpu_*() definitions to include/linux/percpu-defs.h percpu: move generic {raw|this}_cpu_*_N() definitions to include/asm-generic/percpu.h percpu: only allow sized arch overrides for {raw|this}_cpu_*() ops percpu: reorganize include/linux/percpu-defs.h percpu: move accessors from include/linux/percpu.h to percpu-defs.h percpu: include/asm-generic/percpu.h should contain only arch-overridable parts percpu: introduce arch_raw_cpu_ptr() ...
Diffstat (limited to 'lib')
-rw-r--r--lib/percpu-refcount.c86
1 files changed, 54 insertions, 32 deletions
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index 963b7034a51b..fe5a3342e960 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -31,6 +31,11 @@
31 31
32#define PCPU_COUNT_BIAS (1U << 31) 32#define PCPU_COUNT_BIAS (1U << 31)
33 33
34static unsigned __percpu *pcpu_count_ptr(struct percpu_ref *ref)
35{
36 return (unsigned __percpu *)(ref->pcpu_count_ptr & ~PCPU_REF_DEAD);
37}
38
34/** 39/**
35 * percpu_ref_init - initialize a percpu refcount 40 * percpu_ref_init - initialize a percpu refcount
36 * @ref: percpu_ref to initialize 41 * @ref: percpu_ref to initialize
@@ -46,8 +51,8 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release)
46{ 51{
47 atomic_set(&ref->count, 1 + PCPU_COUNT_BIAS); 52 atomic_set(&ref->count, 1 + PCPU_COUNT_BIAS);
48 53
49 ref->pcpu_count = alloc_percpu(unsigned); 54 ref->pcpu_count_ptr = (unsigned long)alloc_percpu(unsigned);
50 if (!ref->pcpu_count) 55 if (!ref->pcpu_count_ptr)
51 return -ENOMEM; 56 return -ENOMEM;
52 57
53 ref->release = release; 58 ref->release = release;
@@ -56,53 +61,71 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release)
56EXPORT_SYMBOL_GPL(percpu_ref_init); 61EXPORT_SYMBOL_GPL(percpu_ref_init);
57 62
58/** 63/**
59 * percpu_ref_cancel_init - cancel percpu_ref_init() 64 * percpu_ref_reinit - re-initialize a percpu refcount
60 * @ref: percpu_ref to cancel init for 65 * @ref: perpcu_ref to re-initialize
61 * 66 *
62 * Once a percpu_ref is initialized, its destruction is initiated by 67 * Re-initialize @ref so that it's in the same state as when it finished
63 * percpu_ref_kill() and completes asynchronously, which can be painful to 68 * percpu_ref_init(). @ref must have been initialized successfully, killed
64 * do when destroying a half-constructed object in init failure path. 69 * and reached 0 but not exited.
65 * 70 *
66 * This function destroys @ref without invoking @ref->release and the 71 * Note that percpu_ref_tryget[_live]() are safe to perform on @ref while
67 * memory area containing it can be freed immediately on return. To 72 * this function is in progress.
68 * prevent accidental misuse, it's required that @ref has finished
69 * percpu_ref_init(), whether successful or not, but never used.
70 *
71 * The weird name and usage restriction are to prevent people from using
72 * this function by mistake for normal shutdown instead of
73 * percpu_ref_kill().
74 */ 73 */
75void percpu_ref_cancel_init(struct percpu_ref *ref) 74void percpu_ref_reinit(struct percpu_ref *ref)
76{ 75{
77 unsigned __percpu *pcpu_count = ref->pcpu_count; 76 unsigned __percpu *pcpu_count = pcpu_count_ptr(ref);
78 int cpu; 77 int cpu;
79 78
80 WARN_ON_ONCE(atomic_read(&ref->count) != 1 + PCPU_COUNT_BIAS); 79 BUG_ON(!pcpu_count);
80 WARN_ON(!percpu_ref_is_zero(ref));
81
82 atomic_set(&ref->count, 1 + PCPU_COUNT_BIAS);
83
84 /*
85 * Restore per-cpu operation. smp_store_release() is paired with
86 * smp_read_barrier_depends() in __pcpu_ref_alive() and guarantees
87 * that the zeroing is visible to all percpu accesses which can see
88 * the following PCPU_REF_DEAD clearing.
89 */
90 for_each_possible_cpu(cpu)
91 *per_cpu_ptr(pcpu_count, cpu) = 0;
92
93 smp_store_release(&ref->pcpu_count_ptr,
94 ref->pcpu_count_ptr & ~PCPU_REF_DEAD);
95}
96EXPORT_SYMBOL_GPL(percpu_ref_reinit);
97
98/**
99 * percpu_ref_exit - undo percpu_ref_init()
100 * @ref: percpu_ref to exit
101 *
102 * This function exits @ref. The caller is responsible for ensuring that
103 * @ref is no longer in active use. The usual places to invoke this
104 * function from are the @ref->release() callback or in init failure path
105 * where percpu_ref_init() succeeded but other parts of the initialization
106 * of the embedding object failed.
107 */
108void percpu_ref_exit(struct percpu_ref *ref)
109{
110 unsigned __percpu *pcpu_count = pcpu_count_ptr(ref);
81 111
82 if (pcpu_count) { 112 if (pcpu_count) {
83 for_each_possible_cpu(cpu) 113 free_percpu(pcpu_count);
84 WARN_ON_ONCE(*per_cpu_ptr(pcpu_count, cpu)); 114 ref->pcpu_count_ptr = PCPU_REF_DEAD;
85 free_percpu(ref->pcpu_count);
86 } 115 }
87} 116}
88EXPORT_SYMBOL_GPL(percpu_ref_cancel_init); 117EXPORT_SYMBOL_GPL(percpu_ref_exit);
89 118
90static void percpu_ref_kill_rcu(struct rcu_head *rcu) 119static void percpu_ref_kill_rcu(struct rcu_head *rcu)
91{ 120{
92 struct percpu_ref *ref = container_of(rcu, struct percpu_ref, rcu); 121 struct percpu_ref *ref = container_of(rcu, struct percpu_ref, rcu);
93 unsigned __percpu *pcpu_count = ref->pcpu_count; 122 unsigned __percpu *pcpu_count = pcpu_count_ptr(ref);
94 unsigned count = 0; 123 unsigned count = 0;
95 int cpu; 124 int cpu;
96 125
97 /* Mask out PCPU_REF_DEAD */
98 pcpu_count = (unsigned __percpu *)
99 (((unsigned long) pcpu_count) & ~PCPU_STATUS_MASK);
100
101 for_each_possible_cpu(cpu) 126 for_each_possible_cpu(cpu)
102 count += *per_cpu_ptr(pcpu_count, cpu); 127 count += *per_cpu_ptr(pcpu_count, cpu);
103 128
104 free_percpu(pcpu_count);
105
106 pr_debug("global %i pcpu %i", atomic_read(&ref->count), (int) count); 129 pr_debug("global %i pcpu %i", atomic_read(&ref->count), (int) count);
107 130
108 /* 131 /*
@@ -152,11 +175,10 @@ static void percpu_ref_kill_rcu(struct rcu_head *rcu)
152void percpu_ref_kill_and_confirm(struct percpu_ref *ref, 175void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
153 percpu_ref_func_t *confirm_kill) 176 percpu_ref_func_t *confirm_kill)
154{ 177{
155 WARN_ONCE(REF_STATUS(ref->pcpu_count) == PCPU_REF_DEAD, 178 WARN_ONCE(ref->pcpu_count_ptr & PCPU_REF_DEAD,
156 "percpu_ref_kill() called more than once!\n"); 179 "percpu_ref_kill() called more than once!\n");
157 180
158 ref->pcpu_count = (unsigned __percpu *) 181 ref->pcpu_count_ptr |= PCPU_REF_DEAD;
159 (((unsigned long) ref->pcpu_count)|PCPU_REF_DEAD);
160 ref->confirm_kill = confirm_kill; 182 ref->confirm_kill = confirm_kill;
161 183
162 call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu); 184 call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu);