Branch data 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 : 408876 : bool refcount_dec_not_one(refcount_t *r) 75 : : { 76 : 408876 : unsigned int new, val = atomic_read(&r->refs); 77 : : 78 : 408876 : do { 79 [ + - ]: 408876 : if (unlikely(val == REFCOUNT_SATURATED)) 80 : : return true; 81 : : 82 [ + + ]: 408876 : if (val == 1) 83 : : return false; 84 : : 85 : 408395 : new = val - 1; 86 [ - + ]: 408395 : if (new > val) { 87 [ # # ]: 0 : WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n"); 88 : 0 : return true; 89 : : } 90 : : 91 [ - + ]: 408395 : } 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 : 2497 : bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock) 145 : : { 146 [ + + ]: 2497 : if (refcount_dec_not_one(r)) 147 : : return false; 148 : : 149 : 221 : spin_lock(lock); 150 [ - + ]: 221 : 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 interupts. 168 : : * 169 : : * Return: true and hold spinlock if able to decrement refcount to 0, false 170 : : * otherwise 171 : : */ 172 : 342424 : bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock, 173 : : unsigned long *flags) 174 : : { 175 [ + + ]: 342424 : if (refcount_dec_not_one(r)) 176 : : return false; 177 : : 178 : 13 : spin_lock_irqsave(lock, *flags); 179 [ - + ]: 13 : 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);