~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/refcount.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 void refcount_warn_saturate(refcount_t *r, enum refcount_saturation_type t)
 14 {
 15         refcount_set(r, REFCOUNT_SATURATED);
 16 
 17         switch (t) {
 18         case REFCOUNT_ADD_NOT_ZERO_OVF:
 19                 REFCOUNT_WARN("saturated; leaking memory");
 20                 break;
 21         case REFCOUNT_ADD_OVF:
 22                 REFCOUNT_WARN("saturated; leaking memory");
 23                 break;
 24         case REFCOUNT_ADD_UAF:
 25                 REFCOUNT_WARN("addition on 0; use-after-free");
 26                 break;
 27         case REFCOUNT_SUB_UAF:
 28                 REFCOUNT_WARN("underflow; use-after-free");
 29                 break;
 30         case REFCOUNT_DEC_LEAK:
 31                 REFCOUNT_WARN("decrement hit 0; leaking memory");
 32                 break;
 33         default:
 34                 REFCOUNT_WARN("unknown saturation event!?");
 35         }
 36 }
 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 bool refcount_dec_if_one(refcount_t *r)
 56 {
 57         int val = 1;
 58 
 59         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 bool refcount_dec_not_one(refcount_t *r)
 75 {
 76         unsigned int new, val = atomic_read(&r->refs);
 77 
 78         do {
 79                 if (unlikely(val == REFCOUNT_SATURATED))
 80                         return true;
 81 
 82                 if (val == 1)
 83                         return false;
 84 
 85                 new = val - 1;
 86                 if (new > val) {
 87                         WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n");
 88                         return true;
 89                 }
 90 
 91         } 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 bool refcount_dec_and_mutex_lock(refcount_t *r, struct mutex *lock)
114 {
115         if (refcount_dec_not_one(r))
116                 return false;
117 
118         mutex_lock(lock);
119         if (!refcount_dec_and_test(r)) {
120                 mutex_unlock(lock);
121                 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 bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock)
145 {
146         if (refcount_dec_not_one(r))
147                 return false;
148 
149         spin_lock(lock);
150         if (!refcount_dec_and_test(r)) {
151                 spin_unlock(lock);
152                 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 bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock,
173                                    unsigned long *flags)
174 {
175         if (refcount_dec_not_one(r))
176                 return false;
177 
178         spin_lock_irqsave(lock, *flags);
179         if (!refcount_dec_and_test(r)) {
180                 spin_unlock_irqrestore(lock, *flags);
181                 return false;
182         }
183 
184         return true;
185 }
186 EXPORT_SYMBOL(refcount_dec_and_lock_irqsave);
187 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php