xref: /linux/lib/refcount.c (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
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