aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/percpu-refcount.h
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2014-06-04 09:58:24 -0400
committerTejun Heo <tj@kernel.org>2014-06-04 12:12:29 -0400
commit0c36b390a546055b6815d4b93a2c9fed4d980ffb (patch)
treec0ef99ba5fa35881ba8c50ac5d2238daa7e5138a /include/linux/percpu-refcount.h
parent5a838c3b60e3a36ade764cf7751b8f17d7c9c2da (diff)
percpu-refcount: fix usage of this_cpu_ops
The percpu-refcount infrastructure uses the underscore variants of this_cpu_ops in order to modify percpu reference counters. (e.g. __this_cpu_inc()). However the underscore variants do not atomically update the percpu variable, instead they may be implemented using read-modify-write semantics (more than one instruction). Therefore it is only safe to use the underscore variant if the context is always the same (process, softirq, or hardirq). Otherwise it is possible to lose updates. This problem is something that Sebastian has seen within the aio subsystem which uses percpu refcounters both in process and softirq context leading to reference counts that never dropped to zeroes; even though the number of "get" and "put" calls matched. Fix this by using the non-underscore this_cpu_ops variant which provides correct per cpu atomic semantics and fixes the corrupted reference counts. Cc: Kent Overstreet <kmo@daterainc.com> Cc: <stable@vger.kernel.org> # v3.11+ Reported-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Tejun Heo <tj@kernel.org> References: http://lkml.kernel.org/g/alpine.LFD.2.11.1406041540520.21183@denkbrett
Diffstat (limited to 'include/linux/percpu-refcount.h')
-rw-r--r--include/linux/percpu-refcount.h6
1 files changed, 3 insertions, 3 deletions
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
index 95961f0bf62d..0afb48fd449d 100644
--- a/include/linux/percpu-refcount.h
+++ b/include/linux/percpu-refcount.h
@@ -110,7 +110,7 @@ static inline void percpu_ref_get(struct percpu_ref *ref)
110 pcpu_count = ACCESS_ONCE(ref->pcpu_count); 110 pcpu_count = ACCESS_ONCE(ref->pcpu_count);
111 111
112 if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR)) 112 if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR))
113 __this_cpu_inc(*pcpu_count); 113 this_cpu_inc(*pcpu_count);
114 else 114 else
115 atomic_inc(&ref->count); 115 atomic_inc(&ref->count);
116 116
@@ -139,7 +139,7 @@ static inline bool percpu_ref_tryget(struct percpu_ref *ref)
139 pcpu_count = ACCESS_ONCE(ref->pcpu_count); 139 pcpu_count = ACCESS_ONCE(ref->pcpu_count);
140 140
141 if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR)) { 141 if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR)) {
142 __this_cpu_inc(*pcpu_count); 142 this_cpu_inc(*pcpu_count);
143 ret = true; 143 ret = true;
144 } 144 }
145 145
@@ -164,7 +164,7 @@ static inline void percpu_ref_put(struct percpu_ref *ref)
164 pcpu_count = ACCESS_ONCE(ref->pcpu_count); 164 pcpu_count = ACCESS_ONCE(ref->pcpu_count);
165 165
166 if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR)) 166 if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR))
167 __this_cpu_dec(*pcpu_count); 167 this_cpu_dec(*pcpu_count);
168 else if (unlikely(atomic_dec_and_test(&ref->count))) 168 else if (unlikely(atomic_dec_and_test(&ref->count)))
169 ref->release(ref); 169 ref->release(ref);
170 170