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