Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0 2 : /* 3 : * Out-of-line refcount functions. 4 : */ 5 : 6 : #include <linux/mutex.h> 7 : #include <linux/refcount.h> 8 : #include <linux/spinlock.h> 9 : #include <linux/bug.h> 10 : 11 : #define REFCOUNT_WARN(str) WARN_ONCE(1, "refcount_t: " str ".\n") 12 : 13 0 : void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t) 14 : { 15 0 : refcount_set(r, REFCOUNT_SATURATED); 16 : 17 0 : switch (t) { 18 : case REFCOUNT_ADD_NOT_ZERO_OVF: 19 0 : REFCOUNT_WARN("saturated; leaking memory"); 20 : break; 21 : case REFCOUNT_ADD_OVF: 22 0 : REFCOUNT_WARN("saturated; leaking memory"); 23 : break; 24 : case REFCOUNT_ADD_UAF: 25 0 : REFCOUNT_WARN("addition on 0; use-after-free"); 26 : break; 27 : case REFCOUNT_SUB_UAF: 28 0 : REFCOUNT_WARN("underflow; use-after-free"); 29 : break; 30 : case REFCOUNT_DEC_LEAK: 31 0 : REFCOUNT_WARN("decrement hit 0; leaking memory"); 32 : break; 33 : default: 34 0 : REFCOUNT_WARN("unknown saturation event!?"); 35 : } 36 0 : } 37 : EXPORT_SYMBOL(refcount_warn_saturate); 38 : 39 : /** 40 : * refcount_dec_if_one - decrement a refcount if it is 1 41 : * @r: the refcount 42 : * 43 : * No atomic_t counterpart, it attempts a 1 -> 0 transition and returns the 44 : * success thereof. 45 : * 46 : * Like all decrement operations, it provides release memory order and provides 47 : * a control dependency. 48 : * 49 : * It can be used like a try-delete operator; this explicit case is provided 50 : * and not cmpxchg in generic, because that would allow implementing unsafe 51 : * operations. 52 : * 53 : * Return: true if the resulting refcount is 0, false otherwise 54 : */ 55 0 : bool refcount_dec_if_one(refcount_t *r) 56 : { 57 0 : int val = 1; 58 : 59 0 : return atomic_try_cmpxchg_release(&r->refs, &val, 0); 60 : } 61 : EXPORT_SYMBOL(refcount_dec_if_one); 62 : 63 : /** 64 : * refcount_dec_not_one - decrement a refcount if it is not 1 65 : * @r: the refcount 66 : * 67 : * No atomic_t counterpart, it decrements unless the value is 1, in which case 68 : * it will return false. 69 : * 70 : * Was often done like: atomic_add_unless(&var, -1, 1) 71 : * 72 : * Return: true if the decrement operation was successful, false otherwise 73 : */ 74 159 : bool refcount_dec_not_one(refcount_t *r) 75 : { 76 318 : unsigned int new, val = atomic_read(&r->refs); 77 : 78 : do { 79 159 : if (unlikely(val == REFCOUNT_SATURATED)) 80 : return true; 81 : 82 159 : if (val == 1) 83 : return false; 84 : 85 159 : new = val - 1; 86 159 : if (new > val) { 87 0 : WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n"); 88 : return true; 89 : } 90 : 91 318 : } while (!atomic_try_cmpxchg_release(&r->refs, &val, new)); 92 : 93 : return true; 94 : } 95 : EXPORT_SYMBOL(refcount_dec_not_one); 96 : 97 : /** 98 : * refcount_dec_and_mutex_lock - return holding mutex if able to decrement 99 : * refcount to 0 100 : * @r: the refcount 101 : * @lock: the mutex to be locked 102 : * 103 : * Similar to atomic_dec_and_mutex_lock(), it will WARN on underflow and fail 104 : * to decrement when saturated at REFCOUNT_SATURATED. 105 : * 106 : * Provides release memory ordering, such that prior loads and stores are done 107 : * before, and provides a control dependency such that free() must come after. 108 : * See the comment on top. 109 : * 110 : * Return: true and hold mutex if able to decrement refcount to 0, false 111 : * otherwise 112 : */ 113 0 : bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock) 114 : { 115 0 : if (refcount_dec_not_one(r)) 116 : return false; 117 : 118 0 : mutex_lock(lock); 119 0 : if (!refcount_dec_and_test(r)) { 120 0 : mutex_unlock(lock); 121 0 : return false; 122 : } 123 : 124 : return true; 125 : } 126 : EXPORT_SYMBOL(refcount_dec_and_mutex_lock); 127 : 128 : /** 129 : * refcount_dec_and_lock - return holding spinlock if able to decrement 130 : * refcount to 0 131 : * @r: the refcount 132 : * @lock: the spinlock to be locked 133 : * 134 : * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to 135 : * decrement when saturated at REFCOUNT_SATURATED. 136 : * 137 : * Provides release memory ordering, such that prior loads and stores are done 138 : * before, and provides a control dependency such that free() must come after. 139 : * See the comment on top. 140 : * 141 : * Return: true and hold spinlock if able to decrement refcount to 0, false 142 : * otherwise 143 : */ 144 0 : bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) 145 : { 146 0 : if (refcount_dec_not_one(r)) 147 : return false; 148 : 149 0 : spin_lock(lock); 150 0 : if (!refcount_dec_and_test(r)) { 151 0 : spin_unlock(lock); 152 0 : return false; 153 : } 154 : 155 : return true; 156 : } 157 : EXPORT_SYMBOL(refcount_dec_and_lock); 158 : 159 : /** 160 : * refcount_dec_and_lock_irqsave - return holding spinlock with disabled 161 : * interrupts if able to decrement refcount to 0 162 : * @r: the refcount 163 : * @lock: the spinlock to be locked 164 : * @flags: saved IRQ-flags if the is acquired 165 : * 166 : * Same as refcount_dec_and_lock() above except that the spinlock is acquired 167 : * with disabled interrupts. 168 : * 169 : * Return: true and hold spinlock if able to decrement refcount to 0, false 170 : * otherwise 171 : */ 172 159 : bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock, 173 : unsigned long *flags) 174 : { 175 159 : if (refcount_dec_not_one(r)) 176 : return false; 177 : 178 0 : spin_lock_irqsave(lock, *flags); 179 0 : if (!refcount_dec_and_test(r)) { 180 0 : spin_unlock_irqrestore(lock, *flags); 181 0 : return false; 182 : } 183 : 184 : return true; 185 : } 186 : EXPORT_SYMBOL(refcount_dec_and_lock_irqsave);