Merge tag 'mm-hotfixes-stable-2025-07-11-16-16' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-block.git] / include / linux / local_lock_internal.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _LINUX_LOCAL_LOCK_H
3 # error "Do not include directly, include linux/local_lock.h"
4 #endif
5
6 #include <linux/percpu-defs.h>
7 #include <linux/lockdep.h>
8
9 #ifndef CONFIG_PREEMPT_RT
10
11 typedef struct {
12 #ifdef CONFIG_DEBUG_LOCK_ALLOC
13         struct lockdep_map      dep_map;
14         struct task_struct      *owner;
15 #endif
16 } local_lock_t;
17
18 /* local_trylock() and local_trylock_irqsave() only work with local_trylock_t */
19 typedef struct {
20         local_lock_t    llock;
21         u8              acquired;
22 } local_trylock_t;
23
24 #ifdef CONFIG_DEBUG_LOCK_ALLOC
25 # define LOCAL_LOCK_DEBUG_INIT(lockname)                \
26         .dep_map = {                                    \
27                 .name = #lockname,                      \
28                 .wait_type_inner = LD_WAIT_CONFIG,      \
29                 .lock_type = LD_LOCK_PERCPU,            \
30         },                                              \
31         .owner = NULL,
32
33 # define LOCAL_TRYLOCK_DEBUG_INIT(lockname)             \
34         .llock = { LOCAL_LOCK_DEBUG_INIT((lockname).llock) },
35
36 static inline void local_lock_acquire(local_lock_t *l)
37 {
38         lock_map_acquire(&l->dep_map);
39         DEBUG_LOCKS_WARN_ON(l->owner);
40         l->owner = current;
41 }
42
43 static inline void local_trylock_acquire(local_lock_t *l)
44 {
45         lock_map_acquire_try(&l->dep_map);
46         DEBUG_LOCKS_WARN_ON(l->owner);
47         l->owner = current;
48 }
49
50 static inline void local_lock_release(local_lock_t *l)
51 {
52         DEBUG_LOCKS_WARN_ON(l->owner != current);
53         l->owner = NULL;
54         lock_map_release(&l->dep_map);
55 }
56
57 static inline void local_lock_debug_init(local_lock_t *l)
58 {
59         l->owner = NULL;
60 }
61 #else /* CONFIG_DEBUG_LOCK_ALLOC */
62 # define LOCAL_LOCK_DEBUG_INIT(lockname)
63 # define LOCAL_TRYLOCK_DEBUG_INIT(lockname)
64 static inline void local_lock_acquire(local_lock_t *l) { }
65 static inline void local_trylock_acquire(local_lock_t *l) { }
66 static inline void local_lock_release(local_lock_t *l) { }
67 static inline void local_lock_debug_init(local_lock_t *l) { }
68 #endif /* !CONFIG_DEBUG_LOCK_ALLOC */
69
70 #define INIT_LOCAL_LOCK(lockname)       { LOCAL_LOCK_DEBUG_INIT(lockname) }
71 #define INIT_LOCAL_TRYLOCK(lockname)    { LOCAL_TRYLOCK_DEBUG_INIT(lockname) }
72
73 #define __local_lock_init(lock)                                 \
74 do {                                                            \
75         static struct lock_class_key __key;                     \
76                                                                 \
77         debug_check_no_locks_freed((void *)lock, sizeof(*lock));\
78         lockdep_init_map_type(&(lock)->dep_map, #lock, &__key,  \
79                               0, LD_WAIT_CONFIG, LD_WAIT_INV,   \
80                               LD_LOCK_PERCPU);                  \
81         local_lock_debug_init(lock);                            \
82 } while (0)
83
84 #define __local_trylock_init(lock) __local_lock_init(lock.llock)
85
86 #define __spinlock_nested_bh_init(lock)                         \
87 do {                                                            \
88         static struct lock_class_key __key;                     \
89                                                                 \
90         debug_check_no_locks_freed((void *)lock, sizeof(*lock));\
91         lockdep_init_map_type(&(lock)->dep_map, #lock, &__key,  \
92                               0, LD_WAIT_CONFIG, LD_WAIT_INV,   \
93                               LD_LOCK_NORMAL);                  \
94         local_lock_debug_init(lock);                            \
95 } while (0)
96
97 #define __local_lock_acquire(lock)                                      \
98         do {                                                            \
99                 local_trylock_t *tl;                                    \
100                 local_lock_t *l;                                        \
101                                                                         \
102                 l = (local_lock_t *)this_cpu_ptr(lock);                 \
103                 tl = (local_trylock_t *)l;                              \
104                 _Generic((lock),                                        \
105                         __percpu local_trylock_t *: ({                  \
106                                 lockdep_assert(tl->acquired == 0);      \
107                                 WRITE_ONCE(tl->acquired, 1);            \
108                         }),                                             \
109                         __percpu local_lock_t *: (void)0);              \
110                 local_lock_acquire(l);                                  \
111         } while (0)
112
113 #define __local_lock(lock)                                      \
114         do {                                                    \
115                 preempt_disable();                              \
116                 __local_lock_acquire(lock);                     \
117         } while (0)
118
119 #define __local_lock_irq(lock)                                  \
120         do {                                                    \
121                 local_irq_disable();                            \
122                 __local_lock_acquire(lock);                     \
123         } while (0)
124
125 #define __local_lock_irqsave(lock, flags)                       \
126         do {                                                    \
127                 local_irq_save(flags);                          \
128                 __local_lock_acquire(lock);                     \
129         } while (0)
130
131 #define __local_trylock(lock)                                   \
132         ({                                                      \
133                 local_trylock_t *tl;                            \
134                                                                 \
135                 preempt_disable();                              \
136                 tl = this_cpu_ptr(lock);                        \
137                 if (READ_ONCE(tl->acquired)) {                  \
138                         preempt_enable();                       \
139                         tl = NULL;                              \
140                 } else {                                        \
141                         WRITE_ONCE(tl->acquired, 1);            \
142                         local_trylock_acquire(                  \
143                                 (local_lock_t *)tl);            \
144                 }                                               \
145                 !!tl;                                           \
146         })
147
148 #define __local_trylock_irqsave(lock, flags)                    \
149         ({                                                      \
150                 local_trylock_t *tl;                            \
151                                                                 \
152                 local_irq_save(flags);                          \
153                 tl = this_cpu_ptr(lock);                        \
154                 if (READ_ONCE(tl->acquired)) {                  \
155                         local_irq_restore(flags);               \
156                         tl = NULL;                              \
157                 } else {                                        \
158                         WRITE_ONCE(tl->acquired, 1);            \
159                         local_trylock_acquire(                  \
160                                 (local_lock_t *)tl);            \
161                 }                                               \
162                 !!tl;                                           \
163         })
164
165 #define __local_lock_release(lock)                                      \
166         do {                                                            \
167                 local_trylock_t *tl;                                    \
168                 local_lock_t *l;                                        \
169                                                                         \
170                 l = (local_lock_t *)this_cpu_ptr(lock);                 \
171                 tl = (local_trylock_t *)l;                              \
172                 local_lock_release(l);                                  \
173                 _Generic((lock),                                        \
174                         __percpu local_trylock_t *: ({                  \
175                                 lockdep_assert(tl->acquired == 1);      \
176                                 WRITE_ONCE(tl->acquired, 0);            \
177                         }),                                             \
178                         __percpu local_lock_t *: (void)0);              \
179         } while (0)
180
181 #define __local_unlock(lock)                                    \
182         do {                                                    \
183                 __local_lock_release(lock);                     \
184                 preempt_enable();                               \
185         } while (0)
186
187 #define __local_unlock_irq(lock)                                \
188         do {                                                    \
189                 __local_lock_release(lock);                     \
190                 local_irq_enable();                             \
191         } while (0)
192
193 #define __local_unlock_irqrestore(lock, flags)                  \
194         do {                                                    \
195                 __local_lock_release(lock);                     \
196                 local_irq_restore(flags);                       \
197         } while (0)
198
199 #define __local_lock_nested_bh(lock)                            \
200         do {                                                    \
201                 lockdep_assert_in_softirq();                    \
202                 local_lock_acquire(this_cpu_ptr(lock)); \
203         } while (0)
204
205 #define __local_unlock_nested_bh(lock)                          \
206         local_lock_release(this_cpu_ptr(lock))
207
208 #else /* !CONFIG_PREEMPT_RT */
209
210 /*
211  * On PREEMPT_RT local_lock maps to a per CPU spinlock, which protects the
212  * critical section while staying preemptible.
213  */
214 typedef spinlock_t local_lock_t;
215 typedef spinlock_t local_trylock_t;
216
217 #define INIT_LOCAL_LOCK(lockname) __LOCAL_SPIN_LOCK_UNLOCKED((lockname))
218 #define INIT_LOCAL_TRYLOCK(lockname) __LOCAL_SPIN_LOCK_UNLOCKED((lockname))
219
220 #define __local_lock_init(l)                                    \
221         do {                                                    \
222                 local_spin_lock_init((l));                      \
223         } while (0)
224
225 #define __local_trylock_init(l)                 __local_lock_init(l)
226
227 #define __local_lock(__lock)                                    \
228         do {                                                    \
229                 migrate_disable();                              \
230                 spin_lock(this_cpu_ptr((__lock)));              \
231         } while (0)
232
233 #define __local_lock_irq(lock)                  __local_lock(lock)
234
235 #define __local_lock_irqsave(lock, flags)                       \
236         do {                                                    \
237                 typecheck(unsigned long, flags);                \
238                 flags = 0;                                      \
239                 __local_lock(lock);                             \
240         } while (0)
241
242 #define __local_unlock(__lock)                                  \
243         do {                                                    \
244                 spin_unlock(this_cpu_ptr((__lock)));            \
245                 migrate_enable();                               \
246         } while (0)
247
248 #define __local_unlock_irq(lock)                __local_unlock(lock)
249
250 #define __local_unlock_irqrestore(lock, flags)  __local_unlock(lock)
251
252 #define __local_lock_nested_bh(lock)                            \
253 do {                                                            \
254         lockdep_assert_in_softirq_func();                       \
255         spin_lock(this_cpu_ptr(lock));                          \
256 } while (0)
257
258 #define __local_unlock_nested_bh(lock)                          \
259 do {                                                            \
260         spin_unlock(this_cpu_ptr((lock)));                      \
261 } while (0)
262
263 #define __local_trylock(lock)                                   \
264         ({                                                      \
265                 int __locked;                                   \
266                                                                 \
267                 if (in_nmi() | in_hardirq()) {                  \
268                         __locked = 0;                           \
269                 } else {                                        \
270                         migrate_disable();                      \
271                         __locked = spin_trylock(this_cpu_ptr((lock)));  \
272                         if (!__locked)                          \
273                                 migrate_enable();               \
274                 }                                               \
275                 __locked;                                       \
276         })
277
278 #define __local_trylock_irqsave(lock, flags)                    \
279         ({                                                      \
280                 typecheck(unsigned long, flags);                \
281                 flags = 0;                                      \
282                 __local_trylock(lock);                          \
283         })
284
285 #endif /* CONFIG_PREEMPT_RT */