#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
                        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;
 }
 {
        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);
 }
 
 /**
                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;
 }
  */
 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 */
 
 
 #include <linux/spinlock.h>
 #include <linux/bug.h>
 
+#define REFCOUNT_WARN(str)     WARN_ONCE(1, "refcount_t: " str ".\n")
+
+void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t)
+{
+       refcount_set(r, REFCOUNT_SATURATED);
+
+       switch (t) {
+       case REFCOUNT_ADD_NOT_ZERO_OVF:
+               REFCOUNT_WARN("saturated; leaking memory");
+               break;
+       case REFCOUNT_ADD_OVF:
+               REFCOUNT_WARN("saturated; leaking memory");
+               break;
+       case REFCOUNT_ADD_UAF:
+               REFCOUNT_WARN("addition on 0; use-after-free");
+               break;
+       case REFCOUNT_SUB_UAF:
+               REFCOUNT_WARN("underflow; use-after-free");
+               break;
+       case REFCOUNT_DEC_LEAK:
+               REFCOUNT_WARN("decrement hit 0; leaking memory");
+               break;
+       default:
+               REFCOUNT_WARN("unknown saturation event!?");
+       }
+}
+EXPORT_SYMBOL(refcount_warn_saturate);
+
 /**
  * refcount_dec_if_one - decrement a refcount if it is 1
  * @r: the refcount