1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fe9d4f57SAlexey Dobriyan #include <linux/kdebug.h>
3fe9d4f57SAlexey Dobriyan #include <linux/kprobes.h>
49984de1aSPaul Gortmaker #include <linux/export.h>
5fe9d4f57SAlexey Dobriyan #include <linux/notifier.h>
6fe9d4f57SAlexey Dobriyan #include <linux/rcupdate.h>
7fe9d4f57SAlexey Dobriyan #include <linux/vmalloc.h>
8c166f23cSAdrian Bunk #include <linux/reboot.h>
9fe9d4f57SAlexey Dobriyan
10*f4708a82SGuilherme G. Piccoli #define CREATE_TRACE_POINTS
11*f4708a82SGuilherme G. Piccoli #include <trace/events/notifier.h>
12*f4708a82SGuilherme G. Piccoli
13fe9d4f57SAlexey Dobriyan /*
14fe9d4f57SAlexey Dobriyan * Notifier list for kernel code which wants to be called
15fe9d4f57SAlexey Dobriyan * at shutdown. This is used to stop any idling DMA operations
16fe9d4f57SAlexey Dobriyan * and the like.
17fe9d4f57SAlexey Dobriyan */
18fe9d4f57SAlexey Dobriyan BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
19fe9d4f57SAlexey Dobriyan
20fe9d4f57SAlexey Dobriyan /*
21fe9d4f57SAlexey Dobriyan * Notifier chain core routines. The exported routines below
22fe9d4f57SAlexey Dobriyan * are layered on top of these, with appropriate locking added.
23fe9d4f57SAlexey Dobriyan */
24fe9d4f57SAlexey Dobriyan
notifier_chain_register(struct notifier_block ** nl,struct notifier_block * n,bool unique_priority)25fe9d4f57SAlexey Dobriyan static int notifier_chain_register(struct notifier_block **nl,
26c82f898dSDmitry Osipenko struct notifier_block *n,
27c82f898dSDmitry Osipenko bool unique_priority)
28fe9d4f57SAlexey Dobriyan {
29fe9d4f57SAlexey Dobriyan while ((*nl) != NULL) {
301a50cb80SXiaoming Ni if (unlikely((*nl) == n)) {
315abb065dSBorislav Petkov WARN(1, "notifier callback %ps already registered",
325abb065dSBorislav Petkov n->notifier_call);
335abb065dSBorislav Petkov return -EEXIST;
341a50cb80SXiaoming Ni }
35fe9d4f57SAlexey Dobriyan if (n->priority > (*nl)->priority)
36fe9d4f57SAlexey Dobriyan break;
37c82f898dSDmitry Osipenko if (n->priority == (*nl)->priority && unique_priority)
38c82f898dSDmitry Osipenko return -EBUSY;
39fe9d4f57SAlexey Dobriyan nl = &((*nl)->next);
40fe9d4f57SAlexey Dobriyan }
41fe9d4f57SAlexey Dobriyan n->next = *nl;
42fe9d4f57SAlexey Dobriyan rcu_assign_pointer(*nl, n);
43*f4708a82SGuilherme G. Piccoli trace_notifier_register((void *)n->notifier_call);
44fe9d4f57SAlexey Dobriyan return 0;
45fe9d4f57SAlexey Dobriyan }
46fe9d4f57SAlexey Dobriyan
notifier_chain_unregister(struct notifier_block ** nl,struct notifier_block * n)47fe9d4f57SAlexey Dobriyan static int notifier_chain_unregister(struct notifier_block **nl,
48fe9d4f57SAlexey Dobriyan struct notifier_block *n)
49fe9d4f57SAlexey Dobriyan {
50fe9d4f57SAlexey Dobriyan while ((*nl) != NULL) {
51fe9d4f57SAlexey Dobriyan if ((*nl) == n) {
52fe9d4f57SAlexey Dobriyan rcu_assign_pointer(*nl, n->next);
53*f4708a82SGuilherme G. Piccoli trace_notifier_unregister((void *)n->notifier_call);
54fe9d4f57SAlexey Dobriyan return 0;
55fe9d4f57SAlexey Dobriyan }
56fe9d4f57SAlexey Dobriyan nl = &((*nl)->next);
57fe9d4f57SAlexey Dobriyan }
58fe9d4f57SAlexey Dobriyan return -ENOENT;
59fe9d4f57SAlexey Dobriyan }
60fe9d4f57SAlexey Dobriyan
61fe9d4f57SAlexey Dobriyan /**
62fe9d4f57SAlexey Dobriyan * notifier_call_chain - Informs the registered notifiers about an event.
63fe9d4f57SAlexey Dobriyan * @nl: Pointer to head of the blocking notifier chain
64fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function
65fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function
66fe9d4f57SAlexey Dobriyan * @nr_to_call: Number of notifier functions to be called. Don't care
67fe9d4f57SAlexey Dobriyan * value of this parameter is -1.
68fe9d4f57SAlexey Dobriyan * @nr_calls: Records the number of notifications sent. Don't care
69fe9d4f57SAlexey Dobriyan * value of this field is NULL.
70f9b4dc92SLukas Bulwahn * Return: notifier_call_chain returns the value returned by the
71fe9d4f57SAlexey Dobriyan * last notifier function called.
72fe9d4f57SAlexey Dobriyan */
notifier_call_chain(struct notifier_block ** nl,unsigned long val,void * v,int nr_to_call,int * nr_calls)73b40a2cb6SMasami Hiramatsu static int notifier_call_chain(struct notifier_block **nl,
74fe9d4f57SAlexey Dobriyan unsigned long val, void *v,
75fe9d4f57SAlexey Dobriyan int nr_to_call, int *nr_calls)
76fe9d4f57SAlexey Dobriyan {
77fe9d4f57SAlexey Dobriyan int ret = NOTIFY_DONE;
78fe9d4f57SAlexey Dobriyan struct notifier_block *nb, *next_nb;
79fe9d4f57SAlexey Dobriyan
80d11c563dSPaul E. McKenney nb = rcu_dereference_raw(*nl);
81fe9d4f57SAlexey Dobriyan
82fe9d4f57SAlexey Dobriyan while (nb && nr_to_call) {
83d11c563dSPaul E. McKenney next_nb = rcu_dereference_raw(nb->next);
841b2439dbSArjan van de Ven
851b2439dbSArjan van de Ven #ifdef CONFIG_DEBUG_NOTIFIERS
86ab7476cfSArjan van de Ven if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {
871b2439dbSArjan van de Ven WARN(1, "Invalid notifier called!");
881b2439dbSArjan van de Ven nb = next_nb;
891b2439dbSArjan van de Ven continue;
901b2439dbSArjan van de Ven }
911b2439dbSArjan van de Ven #endif
92*f4708a82SGuilherme G. Piccoli trace_notifier_run((void *)nb->notifier_call);
93fe9d4f57SAlexey Dobriyan ret = nb->notifier_call(nb, val, v);
94fe9d4f57SAlexey Dobriyan
95fe9d4f57SAlexey Dobriyan if (nr_calls)
96fe9d4f57SAlexey Dobriyan (*nr_calls)++;
97fe9d4f57SAlexey Dobriyan
983e6dadedSViresh Kumar if (ret & NOTIFY_STOP_MASK)
99fe9d4f57SAlexey Dobriyan break;
100fe9d4f57SAlexey Dobriyan nb = next_nb;
101fe9d4f57SAlexey Dobriyan nr_to_call--;
102fe9d4f57SAlexey Dobriyan }
103fe9d4f57SAlexey Dobriyan return ret;
104fe9d4f57SAlexey Dobriyan }
105b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(notifier_call_chain);
106fe9d4f57SAlexey Dobriyan
10770d93298SPeter Zijlstra /**
10870d93298SPeter Zijlstra * notifier_call_chain_robust - Inform the registered notifiers about an event
10970d93298SPeter Zijlstra * and rollback on error.
11070d93298SPeter Zijlstra * @nl: Pointer to head of the blocking notifier chain
11170d93298SPeter Zijlstra * @val_up: Value passed unmodified to the notifier function
11270d93298SPeter Zijlstra * @val_down: Value passed unmodified to the notifier function when recovering
11370d93298SPeter Zijlstra * from an error on @val_up
114f9b4dc92SLukas Bulwahn * @v: Pointer passed unmodified to the notifier function
11570d93298SPeter Zijlstra *
11670d93298SPeter Zijlstra * NOTE: It is important the @nl chain doesn't change between the two
11770d93298SPeter Zijlstra * invocations of notifier_call_chain() such that we visit the
11870d93298SPeter Zijlstra * exact same notifier callbacks; this rules out any RCU usage.
11970d93298SPeter Zijlstra *
120f9b4dc92SLukas Bulwahn * Return: the return value of the @val_up call.
12170d93298SPeter Zijlstra */
notifier_call_chain_robust(struct notifier_block ** nl,unsigned long val_up,unsigned long val_down,void * v)12270d93298SPeter Zijlstra static int notifier_call_chain_robust(struct notifier_block **nl,
12370d93298SPeter Zijlstra unsigned long val_up, unsigned long val_down,
12470d93298SPeter Zijlstra void *v)
12570d93298SPeter Zijlstra {
12670d93298SPeter Zijlstra int ret, nr = 0;
12770d93298SPeter Zijlstra
12870d93298SPeter Zijlstra ret = notifier_call_chain(nl, val_up, v, -1, &nr);
12970d93298SPeter Zijlstra if (ret & NOTIFY_STOP_MASK)
13070d93298SPeter Zijlstra notifier_call_chain(nl, val_down, v, nr-1, NULL);
13170d93298SPeter Zijlstra
13270d93298SPeter Zijlstra return ret;
13370d93298SPeter Zijlstra }
13470d93298SPeter Zijlstra
135fe9d4f57SAlexey Dobriyan /*
136fe9d4f57SAlexey Dobriyan * Atomic notifier chain routines. Registration and unregistration
137fe9d4f57SAlexey Dobriyan * use a spinlock, and call_chain is synchronized by RCU (no locks).
138fe9d4f57SAlexey Dobriyan */
139fe9d4f57SAlexey Dobriyan
140fe9d4f57SAlexey Dobriyan /**
141fe9d4f57SAlexey Dobriyan * atomic_notifier_chain_register - Add notifier to an atomic notifier chain
142fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the atomic notifier chain
143fe9d4f57SAlexey Dobriyan * @n: New entry in notifier chain
144fe9d4f57SAlexey Dobriyan *
145fe9d4f57SAlexey Dobriyan * Adds a notifier to an atomic notifier chain.
146fe9d4f57SAlexey Dobriyan *
1475abb065dSBorislav Petkov * Returns 0 on success, %-EEXIST on error.
148fe9d4f57SAlexey Dobriyan */
atomic_notifier_chain_register(struct atomic_notifier_head * nh,struct notifier_block * n)149fe9d4f57SAlexey Dobriyan int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
150fe9d4f57SAlexey Dobriyan struct notifier_block *n)
151fe9d4f57SAlexey Dobriyan {
152fe9d4f57SAlexey Dobriyan unsigned long flags;
153fe9d4f57SAlexey Dobriyan int ret;
154fe9d4f57SAlexey Dobriyan
155fe9d4f57SAlexey Dobriyan spin_lock_irqsave(&nh->lock, flags);
156c82f898dSDmitry Osipenko ret = notifier_chain_register(&nh->head, n, false);
157fe9d4f57SAlexey Dobriyan spin_unlock_irqrestore(&nh->lock, flags);
158fe9d4f57SAlexey Dobriyan return ret;
159fe9d4f57SAlexey Dobriyan }
160fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_chain_register);
161fe9d4f57SAlexey Dobriyan
162fe9d4f57SAlexey Dobriyan /**
163c82f898dSDmitry Osipenko * atomic_notifier_chain_register_unique_prio - Add notifier to an atomic notifier chain
164c82f898dSDmitry Osipenko * @nh: Pointer to head of the atomic notifier chain
165c82f898dSDmitry Osipenko * @n: New entry in notifier chain
166c82f898dSDmitry Osipenko *
167c82f898dSDmitry Osipenko * Adds a notifier to an atomic notifier chain if there is no other
168c82f898dSDmitry Osipenko * notifier registered using the same priority.
169c82f898dSDmitry Osipenko *
170c82f898dSDmitry Osipenko * Returns 0 on success, %-EEXIST or %-EBUSY on error.
171c82f898dSDmitry Osipenko */
atomic_notifier_chain_register_unique_prio(struct atomic_notifier_head * nh,struct notifier_block * n)172c82f898dSDmitry Osipenko int atomic_notifier_chain_register_unique_prio(struct atomic_notifier_head *nh,
173c82f898dSDmitry Osipenko struct notifier_block *n)
174c82f898dSDmitry Osipenko {
175c82f898dSDmitry Osipenko unsigned long flags;
176c82f898dSDmitry Osipenko int ret;
177c82f898dSDmitry Osipenko
178c82f898dSDmitry Osipenko spin_lock_irqsave(&nh->lock, flags);
179c82f898dSDmitry Osipenko ret = notifier_chain_register(&nh->head, n, true);
180c82f898dSDmitry Osipenko spin_unlock_irqrestore(&nh->lock, flags);
181c82f898dSDmitry Osipenko return ret;
182c82f898dSDmitry Osipenko }
183c82f898dSDmitry Osipenko EXPORT_SYMBOL_GPL(atomic_notifier_chain_register_unique_prio);
184c82f898dSDmitry Osipenko
185c82f898dSDmitry Osipenko /**
186fe9d4f57SAlexey Dobriyan * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain
187fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the atomic notifier chain
188fe9d4f57SAlexey Dobriyan * @n: Entry to remove from notifier chain
189fe9d4f57SAlexey Dobriyan *
190fe9d4f57SAlexey Dobriyan * Removes a notifier from an atomic notifier chain.
191fe9d4f57SAlexey Dobriyan *
192fe9d4f57SAlexey Dobriyan * Returns zero on success or %-ENOENT on failure.
193fe9d4f57SAlexey Dobriyan */
atomic_notifier_chain_unregister(struct atomic_notifier_head * nh,struct notifier_block * n)194fe9d4f57SAlexey Dobriyan int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
195fe9d4f57SAlexey Dobriyan struct notifier_block *n)
196fe9d4f57SAlexey Dobriyan {
197fe9d4f57SAlexey Dobriyan unsigned long flags;
198fe9d4f57SAlexey Dobriyan int ret;
199fe9d4f57SAlexey Dobriyan
200fe9d4f57SAlexey Dobriyan spin_lock_irqsave(&nh->lock, flags);
201fe9d4f57SAlexey Dobriyan ret = notifier_chain_unregister(&nh->head, n);
202fe9d4f57SAlexey Dobriyan spin_unlock_irqrestore(&nh->lock, flags);
203fe9d4f57SAlexey Dobriyan synchronize_rcu();
204fe9d4f57SAlexey Dobriyan return ret;
205fe9d4f57SAlexey Dobriyan }
206fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
207fe9d4f57SAlexey Dobriyan
208fe9d4f57SAlexey Dobriyan /**
20970d93298SPeter Zijlstra * atomic_notifier_call_chain - Call functions in an atomic notifier chain
210fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the atomic notifier chain
211fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function
212fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function
213fe9d4f57SAlexey Dobriyan *
214fe9d4f57SAlexey Dobriyan * Calls each function in a notifier chain in turn. The functions
215fe9d4f57SAlexey Dobriyan * run in an atomic context, so they must not block.
216fe9d4f57SAlexey Dobriyan * This routine uses RCU to synchronize with changes to the chain.
217fe9d4f57SAlexey Dobriyan *
218fe9d4f57SAlexey Dobriyan * If the return value of the notifier can be and'ed
219fe9d4f57SAlexey Dobriyan * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain()
220fe9d4f57SAlexey Dobriyan * will return immediately, with the return value of
221fe9d4f57SAlexey Dobriyan * the notifier function which halted execution.
222fe9d4f57SAlexey Dobriyan * Otherwise the return value is the return value
223fe9d4f57SAlexey Dobriyan * of the last notifier function called.
224fe9d4f57SAlexey Dobriyan */
atomic_notifier_call_chain(struct atomic_notifier_head * nh,unsigned long val,void * v)22570d93298SPeter Zijlstra int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
22670d93298SPeter Zijlstra unsigned long val, void *v)
227fe9d4f57SAlexey Dobriyan {
228fe9d4f57SAlexey Dobriyan int ret;
229fe9d4f57SAlexey Dobriyan
230fe9d4f57SAlexey Dobriyan rcu_read_lock();
23170d93298SPeter Zijlstra ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
232fe9d4f57SAlexey Dobriyan rcu_read_unlock();
233fe9d4f57SAlexey Dobriyan
23470d93298SPeter Zijlstra return ret;
235fe9d4f57SAlexey Dobriyan }
236fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
237b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(atomic_notifier_call_chain);
238fe9d4f57SAlexey Dobriyan
23913dfd97aSDmitry Osipenko /**
24013dfd97aSDmitry Osipenko * atomic_notifier_call_chain_is_empty - Check whether notifier chain is empty
24113dfd97aSDmitry Osipenko * @nh: Pointer to head of the atomic notifier chain
24213dfd97aSDmitry Osipenko *
24313dfd97aSDmitry Osipenko * Checks whether notifier chain is empty.
24413dfd97aSDmitry Osipenko *
24513dfd97aSDmitry Osipenko * Returns true is notifier chain is empty, false otherwise.
24613dfd97aSDmitry Osipenko */
atomic_notifier_call_chain_is_empty(struct atomic_notifier_head * nh)24713dfd97aSDmitry Osipenko bool atomic_notifier_call_chain_is_empty(struct atomic_notifier_head *nh)
24813dfd97aSDmitry Osipenko {
24913dfd97aSDmitry Osipenko return !rcu_access_pointer(nh->head);
25013dfd97aSDmitry Osipenko }
25113dfd97aSDmitry Osipenko
252fe9d4f57SAlexey Dobriyan /*
253fe9d4f57SAlexey Dobriyan * Blocking notifier chain routines. All access to the chain is
254fe9d4f57SAlexey Dobriyan * synchronized by an rwsem.
255fe9d4f57SAlexey Dobriyan */
256fe9d4f57SAlexey Dobriyan
__blocking_notifier_chain_register(struct blocking_notifier_head * nh,struct notifier_block * n,bool unique_priority)257c82f898dSDmitry Osipenko static int __blocking_notifier_chain_register(struct blocking_notifier_head *nh,
258c82f898dSDmitry Osipenko struct notifier_block *n,
259c82f898dSDmitry Osipenko bool unique_priority)
260c82f898dSDmitry Osipenko {
261c82f898dSDmitry Osipenko int ret;
262c82f898dSDmitry Osipenko
263c82f898dSDmitry Osipenko /*
264c82f898dSDmitry Osipenko * This code gets used during boot-up, when task switching is
265c82f898dSDmitry Osipenko * not yet working and interrupts must remain disabled. At
266c82f898dSDmitry Osipenko * such times we must not call down_write().
267c82f898dSDmitry Osipenko */
268c82f898dSDmitry Osipenko if (unlikely(system_state == SYSTEM_BOOTING))
269c82f898dSDmitry Osipenko return notifier_chain_register(&nh->head, n, unique_priority);
270c82f898dSDmitry Osipenko
271c82f898dSDmitry Osipenko down_write(&nh->rwsem);
272c82f898dSDmitry Osipenko ret = notifier_chain_register(&nh->head, n, unique_priority);
273c82f898dSDmitry Osipenko up_write(&nh->rwsem);
274c82f898dSDmitry Osipenko return ret;
275c82f898dSDmitry Osipenko }
276c82f898dSDmitry Osipenko
277fe9d4f57SAlexey Dobriyan /**
278fe9d4f57SAlexey Dobriyan * blocking_notifier_chain_register - Add notifier to a blocking notifier chain
279fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the blocking notifier chain
280fe9d4f57SAlexey Dobriyan * @n: New entry in notifier chain
281fe9d4f57SAlexey Dobriyan *
282fe9d4f57SAlexey Dobriyan * Adds a notifier to a blocking notifier chain.
283fe9d4f57SAlexey Dobriyan * Must be called in process context.
284fe9d4f57SAlexey Dobriyan *
2855abb065dSBorislav Petkov * Returns 0 on success, %-EEXIST on error.
286fe9d4f57SAlexey Dobriyan */
blocking_notifier_chain_register(struct blocking_notifier_head * nh,struct notifier_block * n)287fe9d4f57SAlexey Dobriyan int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
288fe9d4f57SAlexey Dobriyan struct notifier_block *n)
289fe9d4f57SAlexey Dobriyan {
290c82f898dSDmitry Osipenko return __blocking_notifier_chain_register(nh, n, false);
291fe9d4f57SAlexey Dobriyan }
292fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
293fe9d4f57SAlexey Dobriyan
294fe9d4f57SAlexey Dobriyan /**
295c82f898dSDmitry Osipenko * blocking_notifier_chain_register_unique_prio - Add notifier to a blocking notifier chain
296c82f898dSDmitry Osipenko * @nh: Pointer to head of the blocking notifier chain
297c82f898dSDmitry Osipenko * @n: New entry in notifier chain
298c82f898dSDmitry Osipenko *
299c82f898dSDmitry Osipenko * Adds a notifier to an blocking notifier chain if there is no other
300c82f898dSDmitry Osipenko * notifier registered using the same priority.
301c82f898dSDmitry Osipenko *
302c82f898dSDmitry Osipenko * Returns 0 on success, %-EEXIST or %-EBUSY on error.
303c82f898dSDmitry Osipenko */
blocking_notifier_chain_register_unique_prio(struct blocking_notifier_head * nh,struct notifier_block * n)304c82f898dSDmitry Osipenko int blocking_notifier_chain_register_unique_prio(struct blocking_notifier_head *nh,
305c82f898dSDmitry Osipenko struct notifier_block *n)
306c82f898dSDmitry Osipenko {
307c82f898dSDmitry Osipenko return __blocking_notifier_chain_register(nh, n, true);
308c82f898dSDmitry Osipenko }
309c82f898dSDmitry Osipenko EXPORT_SYMBOL_GPL(blocking_notifier_chain_register_unique_prio);
310c82f898dSDmitry Osipenko
311c82f898dSDmitry Osipenko /**
312fe9d4f57SAlexey Dobriyan * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
313fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the blocking notifier chain
314fe9d4f57SAlexey Dobriyan * @n: Entry to remove from notifier chain
315fe9d4f57SAlexey Dobriyan *
316fe9d4f57SAlexey Dobriyan * Removes a notifier from a blocking notifier chain.
317fe9d4f57SAlexey Dobriyan * Must be called from process context.
318fe9d4f57SAlexey Dobriyan *
319fe9d4f57SAlexey Dobriyan * Returns zero on success or %-ENOENT on failure.
320fe9d4f57SAlexey Dobriyan */
blocking_notifier_chain_unregister(struct blocking_notifier_head * nh,struct notifier_block * n)321fe9d4f57SAlexey Dobriyan int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
322fe9d4f57SAlexey Dobriyan struct notifier_block *n)
323fe9d4f57SAlexey Dobriyan {
324fe9d4f57SAlexey Dobriyan int ret;
325fe9d4f57SAlexey Dobriyan
326fe9d4f57SAlexey Dobriyan /*
327fe9d4f57SAlexey Dobriyan * This code gets used during boot-up, when task switching is
328fe9d4f57SAlexey Dobriyan * not yet working and interrupts must remain disabled. At
329fe9d4f57SAlexey Dobriyan * such times we must not call down_write().
330fe9d4f57SAlexey Dobriyan */
331fe9d4f57SAlexey Dobriyan if (unlikely(system_state == SYSTEM_BOOTING))
332fe9d4f57SAlexey Dobriyan return notifier_chain_unregister(&nh->head, n);
333fe9d4f57SAlexey Dobriyan
334fe9d4f57SAlexey Dobriyan down_write(&nh->rwsem);
335fe9d4f57SAlexey Dobriyan ret = notifier_chain_unregister(&nh->head, n);
336fe9d4f57SAlexey Dobriyan up_write(&nh->rwsem);
337fe9d4f57SAlexey Dobriyan return ret;
338fe9d4f57SAlexey Dobriyan }
339fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
340fe9d4f57SAlexey Dobriyan
blocking_notifier_call_chain_robust(struct blocking_notifier_head * nh,unsigned long val_up,unsigned long val_down,void * v)34170d93298SPeter Zijlstra int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
34270d93298SPeter Zijlstra unsigned long val_up, unsigned long val_down, void *v)
34370d93298SPeter Zijlstra {
34470d93298SPeter Zijlstra int ret = NOTIFY_DONE;
34570d93298SPeter Zijlstra
34670d93298SPeter Zijlstra /*
34770d93298SPeter Zijlstra * We check the head outside the lock, but if this access is
34870d93298SPeter Zijlstra * racy then it does not matter what the result of the test
34970d93298SPeter Zijlstra * is, we re-check the list after having taken the lock anyway:
35070d93298SPeter Zijlstra */
35170d93298SPeter Zijlstra if (rcu_access_pointer(nh->head)) {
35270d93298SPeter Zijlstra down_read(&nh->rwsem);
35370d93298SPeter Zijlstra ret = notifier_call_chain_robust(&nh->head, val_up, val_down, v);
35470d93298SPeter Zijlstra up_read(&nh->rwsem);
35570d93298SPeter Zijlstra }
35670d93298SPeter Zijlstra return ret;
35770d93298SPeter Zijlstra }
35870d93298SPeter Zijlstra EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_robust);
35970d93298SPeter Zijlstra
360fe9d4f57SAlexey Dobriyan /**
36170d93298SPeter Zijlstra * blocking_notifier_call_chain - Call functions in a blocking notifier chain
362fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the blocking notifier chain
363fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function
364fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function
365fe9d4f57SAlexey Dobriyan *
366fe9d4f57SAlexey Dobriyan * Calls each function in a notifier chain in turn. The functions
367fe9d4f57SAlexey Dobriyan * run in a process context, so they are allowed to block.
368fe9d4f57SAlexey Dobriyan *
369fe9d4f57SAlexey Dobriyan * If the return value of the notifier can be and'ed
370fe9d4f57SAlexey Dobriyan * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain()
371fe9d4f57SAlexey Dobriyan * will return immediately, with the return value of
372fe9d4f57SAlexey Dobriyan * the notifier function which halted execution.
373fe9d4f57SAlexey Dobriyan * Otherwise the return value is the return value
374fe9d4f57SAlexey Dobriyan * of the last notifier function called.
375fe9d4f57SAlexey Dobriyan */
blocking_notifier_call_chain(struct blocking_notifier_head * nh,unsigned long val,void * v)37670d93298SPeter Zijlstra int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
37770d93298SPeter Zijlstra unsigned long val, void *v)
378fe9d4f57SAlexey Dobriyan {
379fe9d4f57SAlexey Dobriyan int ret = NOTIFY_DONE;
380fe9d4f57SAlexey Dobriyan
381fe9d4f57SAlexey Dobriyan /*
382fe9d4f57SAlexey Dobriyan * We check the head outside the lock, but if this access is
383fe9d4f57SAlexey Dobriyan * racy then it does not matter what the result of the test
384fe9d4f57SAlexey Dobriyan * is, we re-check the list after having taken the lock anyway:
385fe9d4f57SAlexey Dobriyan */
3868857563bSPaul E. McKenney if (rcu_access_pointer(nh->head)) {
387fe9d4f57SAlexey Dobriyan down_read(&nh->rwsem);
38870d93298SPeter Zijlstra ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
389fe9d4f57SAlexey Dobriyan up_read(&nh->rwsem);
390fe9d4f57SAlexey Dobriyan }
391fe9d4f57SAlexey Dobriyan return ret;
392fe9d4f57SAlexey Dobriyan }
393fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
394fe9d4f57SAlexey Dobriyan
395fe9d4f57SAlexey Dobriyan /*
396fe9d4f57SAlexey Dobriyan * Raw notifier chain routines. There is no protection;
397fe9d4f57SAlexey Dobriyan * the caller must provide it. Use at your own risk!
398fe9d4f57SAlexey Dobriyan */
399fe9d4f57SAlexey Dobriyan
400fe9d4f57SAlexey Dobriyan /**
401fe9d4f57SAlexey Dobriyan * raw_notifier_chain_register - Add notifier to a raw notifier chain
402fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the raw notifier chain
403fe9d4f57SAlexey Dobriyan * @n: New entry in notifier chain
404fe9d4f57SAlexey Dobriyan *
405fe9d4f57SAlexey Dobriyan * Adds a notifier to a raw notifier chain.
406fe9d4f57SAlexey Dobriyan * All locking must be provided by the caller.
407fe9d4f57SAlexey Dobriyan *
4085abb065dSBorislav Petkov * Returns 0 on success, %-EEXIST on error.
409fe9d4f57SAlexey Dobriyan */
raw_notifier_chain_register(struct raw_notifier_head * nh,struct notifier_block * n)410fe9d4f57SAlexey Dobriyan int raw_notifier_chain_register(struct raw_notifier_head *nh,
411fe9d4f57SAlexey Dobriyan struct notifier_block *n)
412fe9d4f57SAlexey Dobriyan {
413c82f898dSDmitry Osipenko return notifier_chain_register(&nh->head, n, false);
414fe9d4f57SAlexey Dobriyan }
415fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_chain_register);
416fe9d4f57SAlexey Dobriyan
417fe9d4f57SAlexey Dobriyan /**
418fe9d4f57SAlexey Dobriyan * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain
419fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the raw notifier chain
420fe9d4f57SAlexey Dobriyan * @n: Entry to remove from notifier chain
421fe9d4f57SAlexey Dobriyan *
422fe9d4f57SAlexey Dobriyan * Removes a notifier from a raw notifier chain.
423fe9d4f57SAlexey Dobriyan * All locking must be provided by the caller.
424fe9d4f57SAlexey Dobriyan *
425fe9d4f57SAlexey Dobriyan * Returns zero on success or %-ENOENT on failure.
426fe9d4f57SAlexey Dobriyan */
raw_notifier_chain_unregister(struct raw_notifier_head * nh,struct notifier_block * n)427fe9d4f57SAlexey Dobriyan int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
428fe9d4f57SAlexey Dobriyan struct notifier_block *n)
429fe9d4f57SAlexey Dobriyan {
430fe9d4f57SAlexey Dobriyan return notifier_chain_unregister(&nh->head, n);
431fe9d4f57SAlexey Dobriyan }
432fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
433fe9d4f57SAlexey Dobriyan
raw_notifier_call_chain_robust(struct raw_notifier_head * nh,unsigned long val_up,unsigned long val_down,void * v)43470d93298SPeter Zijlstra int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
43570d93298SPeter Zijlstra unsigned long val_up, unsigned long val_down, void *v)
43670d93298SPeter Zijlstra {
43770d93298SPeter Zijlstra return notifier_call_chain_robust(&nh->head, val_up, val_down, v);
43870d93298SPeter Zijlstra }
43970d93298SPeter Zijlstra EXPORT_SYMBOL_GPL(raw_notifier_call_chain_robust);
44070d93298SPeter Zijlstra
441fe9d4f57SAlexey Dobriyan /**
44270d93298SPeter Zijlstra * raw_notifier_call_chain - Call functions in a raw notifier chain
443fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the raw notifier chain
444fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function
445fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function
446fe9d4f57SAlexey Dobriyan *
447fe9d4f57SAlexey Dobriyan * Calls each function in a notifier chain in turn. The functions
448fe9d4f57SAlexey Dobriyan * run in an undefined context.
449fe9d4f57SAlexey Dobriyan * All locking must be provided by the caller.
450fe9d4f57SAlexey Dobriyan *
451fe9d4f57SAlexey Dobriyan * If the return value of the notifier can be and'ed
452fe9d4f57SAlexey Dobriyan * with %NOTIFY_STOP_MASK then raw_notifier_call_chain()
453fe9d4f57SAlexey Dobriyan * will return immediately, with the return value of
454fe9d4f57SAlexey Dobriyan * the notifier function which halted execution.
455fe9d4f57SAlexey Dobriyan * Otherwise the return value is the return value
456fe9d4f57SAlexey Dobriyan * of the last notifier function called.
457fe9d4f57SAlexey Dobriyan */
raw_notifier_call_chain(struct raw_notifier_head * nh,unsigned long val,void * v)458fe9d4f57SAlexey Dobriyan int raw_notifier_call_chain(struct raw_notifier_head *nh,
459fe9d4f57SAlexey Dobriyan unsigned long val, void *v)
460fe9d4f57SAlexey Dobriyan {
46170d93298SPeter Zijlstra return notifier_call_chain(&nh->head, val, v, -1, NULL);
462fe9d4f57SAlexey Dobriyan }
463fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
464fe9d4f57SAlexey Dobriyan
465fe9d4f57SAlexey Dobriyan /*
466fe9d4f57SAlexey Dobriyan * SRCU notifier chain routines. Registration and unregistration
467fe9d4f57SAlexey Dobriyan * use a mutex, and call_chain is synchronized by SRCU (no locks).
468fe9d4f57SAlexey Dobriyan */
469fe9d4f57SAlexey Dobriyan
470fe9d4f57SAlexey Dobriyan /**
471fe9d4f57SAlexey Dobriyan * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain
472fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the SRCU notifier chain
473fe9d4f57SAlexey Dobriyan * @n: New entry in notifier chain
474fe9d4f57SAlexey Dobriyan *
475fe9d4f57SAlexey Dobriyan * Adds a notifier to an SRCU notifier chain.
476fe9d4f57SAlexey Dobriyan * Must be called in process context.
477fe9d4f57SAlexey Dobriyan *
4785abb065dSBorislav Petkov * Returns 0 on success, %-EEXIST on error.
479fe9d4f57SAlexey Dobriyan */
srcu_notifier_chain_register(struct srcu_notifier_head * nh,struct notifier_block * n)480fe9d4f57SAlexey Dobriyan int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
481fe9d4f57SAlexey Dobriyan struct notifier_block *n)
482fe9d4f57SAlexey Dobriyan {
483fe9d4f57SAlexey Dobriyan int ret;
484fe9d4f57SAlexey Dobriyan
485fe9d4f57SAlexey Dobriyan /*
486fe9d4f57SAlexey Dobriyan * This code gets used during boot-up, when task switching is
487fe9d4f57SAlexey Dobriyan * not yet working and interrupts must remain disabled. At
488fe9d4f57SAlexey Dobriyan * such times we must not call mutex_lock().
489fe9d4f57SAlexey Dobriyan */
490fe9d4f57SAlexey Dobriyan if (unlikely(system_state == SYSTEM_BOOTING))
491c82f898dSDmitry Osipenko return notifier_chain_register(&nh->head, n, false);
492fe9d4f57SAlexey Dobriyan
493fe9d4f57SAlexey Dobriyan mutex_lock(&nh->mutex);
494c82f898dSDmitry Osipenko ret = notifier_chain_register(&nh->head, n, false);
495fe9d4f57SAlexey Dobriyan mutex_unlock(&nh->mutex);
496fe9d4f57SAlexey Dobriyan return ret;
497fe9d4f57SAlexey Dobriyan }
498fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_chain_register);
499fe9d4f57SAlexey Dobriyan
500fe9d4f57SAlexey Dobriyan /**
501fe9d4f57SAlexey Dobriyan * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain
502fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the SRCU notifier chain
503fe9d4f57SAlexey Dobriyan * @n: Entry to remove from notifier chain
504fe9d4f57SAlexey Dobriyan *
505fe9d4f57SAlexey Dobriyan * Removes a notifier from an SRCU notifier chain.
506fe9d4f57SAlexey Dobriyan * Must be called from process context.
507fe9d4f57SAlexey Dobriyan *
508fe9d4f57SAlexey Dobriyan * Returns zero on success or %-ENOENT on failure.
509fe9d4f57SAlexey Dobriyan */
srcu_notifier_chain_unregister(struct srcu_notifier_head * nh,struct notifier_block * n)510fe9d4f57SAlexey Dobriyan int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
511fe9d4f57SAlexey Dobriyan struct notifier_block *n)
512fe9d4f57SAlexey Dobriyan {
513fe9d4f57SAlexey Dobriyan int ret;
514fe9d4f57SAlexey Dobriyan
515fe9d4f57SAlexey Dobriyan /*
516fe9d4f57SAlexey Dobriyan * This code gets used during boot-up, when task switching is
517fe9d4f57SAlexey Dobriyan * not yet working and interrupts must remain disabled. At
518fe9d4f57SAlexey Dobriyan * such times we must not call mutex_lock().
519fe9d4f57SAlexey Dobriyan */
520fe9d4f57SAlexey Dobriyan if (unlikely(system_state == SYSTEM_BOOTING))
521fe9d4f57SAlexey Dobriyan return notifier_chain_unregister(&nh->head, n);
522fe9d4f57SAlexey Dobriyan
523fe9d4f57SAlexey Dobriyan mutex_lock(&nh->mutex);
524fe9d4f57SAlexey Dobriyan ret = notifier_chain_unregister(&nh->head, n);
525fe9d4f57SAlexey Dobriyan mutex_unlock(&nh->mutex);
526fe9d4f57SAlexey Dobriyan synchronize_srcu(&nh->srcu);
527fe9d4f57SAlexey Dobriyan return ret;
528fe9d4f57SAlexey Dobriyan }
529fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
530fe9d4f57SAlexey Dobriyan
531fe9d4f57SAlexey Dobriyan /**
53270d93298SPeter Zijlstra * srcu_notifier_call_chain - Call functions in an SRCU notifier chain
533fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the SRCU notifier chain
534fe9d4f57SAlexey Dobriyan * @val: Value passed unmodified to notifier function
535fe9d4f57SAlexey Dobriyan * @v: Pointer passed unmodified to notifier function
536fe9d4f57SAlexey Dobriyan *
537fe9d4f57SAlexey Dobriyan * Calls each function in a notifier chain in turn. The functions
538fe9d4f57SAlexey Dobriyan * run in a process context, so they are allowed to block.
539fe9d4f57SAlexey Dobriyan *
540fe9d4f57SAlexey Dobriyan * If the return value of the notifier can be and'ed
541fe9d4f57SAlexey Dobriyan * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain()
542fe9d4f57SAlexey Dobriyan * will return immediately, with the return value of
543fe9d4f57SAlexey Dobriyan * the notifier function which halted execution.
544fe9d4f57SAlexey Dobriyan * Otherwise the return value is the return value
545fe9d4f57SAlexey Dobriyan * of the last notifier function called.
546fe9d4f57SAlexey Dobriyan */
srcu_notifier_call_chain(struct srcu_notifier_head * nh,unsigned long val,void * v)54770d93298SPeter Zijlstra int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
54870d93298SPeter Zijlstra unsigned long val, void *v)
549fe9d4f57SAlexey Dobriyan {
550fe9d4f57SAlexey Dobriyan int ret;
551fe9d4f57SAlexey Dobriyan int idx;
552fe9d4f57SAlexey Dobriyan
553fe9d4f57SAlexey Dobriyan idx = srcu_read_lock(&nh->srcu);
55470d93298SPeter Zijlstra ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
555fe9d4f57SAlexey Dobriyan srcu_read_unlock(&nh->srcu, idx);
556fe9d4f57SAlexey Dobriyan return ret;
557fe9d4f57SAlexey Dobriyan }
558fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
559fe9d4f57SAlexey Dobriyan
560fe9d4f57SAlexey Dobriyan /**
561fe9d4f57SAlexey Dobriyan * srcu_init_notifier_head - Initialize an SRCU notifier head
562fe9d4f57SAlexey Dobriyan * @nh: Pointer to head of the srcu notifier chain
563fe9d4f57SAlexey Dobriyan *
564fe9d4f57SAlexey Dobriyan * Unlike other sorts of notifier heads, SRCU notifier heads require
565fe9d4f57SAlexey Dobriyan * dynamic initialization. Be sure to call this routine before
566fe9d4f57SAlexey Dobriyan * calling any of the other SRCU notifier routines for this head.
567fe9d4f57SAlexey Dobriyan *
568fe9d4f57SAlexey Dobriyan * If an SRCU notifier head is deallocated, it must first be cleaned
569fe9d4f57SAlexey Dobriyan * up by calling srcu_cleanup_notifier_head(). Otherwise the head's
570fe9d4f57SAlexey Dobriyan * per-cpu data (used by the SRCU mechanism) will leak.
571fe9d4f57SAlexey Dobriyan */
srcu_init_notifier_head(struct srcu_notifier_head * nh)572fe9d4f57SAlexey Dobriyan void srcu_init_notifier_head(struct srcu_notifier_head *nh)
573fe9d4f57SAlexey Dobriyan {
574fe9d4f57SAlexey Dobriyan mutex_init(&nh->mutex);
575fe9d4f57SAlexey Dobriyan if (init_srcu_struct(&nh->srcu) < 0)
576fe9d4f57SAlexey Dobriyan BUG();
577fe9d4f57SAlexey Dobriyan nh->head = NULL;
578fe9d4f57SAlexey Dobriyan }
579fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_init_notifier_head);
580fe9d4f57SAlexey Dobriyan
581fe9d4f57SAlexey Dobriyan static ATOMIC_NOTIFIER_HEAD(die_chain);
582fe9d4f57SAlexey Dobriyan
notify_die(enum die_val val,const char * str,struct pt_regs * regs,long err,int trap,int sig)583b40a2cb6SMasami Hiramatsu int notrace notify_die(enum die_val val, const char *str,
584fe9d4f57SAlexey Dobriyan struct pt_regs *regs, long err, int trap, int sig)
585fe9d4f57SAlexey Dobriyan {
586fe9d4f57SAlexey Dobriyan struct die_args args = {
587fe9d4f57SAlexey Dobriyan .regs = regs,
588fe9d4f57SAlexey Dobriyan .str = str,
589fe9d4f57SAlexey Dobriyan .err = err,
590fe9d4f57SAlexey Dobriyan .trapnr = trap,
591fe9d4f57SAlexey Dobriyan .signr = sig,
592fe9d4f57SAlexey Dobriyan
593fe9d4f57SAlexey Dobriyan };
5945778077dSLinus Torvalds RCU_LOCKDEP_WARN(!rcu_is_watching(),
595e727c7d7SAndy Lutomirski "notify_die called but RCU thinks we're quiescent");
596fe9d4f57SAlexey Dobriyan return atomic_notifier_call_chain(&die_chain, val, &args);
597fe9d4f57SAlexey Dobriyan }
598b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(notify_die);
599fe9d4f57SAlexey Dobriyan
register_die_notifier(struct notifier_block * nb)600fe9d4f57SAlexey Dobriyan int register_die_notifier(struct notifier_block *nb)
601fe9d4f57SAlexey Dobriyan {
602fe9d4f57SAlexey Dobriyan return atomic_notifier_chain_register(&die_chain, nb);
603fe9d4f57SAlexey Dobriyan }
604fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(register_die_notifier);
605fe9d4f57SAlexey Dobriyan
unregister_die_notifier(struct notifier_block * nb)606fe9d4f57SAlexey Dobriyan int unregister_die_notifier(struct notifier_block *nb)
607fe9d4f57SAlexey Dobriyan {
608fe9d4f57SAlexey Dobriyan return atomic_notifier_chain_unregister(&die_chain, nb);
609fe9d4f57SAlexey Dobriyan }
610fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(unregister_die_notifier);
611