locking/refcount: Move saturation warnings out of line
[sfrench/cifs-2.6.git] / include / linux / refcount.h
index e3b218d669ceb9b64ac3c5ffc8a035e15e1e0bf3..1cd0a876a7895fd8ba81a643f43cda0c9b2441d4 100644 (file)
@@ -23,6 +23,16 @@ typedef struct refcount_struct {
 
 #define REFCOUNT_INIT(n)       { .refs = ATOMIC_INIT(n), }
 
+enum refcount_saturation_type {
+       REFCOUNT_ADD_NOT_ZERO_OVF,
+       REFCOUNT_ADD_OVF,
+       REFCOUNT_ADD_UAF,
+       REFCOUNT_SUB_UAF,
+       REFCOUNT_DEC_LEAK,
+};
+
+void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t);
+
 /**
  * refcount_set - set a refcount's value
  * @r: the refcount
@@ -154,10 +164,8 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r)
                        break;
        } while (!atomic_try_cmpxchg_relaxed(&r->refs, &old, old + i));
 
-       if (unlikely(old < 0 || old + i < 0)) {
-               refcount_set(r, REFCOUNT_SATURATED);
-               WARN_ONCE(1, "refcount_t: saturated; leaking memory.\n");
-       }
+       if (unlikely(old < 0 || old + i < 0))
+               refcount_warn_saturate(r, REFCOUNT_ADD_NOT_ZERO_OVF);
 
        return old;
 }
@@ -182,11 +190,10 @@ static inline void refcount_add(int i, refcount_t *r)
 {
        int old = atomic_fetch_add_relaxed(i, &r->refs);
 
-       WARN_ONCE(!old, "refcount_t: addition on 0; use-after-free.\n");
-       if (unlikely(old <= 0 || old + i <= 0)) {
-               refcount_set(r, REFCOUNT_SATURATED);
-               WARN_ONCE(old, "refcount_t: saturated; leaking memory.\n");
-       }
+       if (unlikely(!old))
+               refcount_warn_saturate(r, REFCOUNT_ADD_UAF);
+       else if (unlikely(old < 0 || old + i < 0))
+               refcount_warn_saturate(r, REFCOUNT_ADD_OVF);
 }
 
 /**
@@ -253,10 +260,8 @@ static inline __must_check bool refcount_sub_and_test(int i, refcount_t *r)
                return true;
        }
 
-       if (unlikely(old < 0 || old - i < 0)) {
-               refcount_set(r, REFCOUNT_SATURATED);
-               WARN_ONCE(1, "refcount_t: underflow; use-after-free.\n");
-       }
+       if (unlikely(old < 0 || old - i < 0))
+               refcount_warn_saturate(r, REFCOUNT_SUB_UAF);
 
        return false;
 }
@@ -291,12 +296,8 @@ static inline __must_check bool refcount_dec_and_test(refcount_t *r)
  */
 static inline void refcount_dec(refcount_t *r)
 {
-       int old = atomic_fetch_sub_release(1, &r->refs);
-
-       if (unlikely(old <= 1)) {
-               refcount_set(r, REFCOUNT_SATURATED);
-               WARN_ONCE(1, "refcount_t: decrement hit 0; leaking memory.\n");
-       }
+       if (unlikely(atomic_fetch_sub_release(1, &r->refs) <= 1))
+               refcount_warn_saturate(r, REFCOUNT_DEC_LEAK);
 }
 #else /* CONFIG_REFCOUNT_FULL */