hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/kernel/notifier.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 #include <linux/kdebug.h>
23 #include <linux/kprobes.h>
34 #include <linux/export.h>
....@@ -22,21 +23,10 @@
2223 struct notifier_block *n)
2324 {
2425 while ((*nl) != NULL) {
25
- if (n->priority > (*nl)->priority)
26
- break;
27
- nl = &((*nl)->next);
28
- }
29
- n->next = *nl;
30
- rcu_assign_pointer(*nl, n);
31
- return 0;
32
-}
33
-
34
-static int notifier_chain_cond_register(struct notifier_block **nl,
35
- struct notifier_block *n)
36
-{
37
- while ((*nl) != NULL) {
38
- if ((*nl) == n)
26
+ if (unlikely((*nl) == n)) {
27
+ WARN(1, "double register detected");
3928 return 0;
29
+ }
4030 if (n->priority > (*nl)->priority)
4131 break;
4232 nl = &((*nl)->next);
....@@ -104,6 +94,34 @@
10494 }
10595 NOKPROBE_SYMBOL(notifier_call_chain);
10696
97
+/**
98
+ * notifier_call_chain_robust - Inform the registered notifiers about an event
99
+ * and rollback on error.
100
+ * @nl: Pointer to head of the blocking notifier chain
101
+ * @val_up: Value passed unmodified to the notifier function
102
+ * @val_down: Value passed unmodified to the notifier function when recovering
103
+ * from an error on @val_up
104
+ * @v Pointer passed unmodified to the notifier function
105
+ *
106
+ * NOTE: It is important the @nl chain doesn't change between the two
107
+ * invocations of notifier_call_chain() such that we visit the
108
+ * exact same notifier callbacks; this rules out any RCU usage.
109
+ *
110
+ * Returns: the return value of the @val_up call.
111
+ */
112
+static int notifier_call_chain_robust(struct notifier_block **nl,
113
+ unsigned long val_up, unsigned long val_down,
114
+ void *v)
115
+{
116
+ int ret, nr = 0;
117
+
118
+ ret = notifier_call_chain(nl, val_up, v, -1, &nr);
119
+ if (ret & NOTIFY_STOP_MASK)
120
+ notifier_call_chain(nl, val_down, v, nr-1, NULL);
121
+
122
+ return ret;
123
+}
124
+
107125 /*
108126 * Atomic notifier chain routines. Registration and unregistration
109127 * use a spinlock, and call_chain is synchronized by RCU (no locks).
....@@ -124,9 +142,9 @@
124142 unsigned long flags;
125143 int ret;
126144
127
- spin_lock_irqsave(&nh->lock, flags);
145
+ raw_spin_lock_irqsave(&nh->lock, flags);
128146 ret = notifier_chain_register(&nh->head, n);
129
- spin_unlock_irqrestore(&nh->lock, flags);
147
+ raw_spin_unlock_irqrestore(&nh->lock, flags);
130148 return ret;
131149 }
132150 EXPORT_SYMBOL_GPL(atomic_notifier_chain_register);
....@@ -146,21 +164,38 @@
146164 unsigned long flags;
147165 int ret;
148166
149
- spin_lock_irqsave(&nh->lock, flags);
167
+ raw_spin_lock_irqsave(&nh->lock, flags);
150168 ret = notifier_chain_unregister(&nh->head, n);
151
- spin_unlock_irqrestore(&nh->lock, flags);
169
+ raw_spin_unlock_irqrestore(&nh->lock, flags);
152170 synchronize_rcu();
153171 return ret;
154172 }
155173 EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
156174
175
+int atomic_notifier_call_chain_robust(struct atomic_notifier_head *nh,
176
+ unsigned long val_up, unsigned long val_down, void *v)
177
+{
178
+ unsigned long flags;
179
+ int ret;
180
+
181
+ /*
182
+ * Musn't use RCU; because then the notifier list can
183
+ * change between the up and down traversal.
184
+ */
185
+ raw_spin_lock_irqsave(&nh->lock, flags);
186
+ ret = notifier_call_chain_robust(&nh->head, val_up, val_down, v);
187
+ raw_spin_unlock_irqrestore(&nh->lock, flags);
188
+
189
+ return ret;
190
+}
191
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain_robust);
192
+NOKPROBE_SYMBOL(atomic_notifier_call_chain_robust);
193
+
157194 /**
158
- * __atomic_notifier_call_chain - Call functions in an atomic notifier chain
195
+ * atomic_notifier_call_chain - Call functions in an atomic notifier chain
159196 * @nh: Pointer to head of the atomic notifier chain
160197 * @val: Value passed unmodified to notifier function
161198 * @v: Pointer passed unmodified to notifier function
162
- * @nr_to_call: See the comment for notifier_call_chain.
163
- * @nr_calls: See the comment for notifier_call_chain.
164199 *
165200 * Calls each function in a notifier chain in turn. The functions
166201 * run in an atomic context, so they must not block.
....@@ -173,24 +208,16 @@
173208 * Otherwise the return value is the return value
174209 * of the last notifier function called.
175210 */
176
-int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
177
- unsigned long val, void *v,
178
- int nr_to_call, int *nr_calls)
211
+int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
212
+ unsigned long val, void *v)
179213 {
180214 int ret;
181215
182216 rcu_read_lock();
183
- ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
217
+ ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
184218 rcu_read_unlock();
185
- return ret;
186
-}
187
-EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
188
-NOKPROBE_SYMBOL(__atomic_notifier_call_chain);
189219
190
-int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
191
- unsigned long val, void *v)
192
-{
193
- return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
220
+ return ret;
194221 }
195222 EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
196223 NOKPROBE_SYMBOL(atomic_notifier_call_chain);
....@@ -231,29 +258,6 @@
231258 EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
232259
233260 /**
234
- * blocking_notifier_chain_cond_register - Cond add notifier to a blocking notifier chain
235
- * @nh: Pointer to head of the blocking notifier chain
236
- * @n: New entry in notifier chain
237
- *
238
- * Adds a notifier to a blocking notifier chain, only if not already
239
- * present in the chain.
240
- * Must be called in process context.
241
- *
242
- * Currently always returns zero.
243
- */
244
-int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh,
245
- struct notifier_block *n)
246
-{
247
- int ret;
248
-
249
- down_write(&nh->rwsem);
250
- ret = notifier_chain_cond_register(&nh->head, n);
251
- up_write(&nh->rwsem);
252
- return ret;
253
-}
254
-EXPORT_SYMBOL_GPL(blocking_notifier_chain_cond_register);
255
-
256
-/**
257261 * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
258262 * @nh: Pointer to head of the blocking notifier chain
259263 * @n: Entry to remove from notifier chain
....@@ -283,13 +287,30 @@
283287 }
284288 EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
285289
290
+int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
291
+ unsigned long val_up, unsigned long val_down, void *v)
292
+{
293
+ int ret = NOTIFY_DONE;
294
+
295
+ /*
296
+ * We check the head outside the lock, but if this access is
297
+ * racy then it does not matter what the result of the test
298
+ * is, we re-check the list after having taken the lock anyway:
299
+ */
300
+ if (rcu_access_pointer(nh->head)) {
301
+ down_read(&nh->rwsem);
302
+ ret = notifier_call_chain_robust(&nh->head, val_up, val_down, v);
303
+ up_read(&nh->rwsem);
304
+ }
305
+ return ret;
306
+}
307
+EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_robust);
308
+
286309 /**
287
- * __blocking_notifier_call_chain - Call functions in a blocking notifier chain
310
+ * blocking_notifier_call_chain - Call functions in a blocking notifier chain
288311 * @nh: Pointer to head of the blocking notifier chain
289312 * @val: Value passed unmodified to notifier function
290313 * @v: Pointer passed unmodified to notifier function
291
- * @nr_to_call: See comment for notifier_call_chain.
292
- * @nr_calls: See comment for notifier_call_chain.
293314 *
294315 * Calls each function in a notifier chain in turn. The functions
295316 * run in a process context, so they are allowed to block.
....@@ -301,9 +322,8 @@
301322 * Otherwise the return value is the return value
302323 * of the last notifier function called.
303324 */
304
-int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
305
- unsigned long val, void *v,
306
- int nr_to_call, int *nr_calls)
325
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
326
+ unsigned long val, void *v)
307327 {
308328 int ret = NOTIFY_DONE;
309329
....@@ -314,18 +334,10 @@
314334 */
315335 if (rcu_access_pointer(nh->head)) {
316336 down_read(&nh->rwsem);
317
- ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
318
- nr_calls);
337
+ ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
319338 up_read(&nh->rwsem);
320339 }
321340 return ret;
322
-}
323
-EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
324
-
325
-int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
326
- unsigned long val, void *v)
327
-{
328
- return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
329341 }
330342 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
331343
....@@ -368,13 +380,18 @@
368380 }
369381 EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
370382
383
+int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
384
+ unsigned long val_up, unsigned long val_down, void *v)
385
+{
386
+ return notifier_call_chain_robust(&nh->head, val_up, val_down, v);
387
+}
388
+EXPORT_SYMBOL_GPL(raw_notifier_call_chain_robust);
389
+
371390 /**
372
- * __raw_notifier_call_chain - Call functions in a raw notifier chain
391
+ * raw_notifier_call_chain - Call functions in a raw notifier chain
373392 * @nh: Pointer to head of the raw notifier chain
374393 * @val: Value passed unmodified to notifier function
375394 * @v: Pointer passed unmodified to notifier function
376
- * @nr_to_call: See comment for notifier_call_chain.
377
- * @nr_calls: See comment for notifier_call_chain
378395 *
379396 * Calls each function in a notifier chain in turn. The functions
380397 * run in an undefined context.
....@@ -387,18 +404,10 @@
387404 * Otherwise the return value is the return value
388405 * of the last notifier function called.
389406 */
390
-int __raw_notifier_call_chain(struct raw_notifier_head *nh,
391
- unsigned long val, void *v,
392
- int nr_to_call, int *nr_calls)
393
-{
394
- return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
395
-}
396
-EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
397
-
398407 int raw_notifier_call_chain(struct raw_notifier_head *nh,
399408 unsigned long val, void *v)
400409 {
401
- return __raw_notifier_call_chain(nh, val, v, -1, NULL);
410
+ return notifier_call_chain(&nh->head, val, v, -1, NULL);
402411 }
403412 EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
404413
....@@ -470,12 +479,10 @@
470479 EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
471480
472481 /**
473
- * __srcu_notifier_call_chain - Call functions in an SRCU notifier chain
482
+ * srcu_notifier_call_chain - Call functions in an SRCU notifier chain
474483 * @nh: Pointer to head of the SRCU notifier chain
475484 * @val: Value passed unmodified to notifier function
476485 * @v: Pointer passed unmodified to notifier function
477
- * @nr_to_call: See comment for notifier_call_chain.
478
- * @nr_calls: See comment for notifier_call_chain
479486 *
480487 * Calls each function in a notifier chain in turn. The functions
481488 * run in a process context, so they are allowed to block.
....@@ -487,24 +494,16 @@
487494 * Otherwise the return value is the return value
488495 * of the last notifier function called.
489496 */
490
-int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
491
- unsigned long val, void *v,
492
- int nr_to_call, int *nr_calls)
497
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
498
+ unsigned long val, void *v)
493499 {
494500 int ret;
495501 int idx;
496502
497503 idx = srcu_read_lock(&nh->srcu);
498
- ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
504
+ ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
499505 srcu_read_unlock(&nh->srcu, idx);
500506 return ret;
501
-}
502
-EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
503
-
504
-int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
505
- unsigned long val, void *v)
506
-{
507
- return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
508507 }
509508 EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
510509
....@@ -552,7 +551,6 @@
552551
553552 int register_die_notifier(struct notifier_block *nb)
554553 {
555
- vmalloc_sync_mappings();
556554 return atomic_notifier_chain_register(&die_chain, nb);
557555 }
558556 EXPORT_SYMBOL_GPL(register_die_notifier);