History

locking/refcount: Move saturation warnings out of line

Having the refcount saturation and warnings inline bloats the text, despite the fact that these paths should never be executed in normal operation. Move the refcount saturation and warnings out of line to reduce the image size when refcount_t checking is enabled. Relative to an x86_64 defconfig, the sizes reported by bloat-o-meter are: # defconfig+REFCOUNT_FULL, inline saturation (i.e. before this patch) Total: Before=14762076, After=14915442, chg +1.04% # defconfig+REFCOUNT_FULL, out-of-line saturation (i.e. after this patch) Total: Before=14762076, After=14835497, chg +0.50% A side-effect of this change is that we now only get one warning per refcount saturation type, rather than one per problematic call-site.

Will Deacon committed 6 years ago

Commit 1eb085d1 parent dcb78642 files · +48 −19Browse files

Showing the changes to include/linux (1 of 2 files). Show all

Unified · Split

include/linux/refcount.h+20−19
@@ -23,6 +23,16 @@ typedef struct refcount_struct { · 22 unmodified lines
2323
2424 #define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), }
2525
26+enum refcount_saturation_type {
27+ REFCOUNT_ADD_NOT_ZERO_OVF,
28+ REFCOUNT_ADD_OVF,
29+ REFCOUNT_ADD_UAF,
30+ REFCOUNT_SUB_UAF,
31+ REFCOUNT_DEC_LEAK,
32+};
33+
34+void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t);
35+
2636 /**
2737 * refcount_set - set a refcount's value
2838 * @r: the refcount
@@ -154,10 +164,8 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r) · 125 unmodified lines
154164 break;
155165 } while (!atomic_try_cmpxchg_relaxed(&r->refs, &old, old + i));
156166
157− if (unlikely(old < 0 || old + i < 0)) {
158− refcount_set(r, REFCOUNT_SATURATED);
159− WARN_ONCE(1, "refcount_t: saturated; leaking memory.\n");
160− }
167+ if (unlikely(old < 0 || old + i < 0))
168+ refcount_warn_saturate(r, REFCOUNT_ADD_NOT_ZERO_OVF);
161169
162170 return old;
163171 }
@@ -182,11 +190,10 @@ static inline void refcount_add(int i, refcount_t *r) · 18 unmodified lines
182190 {
183191 int old = atomic_fetch_add_relaxed(i, &r->refs);
184192
185− WARN_ONCE(!old, "refcount_t: addition on 0; use-after-free.\n");
186− if (unlikely(old <= 0 || old + i <= 0)) {
187− refcount_set(r, REFCOUNT_SATURATED);
188− WARN_ONCE(old, "refcount_t: saturated; leaking memory.\n");
189− }
193+ if (unlikely(!old))
194+ refcount_warn_saturate(r, REFCOUNT_ADD_UAF);
195+ else if (unlikely(old < 0 || old + i < 0))
196+ refcount_warn_saturate(r, REFCOUNT_ADD_OVF);
190197 }
191198
192199 /**
@@ -253,10 +260,8 @@ static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r) · 60 unmodified lines
253260 return true;
254261 }
255262
256− if (unlikely(old < 0 || old - i < 0)) {
257− refcount_set(r, REFCOUNT_SATURATED);
258− WARN_ONCE(1, "refcount_t: underflow; use-after-free.\n");
259− }
263+ if (unlikely(old < 0 || old - i < 0))
264+ refcount_warn_saturate(r, REFCOUNT_SUB_UAF);
260265
261266 return false;
262267 }
@@ -291,12 +296,8 @@ static inline __must_check bool refcount_dec_and_test(refcount_t *r) · 28 unmodified lines
291296 */
292297 static inline void refcount_dec(refcount_t *r)
293298 {
294− int old = atomic_fetch_sub_release(1, &r->refs);
295−
296− if (unlikely(old <= 1)) {
297− refcount_set(r, REFCOUNT_SATURATED);
298− WARN_ONCE(1, "refcount_t: decrement hit 0; leaking memory.\n");
299− }
299+ if (unlikely(atomic_fetch_sub_release(1, &r->refs) <= 1))
300+ refcount_warn_saturate(r, REFCOUNT_DEC_LEAK);
300301 }
301302 #else /* CONFIG_REFCOUNT_FULL */
302303

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t