xref: /openbmc/linux/kernel/notifier.c (revision f9b4dc920d35cca8bf85ecce836ee6d23788e7cf)
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 
10fe9d4f57SAlexey Dobriyan /*
11fe9d4f57SAlexey Dobriyan  *	Notifier list for kernel code which wants to be called
12fe9d4f57SAlexey Dobriyan  *	at shutdown. This is used to stop any idling DMA operations
13fe9d4f57SAlexey Dobriyan  *	and the like.
14fe9d4f57SAlexey Dobriyan  */
15fe9d4f57SAlexey Dobriyan BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
16fe9d4f57SAlexey Dobriyan 
17fe9d4f57SAlexey Dobriyan /*
18fe9d4f57SAlexey Dobriyan  *	Notifier chain core routines.  The exported routines below
19fe9d4f57SAlexey Dobriyan  *	are layered on top of these, with appropriate locking added.
20fe9d4f57SAlexey Dobriyan  */
21fe9d4f57SAlexey Dobriyan 
22fe9d4f57SAlexey Dobriyan static int notifier_chain_register(struct notifier_block **nl,
23c82f898dSDmitry Osipenko 				   struct notifier_block *n,
24c82f898dSDmitry Osipenko 				   bool unique_priority)
25fe9d4f57SAlexey Dobriyan {
26fe9d4f57SAlexey Dobriyan 	while ((*nl) != NULL) {
271a50cb80SXiaoming Ni 		if (unlikely((*nl) == n)) {
285abb065dSBorislav Petkov 			WARN(1, "notifier callback %ps already registered",
295abb065dSBorislav Petkov 			     n->notifier_call);
305abb065dSBorislav Petkov 			return -EEXIST;
311a50cb80SXiaoming Ni 		}
32fe9d4f57SAlexey Dobriyan 		if (n->priority > (*nl)->priority)
33fe9d4f57SAlexey Dobriyan 			break;
34c82f898dSDmitry Osipenko 		if (n->priority == (*nl)->priority && unique_priority)
35c82f898dSDmitry Osipenko 			return -EBUSY;
36fe9d4f57SAlexey Dobriyan 		nl = &((*nl)->next);
37fe9d4f57SAlexey Dobriyan 	}
38fe9d4f57SAlexey Dobriyan 	n->next = *nl;
39fe9d4f57SAlexey Dobriyan 	rcu_assign_pointer(*nl, n);
40fe9d4f57SAlexey Dobriyan 	return 0;
41fe9d4f57SAlexey Dobriyan }
42fe9d4f57SAlexey Dobriyan 
43fe9d4f57SAlexey Dobriyan static int notifier_chain_unregister(struct notifier_block **nl,
44fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
45fe9d4f57SAlexey Dobriyan {
46fe9d4f57SAlexey Dobriyan 	while ((*nl) != NULL) {
47fe9d4f57SAlexey Dobriyan 		if ((*nl) == n) {
48fe9d4f57SAlexey Dobriyan 			rcu_assign_pointer(*nl, n->next);
49fe9d4f57SAlexey Dobriyan 			return 0;
50fe9d4f57SAlexey Dobriyan 		}
51fe9d4f57SAlexey Dobriyan 		nl = &((*nl)->next);
52fe9d4f57SAlexey Dobriyan 	}
53fe9d4f57SAlexey Dobriyan 	return -ENOENT;
54fe9d4f57SAlexey Dobriyan }
55fe9d4f57SAlexey Dobriyan 
56fe9d4f57SAlexey Dobriyan /**
57fe9d4f57SAlexey Dobriyan  * notifier_call_chain - Informs the registered notifiers about an event.
58fe9d4f57SAlexey Dobriyan  *	@nl:		Pointer to head of the blocking notifier chain
59fe9d4f57SAlexey Dobriyan  *	@val:		Value passed unmodified to notifier function
60fe9d4f57SAlexey Dobriyan  *	@v:		Pointer passed unmodified to notifier function
61fe9d4f57SAlexey Dobriyan  *	@nr_to_call:	Number of notifier functions to be called. Don't care
62fe9d4f57SAlexey Dobriyan  *			value of this parameter is -1.
63fe9d4f57SAlexey Dobriyan  *	@nr_calls:	Records the number of notifications sent. Don't care
64fe9d4f57SAlexey Dobriyan  *			value of this field is NULL.
65*f9b4dc92SLukas Bulwahn  *	Return:		notifier_call_chain returns the value returned by the
66fe9d4f57SAlexey Dobriyan  *			last notifier function called.
67fe9d4f57SAlexey Dobriyan  */
68b40a2cb6SMasami Hiramatsu static int notifier_call_chain(struct notifier_block **nl,
69fe9d4f57SAlexey Dobriyan 			       unsigned long val, void *v,
70fe9d4f57SAlexey Dobriyan 			       int nr_to_call, int *nr_calls)
71fe9d4f57SAlexey Dobriyan {
72fe9d4f57SAlexey Dobriyan 	int ret = NOTIFY_DONE;
73fe9d4f57SAlexey Dobriyan 	struct notifier_block *nb, *next_nb;
74fe9d4f57SAlexey Dobriyan 
75d11c563dSPaul E. McKenney 	nb = rcu_dereference_raw(*nl);
76fe9d4f57SAlexey Dobriyan 
77fe9d4f57SAlexey Dobriyan 	while (nb && nr_to_call) {
78d11c563dSPaul E. McKenney 		next_nb = rcu_dereference_raw(nb->next);
791b2439dbSArjan van de Ven 
801b2439dbSArjan van de Ven #ifdef CONFIG_DEBUG_NOTIFIERS
81ab7476cfSArjan van de Ven 		if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {
821b2439dbSArjan van de Ven 			WARN(1, "Invalid notifier called!");
831b2439dbSArjan van de Ven 			nb = next_nb;
841b2439dbSArjan van de Ven 			continue;
851b2439dbSArjan van de Ven 		}
861b2439dbSArjan van de Ven #endif
87fe9d4f57SAlexey Dobriyan 		ret = nb->notifier_call(nb, val, v);
88fe9d4f57SAlexey Dobriyan 
89fe9d4f57SAlexey Dobriyan 		if (nr_calls)
90fe9d4f57SAlexey Dobriyan 			(*nr_calls)++;
91fe9d4f57SAlexey Dobriyan 
923e6dadedSViresh Kumar 		if (ret & NOTIFY_STOP_MASK)
93fe9d4f57SAlexey Dobriyan 			break;
94fe9d4f57SAlexey Dobriyan 		nb = next_nb;
95fe9d4f57SAlexey Dobriyan 		nr_to_call--;
96fe9d4f57SAlexey Dobriyan 	}
97fe9d4f57SAlexey Dobriyan 	return ret;
98fe9d4f57SAlexey Dobriyan }
99b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(notifier_call_chain);
100fe9d4f57SAlexey Dobriyan 
10170d93298SPeter Zijlstra /**
10270d93298SPeter Zijlstra  * notifier_call_chain_robust - Inform the registered notifiers about an event
10370d93298SPeter Zijlstra  *                              and rollback on error.
10470d93298SPeter Zijlstra  * @nl:		Pointer to head of the blocking notifier chain
10570d93298SPeter Zijlstra  * @val_up:	Value passed unmodified to the notifier function
10670d93298SPeter Zijlstra  * @val_down:	Value passed unmodified to the notifier function when recovering
10770d93298SPeter Zijlstra  *              from an error on @val_up
108*f9b4dc92SLukas Bulwahn  * @v:		Pointer passed unmodified to the notifier function
10970d93298SPeter Zijlstra  *
11070d93298SPeter Zijlstra  * NOTE:	It is important the @nl chain doesn't change between the two
11170d93298SPeter Zijlstra  *		invocations of notifier_call_chain() such that we visit the
11270d93298SPeter Zijlstra  *		exact same notifier callbacks; this rules out any RCU usage.
11370d93298SPeter Zijlstra  *
114*f9b4dc92SLukas Bulwahn  * Return:	the return value of the @val_up call.
11570d93298SPeter Zijlstra  */
11670d93298SPeter Zijlstra static int notifier_call_chain_robust(struct notifier_block **nl,
11770d93298SPeter Zijlstra 				     unsigned long val_up, unsigned long val_down,
11870d93298SPeter Zijlstra 				     void *v)
11970d93298SPeter Zijlstra {
12070d93298SPeter Zijlstra 	int ret, nr = 0;
12170d93298SPeter Zijlstra 
12270d93298SPeter Zijlstra 	ret = notifier_call_chain(nl, val_up, v, -1, &nr);
12370d93298SPeter Zijlstra 	if (ret & NOTIFY_STOP_MASK)
12470d93298SPeter Zijlstra 		notifier_call_chain(nl, val_down, v, nr-1, NULL);
12570d93298SPeter Zijlstra 
12670d93298SPeter Zijlstra 	return ret;
12770d93298SPeter Zijlstra }
12870d93298SPeter Zijlstra 
129fe9d4f57SAlexey Dobriyan /*
130fe9d4f57SAlexey Dobriyan  *	Atomic notifier chain routines.  Registration and unregistration
131fe9d4f57SAlexey Dobriyan  *	use a spinlock, and call_chain is synchronized by RCU (no locks).
132fe9d4f57SAlexey Dobriyan  */
133fe9d4f57SAlexey Dobriyan 
134fe9d4f57SAlexey Dobriyan /**
135fe9d4f57SAlexey Dobriyan  *	atomic_notifier_chain_register - Add notifier to an atomic notifier chain
136fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the atomic notifier chain
137fe9d4f57SAlexey Dobriyan  *	@n: New entry in notifier chain
138fe9d4f57SAlexey Dobriyan  *
139fe9d4f57SAlexey Dobriyan  *	Adds a notifier to an atomic notifier chain.
140fe9d4f57SAlexey Dobriyan  *
1415abb065dSBorislav Petkov  *	Returns 0 on success, %-EEXIST on error.
142fe9d4f57SAlexey Dobriyan  */
143fe9d4f57SAlexey Dobriyan int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
144fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
145fe9d4f57SAlexey Dobriyan {
146fe9d4f57SAlexey Dobriyan 	unsigned long flags;
147fe9d4f57SAlexey Dobriyan 	int ret;
148fe9d4f57SAlexey Dobriyan 
149fe9d4f57SAlexey Dobriyan 	spin_lock_irqsave(&nh->lock, flags);
150c82f898dSDmitry Osipenko 	ret = notifier_chain_register(&nh->head, n, false);
151fe9d4f57SAlexey Dobriyan 	spin_unlock_irqrestore(&nh->lock, flags);
152fe9d4f57SAlexey Dobriyan 	return ret;
153fe9d4f57SAlexey Dobriyan }
154fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_chain_register);
155fe9d4f57SAlexey Dobriyan 
156fe9d4f57SAlexey Dobriyan /**
157c82f898dSDmitry Osipenko  *	atomic_notifier_chain_register_unique_prio - Add notifier to an atomic notifier chain
158c82f898dSDmitry Osipenko  *	@nh: Pointer to head of the atomic notifier chain
159c82f898dSDmitry Osipenko  *	@n: New entry in notifier chain
160c82f898dSDmitry Osipenko  *
161c82f898dSDmitry Osipenko  *	Adds a notifier to an atomic notifier chain if there is no other
162c82f898dSDmitry Osipenko  *	notifier registered using the same priority.
163c82f898dSDmitry Osipenko  *
164c82f898dSDmitry Osipenko  *	Returns 0 on success, %-EEXIST or %-EBUSY on error.
165c82f898dSDmitry Osipenko  */
166c82f898dSDmitry Osipenko int atomic_notifier_chain_register_unique_prio(struct atomic_notifier_head *nh,
167c82f898dSDmitry Osipenko 					       struct notifier_block *n)
168c82f898dSDmitry Osipenko {
169c82f898dSDmitry Osipenko 	unsigned long flags;
170c82f898dSDmitry Osipenko 	int ret;
171c82f898dSDmitry Osipenko 
172c82f898dSDmitry Osipenko 	spin_lock_irqsave(&nh->lock, flags);
173c82f898dSDmitry Osipenko 	ret = notifier_chain_register(&nh->head, n, true);
174c82f898dSDmitry Osipenko 	spin_unlock_irqrestore(&nh->lock, flags);
175c82f898dSDmitry Osipenko 	return ret;
176c82f898dSDmitry Osipenko }
177c82f898dSDmitry Osipenko EXPORT_SYMBOL_GPL(atomic_notifier_chain_register_unique_prio);
178c82f898dSDmitry Osipenko 
179c82f898dSDmitry Osipenko /**
180fe9d4f57SAlexey Dobriyan  *	atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain
181fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the atomic notifier chain
182fe9d4f57SAlexey Dobriyan  *	@n: Entry to remove from notifier chain
183fe9d4f57SAlexey Dobriyan  *
184fe9d4f57SAlexey Dobriyan  *	Removes a notifier from an atomic notifier chain.
185fe9d4f57SAlexey Dobriyan  *
186fe9d4f57SAlexey Dobriyan  *	Returns zero on success or %-ENOENT on failure.
187fe9d4f57SAlexey Dobriyan  */
188fe9d4f57SAlexey Dobriyan int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
189fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
190fe9d4f57SAlexey Dobriyan {
191fe9d4f57SAlexey Dobriyan 	unsigned long flags;
192fe9d4f57SAlexey Dobriyan 	int ret;
193fe9d4f57SAlexey Dobriyan 
194fe9d4f57SAlexey Dobriyan 	spin_lock_irqsave(&nh->lock, flags);
195fe9d4f57SAlexey Dobriyan 	ret = notifier_chain_unregister(&nh->head, n);
196fe9d4f57SAlexey Dobriyan 	spin_unlock_irqrestore(&nh->lock, flags);
197fe9d4f57SAlexey Dobriyan 	synchronize_rcu();
198fe9d4f57SAlexey Dobriyan 	return ret;
199fe9d4f57SAlexey Dobriyan }
200fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
201fe9d4f57SAlexey Dobriyan 
202fe9d4f57SAlexey Dobriyan /**
20370d93298SPeter Zijlstra  *	atomic_notifier_call_chain - Call functions in an atomic notifier chain
204fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the atomic notifier chain
205fe9d4f57SAlexey Dobriyan  *	@val: Value passed unmodified to notifier function
206fe9d4f57SAlexey Dobriyan  *	@v: Pointer passed unmodified to notifier function
207fe9d4f57SAlexey Dobriyan  *
208fe9d4f57SAlexey Dobriyan  *	Calls each function in a notifier chain in turn.  The functions
209fe9d4f57SAlexey Dobriyan  *	run in an atomic context, so they must not block.
210fe9d4f57SAlexey Dobriyan  *	This routine uses RCU to synchronize with changes to the chain.
211fe9d4f57SAlexey Dobriyan  *
212fe9d4f57SAlexey Dobriyan  *	If the return value of the notifier can be and'ed
213fe9d4f57SAlexey Dobriyan  *	with %NOTIFY_STOP_MASK then atomic_notifier_call_chain()
214fe9d4f57SAlexey Dobriyan  *	will return immediately, with the return value of
215fe9d4f57SAlexey Dobriyan  *	the notifier function which halted execution.
216fe9d4f57SAlexey Dobriyan  *	Otherwise the return value is the return value
217fe9d4f57SAlexey Dobriyan  *	of the last notifier function called.
218fe9d4f57SAlexey Dobriyan  */
21970d93298SPeter Zijlstra int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
22070d93298SPeter Zijlstra 			       unsigned long val, void *v)
221fe9d4f57SAlexey Dobriyan {
222fe9d4f57SAlexey Dobriyan 	int ret;
223fe9d4f57SAlexey Dobriyan 
224fe9d4f57SAlexey Dobriyan 	rcu_read_lock();
22570d93298SPeter Zijlstra 	ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
226fe9d4f57SAlexey Dobriyan 	rcu_read_unlock();
227fe9d4f57SAlexey Dobriyan 
22870d93298SPeter Zijlstra 	return ret;
229fe9d4f57SAlexey Dobriyan }
230fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
231b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(atomic_notifier_call_chain);
232fe9d4f57SAlexey Dobriyan 
23313dfd97aSDmitry Osipenko /**
23413dfd97aSDmitry Osipenko  *	atomic_notifier_call_chain_is_empty - Check whether notifier chain is empty
23513dfd97aSDmitry Osipenko  *	@nh: Pointer to head of the atomic notifier chain
23613dfd97aSDmitry Osipenko  *
23713dfd97aSDmitry Osipenko  *	Checks whether notifier chain is empty.
23813dfd97aSDmitry Osipenko  *
23913dfd97aSDmitry Osipenko  *	Returns true is notifier chain is empty, false otherwise.
24013dfd97aSDmitry Osipenko  */
24113dfd97aSDmitry Osipenko bool atomic_notifier_call_chain_is_empty(struct atomic_notifier_head *nh)
24213dfd97aSDmitry Osipenko {
24313dfd97aSDmitry Osipenko 	return !rcu_access_pointer(nh->head);
24413dfd97aSDmitry Osipenko }
24513dfd97aSDmitry Osipenko 
246fe9d4f57SAlexey Dobriyan /*
247fe9d4f57SAlexey Dobriyan  *	Blocking notifier chain routines.  All access to the chain is
248fe9d4f57SAlexey Dobriyan  *	synchronized by an rwsem.
249fe9d4f57SAlexey Dobriyan  */
250fe9d4f57SAlexey Dobriyan 
251c82f898dSDmitry Osipenko static int __blocking_notifier_chain_register(struct blocking_notifier_head *nh,
252c82f898dSDmitry Osipenko 					      struct notifier_block *n,
253c82f898dSDmitry Osipenko 					      bool unique_priority)
254c82f898dSDmitry Osipenko {
255c82f898dSDmitry Osipenko 	int ret;
256c82f898dSDmitry Osipenko 
257c82f898dSDmitry Osipenko 	/*
258c82f898dSDmitry Osipenko 	 * This code gets used during boot-up, when task switching is
259c82f898dSDmitry Osipenko 	 * not yet working and interrupts must remain disabled.  At
260c82f898dSDmitry Osipenko 	 * such times we must not call down_write().
261c82f898dSDmitry Osipenko 	 */
262c82f898dSDmitry Osipenko 	if (unlikely(system_state == SYSTEM_BOOTING))
263c82f898dSDmitry Osipenko 		return notifier_chain_register(&nh->head, n, unique_priority);
264c82f898dSDmitry Osipenko 
265c82f898dSDmitry Osipenko 	down_write(&nh->rwsem);
266c82f898dSDmitry Osipenko 	ret = notifier_chain_register(&nh->head, n, unique_priority);
267c82f898dSDmitry Osipenko 	up_write(&nh->rwsem);
268c82f898dSDmitry Osipenko 	return ret;
269c82f898dSDmitry Osipenko }
270c82f898dSDmitry Osipenko 
271fe9d4f57SAlexey Dobriyan /**
272fe9d4f57SAlexey Dobriyan  *	blocking_notifier_chain_register - Add notifier to a blocking notifier chain
273fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the blocking notifier chain
274fe9d4f57SAlexey Dobriyan  *	@n: New entry in notifier chain
275fe9d4f57SAlexey Dobriyan  *
276fe9d4f57SAlexey Dobriyan  *	Adds a notifier to a blocking notifier chain.
277fe9d4f57SAlexey Dobriyan  *	Must be called in process context.
278fe9d4f57SAlexey Dobriyan  *
2795abb065dSBorislav Petkov  *	Returns 0 on success, %-EEXIST on error.
280fe9d4f57SAlexey Dobriyan  */
281fe9d4f57SAlexey Dobriyan int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
282fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
283fe9d4f57SAlexey Dobriyan {
284c82f898dSDmitry Osipenko 	return __blocking_notifier_chain_register(nh, n, false);
285fe9d4f57SAlexey Dobriyan }
286fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
287fe9d4f57SAlexey Dobriyan 
288fe9d4f57SAlexey Dobriyan /**
289c82f898dSDmitry Osipenko  *	blocking_notifier_chain_register_unique_prio - Add notifier to a blocking notifier chain
290c82f898dSDmitry Osipenko  *	@nh: Pointer to head of the blocking notifier chain
291c82f898dSDmitry Osipenko  *	@n: New entry in notifier chain
292c82f898dSDmitry Osipenko  *
293c82f898dSDmitry Osipenko  *	Adds a notifier to an blocking notifier chain if there is no other
294c82f898dSDmitry Osipenko  *	notifier registered using the same priority.
295c82f898dSDmitry Osipenko  *
296c82f898dSDmitry Osipenko  *	Returns 0 on success, %-EEXIST or %-EBUSY on error.
297c82f898dSDmitry Osipenko  */
298c82f898dSDmitry Osipenko int blocking_notifier_chain_register_unique_prio(struct blocking_notifier_head *nh,
299c82f898dSDmitry Osipenko 						 struct notifier_block *n)
300c82f898dSDmitry Osipenko {
301c82f898dSDmitry Osipenko 	return __blocking_notifier_chain_register(nh, n, true);
302c82f898dSDmitry Osipenko }
303c82f898dSDmitry Osipenko EXPORT_SYMBOL_GPL(blocking_notifier_chain_register_unique_prio);
304c82f898dSDmitry Osipenko 
305c82f898dSDmitry Osipenko /**
306fe9d4f57SAlexey Dobriyan  *	blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
307fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the blocking notifier chain
308fe9d4f57SAlexey Dobriyan  *	@n: Entry to remove from notifier chain
309fe9d4f57SAlexey Dobriyan  *
310fe9d4f57SAlexey Dobriyan  *	Removes a notifier from a blocking notifier chain.
311fe9d4f57SAlexey Dobriyan  *	Must be called from process context.
312fe9d4f57SAlexey Dobriyan  *
313fe9d4f57SAlexey Dobriyan  *	Returns zero on success or %-ENOENT on failure.
314fe9d4f57SAlexey Dobriyan  */
315fe9d4f57SAlexey Dobriyan int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
316fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
317fe9d4f57SAlexey Dobriyan {
318fe9d4f57SAlexey Dobriyan 	int ret;
319fe9d4f57SAlexey Dobriyan 
320fe9d4f57SAlexey Dobriyan 	/*
321fe9d4f57SAlexey Dobriyan 	 * This code gets used during boot-up, when task switching is
322fe9d4f57SAlexey Dobriyan 	 * not yet working and interrupts must remain disabled.  At
323fe9d4f57SAlexey Dobriyan 	 * such times we must not call down_write().
324fe9d4f57SAlexey Dobriyan 	 */
325fe9d4f57SAlexey Dobriyan 	if (unlikely(system_state == SYSTEM_BOOTING))
326fe9d4f57SAlexey Dobriyan 		return notifier_chain_unregister(&nh->head, n);
327fe9d4f57SAlexey Dobriyan 
328fe9d4f57SAlexey Dobriyan 	down_write(&nh->rwsem);
329fe9d4f57SAlexey Dobriyan 	ret = notifier_chain_unregister(&nh->head, n);
330fe9d4f57SAlexey Dobriyan 	up_write(&nh->rwsem);
331fe9d4f57SAlexey Dobriyan 	return ret;
332fe9d4f57SAlexey Dobriyan }
333fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
334fe9d4f57SAlexey Dobriyan 
33570d93298SPeter Zijlstra int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
33670d93298SPeter Zijlstra 		unsigned long val_up, unsigned long val_down, void *v)
33770d93298SPeter Zijlstra {
33870d93298SPeter Zijlstra 	int ret = NOTIFY_DONE;
33970d93298SPeter Zijlstra 
34070d93298SPeter Zijlstra 	/*
34170d93298SPeter Zijlstra 	 * We check the head outside the lock, but if this access is
34270d93298SPeter Zijlstra 	 * racy then it does not matter what the result of the test
34370d93298SPeter Zijlstra 	 * is, we re-check the list after having taken the lock anyway:
34470d93298SPeter Zijlstra 	 */
34570d93298SPeter Zijlstra 	if (rcu_access_pointer(nh->head)) {
34670d93298SPeter Zijlstra 		down_read(&nh->rwsem);
34770d93298SPeter Zijlstra 		ret = notifier_call_chain_robust(&nh->head, val_up, val_down, v);
34870d93298SPeter Zijlstra 		up_read(&nh->rwsem);
34970d93298SPeter Zijlstra 	}
35070d93298SPeter Zijlstra 	return ret;
35170d93298SPeter Zijlstra }
35270d93298SPeter Zijlstra EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_robust);
35370d93298SPeter Zijlstra 
354fe9d4f57SAlexey Dobriyan /**
35570d93298SPeter Zijlstra  *	blocking_notifier_call_chain - Call functions in a blocking notifier chain
356fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the blocking notifier chain
357fe9d4f57SAlexey Dobriyan  *	@val: Value passed unmodified to notifier function
358fe9d4f57SAlexey Dobriyan  *	@v: Pointer passed unmodified to notifier function
359fe9d4f57SAlexey Dobriyan  *
360fe9d4f57SAlexey Dobriyan  *	Calls each function in a notifier chain in turn.  The functions
361fe9d4f57SAlexey Dobriyan  *	run in a process context, so they are allowed to block.
362fe9d4f57SAlexey Dobriyan  *
363fe9d4f57SAlexey Dobriyan  *	If the return value of the notifier can be and'ed
364fe9d4f57SAlexey Dobriyan  *	with %NOTIFY_STOP_MASK then blocking_notifier_call_chain()
365fe9d4f57SAlexey Dobriyan  *	will return immediately, with the return value of
366fe9d4f57SAlexey Dobriyan  *	the notifier function which halted execution.
367fe9d4f57SAlexey Dobriyan  *	Otherwise the return value is the return value
368fe9d4f57SAlexey Dobriyan  *	of the last notifier function called.
369fe9d4f57SAlexey Dobriyan  */
37070d93298SPeter Zijlstra int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
37170d93298SPeter Zijlstra 		unsigned long val, void *v)
372fe9d4f57SAlexey Dobriyan {
373fe9d4f57SAlexey Dobriyan 	int ret = NOTIFY_DONE;
374fe9d4f57SAlexey Dobriyan 
375fe9d4f57SAlexey Dobriyan 	/*
376fe9d4f57SAlexey Dobriyan 	 * We check the head outside the lock, but if this access is
377fe9d4f57SAlexey Dobriyan 	 * racy then it does not matter what the result of the test
378fe9d4f57SAlexey Dobriyan 	 * is, we re-check the list after having taken the lock anyway:
379fe9d4f57SAlexey Dobriyan 	 */
3808857563bSPaul E. McKenney 	if (rcu_access_pointer(nh->head)) {
381fe9d4f57SAlexey Dobriyan 		down_read(&nh->rwsem);
38270d93298SPeter Zijlstra 		ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
383fe9d4f57SAlexey Dobriyan 		up_read(&nh->rwsem);
384fe9d4f57SAlexey Dobriyan 	}
385fe9d4f57SAlexey Dobriyan 	return ret;
386fe9d4f57SAlexey Dobriyan }
387fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
388fe9d4f57SAlexey Dobriyan 
389fe9d4f57SAlexey Dobriyan /*
390fe9d4f57SAlexey Dobriyan  *	Raw notifier chain routines.  There is no protection;
391fe9d4f57SAlexey Dobriyan  *	the caller must provide it.  Use at your own risk!
392fe9d4f57SAlexey Dobriyan  */
393fe9d4f57SAlexey Dobriyan 
394fe9d4f57SAlexey Dobriyan /**
395fe9d4f57SAlexey Dobriyan  *	raw_notifier_chain_register - Add notifier to a raw notifier chain
396fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the raw notifier chain
397fe9d4f57SAlexey Dobriyan  *	@n: New entry in notifier chain
398fe9d4f57SAlexey Dobriyan  *
399fe9d4f57SAlexey Dobriyan  *	Adds a notifier to a raw notifier chain.
400fe9d4f57SAlexey Dobriyan  *	All locking must be provided by the caller.
401fe9d4f57SAlexey Dobriyan  *
4025abb065dSBorislav Petkov  *	Returns 0 on success, %-EEXIST on error.
403fe9d4f57SAlexey Dobriyan  */
404fe9d4f57SAlexey Dobriyan int raw_notifier_chain_register(struct raw_notifier_head *nh,
405fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
406fe9d4f57SAlexey Dobriyan {
407c82f898dSDmitry Osipenko 	return notifier_chain_register(&nh->head, n, false);
408fe9d4f57SAlexey Dobriyan }
409fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_chain_register);
410fe9d4f57SAlexey Dobriyan 
411fe9d4f57SAlexey Dobriyan /**
412fe9d4f57SAlexey Dobriyan  *	raw_notifier_chain_unregister - Remove notifier from a raw notifier chain
413fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the raw notifier chain
414fe9d4f57SAlexey Dobriyan  *	@n: Entry to remove from notifier chain
415fe9d4f57SAlexey Dobriyan  *
416fe9d4f57SAlexey Dobriyan  *	Removes a notifier from a raw notifier chain.
417fe9d4f57SAlexey Dobriyan  *	All locking must be provided by the caller.
418fe9d4f57SAlexey Dobriyan  *
419fe9d4f57SAlexey Dobriyan  *	Returns zero on success or %-ENOENT on failure.
420fe9d4f57SAlexey Dobriyan  */
421fe9d4f57SAlexey Dobriyan int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
422fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
423fe9d4f57SAlexey Dobriyan {
424fe9d4f57SAlexey Dobriyan 	return notifier_chain_unregister(&nh->head, n);
425fe9d4f57SAlexey Dobriyan }
426fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
427fe9d4f57SAlexey Dobriyan 
42870d93298SPeter Zijlstra int raw_notifier_call_chain_robust(struct raw_notifier_head *nh,
42970d93298SPeter Zijlstra 		unsigned long val_up, unsigned long val_down, void *v)
43070d93298SPeter Zijlstra {
43170d93298SPeter Zijlstra 	return notifier_call_chain_robust(&nh->head, val_up, val_down, v);
43270d93298SPeter Zijlstra }
43370d93298SPeter Zijlstra EXPORT_SYMBOL_GPL(raw_notifier_call_chain_robust);
43470d93298SPeter Zijlstra 
435fe9d4f57SAlexey Dobriyan /**
43670d93298SPeter Zijlstra  *	raw_notifier_call_chain - Call functions in a raw notifier chain
437fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the raw notifier chain
438fe9d4f57SAlexey Dobriyan  *	@val: Value passed unmodified to notifier function
439fe9d4f57SAlexey Dobriyan  *	@v: Pointer passed unmodified to notifier function
440fe9d4f57SAlexey Dobriyan  *
441fe9d4f57SAlexey Dobriyan  *	Calls each function in a notifier chain in turn.  The functions
442fe9d4f57SAlexey Dobriyan  *	run in an undefined context.
443fe9d4f57SAlexey Dobriyan  *	All locking must be provided by the caller.
444fe9d4f57SAlexey Dobriyan  *
445fe9d4f57SAlexey Dobriyan  *	If the return value of the notifier can be and'ed
446fe9d4f57SAlexey Dobriyan  *	with %NOTIFY_STOP_MASK then raw_notifier_call_chain()
447fe9d4f57SAlexey Dobriyan  *	will return immediately, with the return value of
448fe9d4f57SAlexey Dobriyan  *	the notifier function which halted execution.
449fe9d4f57SAlexey Dobriyan  *	Otherwise the return value is the return value
450fe9d4f57SAlexey Dobriyan  *	of the last notifier function called.
451fe9d4f57SAlexey Dobriyan  */
452fe9d4f57SAlexey Dobriyan int raw_notifier_call_chain(struct raw_notifier_head *nh,
453fe9d4f57SAlexey Dobriyan 		unsigned long val, void *v)
454fe9d4f57SAlexey Dobriyan {
45570d93298SPeter Zijlstra 	return notifier_call_chain(&nh->head, val, v, -1, NULL);
456fe9d4f57SAlexey Dobriyan }
457fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
458fe9d4f57SAlexey Dobriyan 
45983fe27eaSPranith Kumar #ifdef CONFIG_SRCU
460fe9d4f57SAlexey Dobriyan /*
461fe9d4f57SAlexey Dobriyan  *	SRCU notifier chain routines.    Registration and unregistration
462fe9d4f57SAlexey Dobriyan  *	use a mutex, and call_chain is synchronized by SRCU (no locks).
463fe9d4f57SAlexey Dobriyan  */
464fe9d4f57SAlexey Dobriyan 
465fe9d4f57SAlexey Dobriyan /**
466fe9d4f57SAlexey Dobriyan  *	srcu_notifier_chain_register - Add notifier to an SRCU notifier chain
467fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the SRCU notifier chain
468fe9d4f57SAlexey Dobriyan  *	@n: New entry in notifier chain
469fe9d4f57SAlexey Dobriyan  *
470fe9d4f57SAlexey Dobriyan  *	Adds a notifier to an SRCU notifier chain.
471fe9d4f57SAlexey Dobriyan  *	Must be called in process context.
472fe9d4f57SAlexey Dobriyan  *
4735abb065dSBorislav Petkov  *	Returns 0 on success, %-EEXIST on error.
474fe9d4f57SAlexey Dobriyan  */
475fe9d4f57SAlexey Dobriyan int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
476fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
477fe9d4f57SAlexey Dobriyan {
478fe9d4f57SAlexey Dobriyan 	int ret;
479fe9d4f57SAlexey Dobriyan 
480fe9d4f57SAlexey Dobriyan 	/*
481fe9d4f57SAlexey Dobriyan 	 * This code gets used during boot-up, when task switching is
482fe9d4f57SAlexey Dobriyan 	 * not yet working and interrupts must remain disabled.  At
483fe9d4f57SAlexey Dobriyan 	 * such times we must not call mutex_lock().
484fe9d4f57SAlexey Dobriyan 	 */
485fe9d4f57SAlexey Dobriyan 	if (unlikely(system_state == SYSTEM_BOOTING))
486c82f898dSDmitry Osipenko 		return notifier_chain_register(&nh->head, n, false);
487fe9d4f57SAlexey Dobriyan 
488fe9d4f57SAlexey Dobriyan 	mutex_lock(&nh->mutex);
489c82f898dSDmitry Osipenko 	ret = notifier_chain_register(&nh->head, n, false);
490fe9d4f57SAlexey Dobriyan 	mutex_unlock(&nh->mutex);
491fe9d4f57SAlexey Dobriyan 	return ret;
492fe9d4f57SAlexey Dobriyan }
493fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_chain_register);
494fe9d4f57SAlexey Dobriyan 
495fe9d4f57SAlexey Dobriyan /**
496fe9d4f57SAlexey Dobriyan  *	srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain
497fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the SRCU notifier chain
498fe9d4f57SAlexey Dobriyan  *	@n: Entry to remove from notifier chain
499fe9d4f57SAlexey Dobriyan  *
500fe9d4f57SAlexey Dobriyan  *	Removes a notifier from an SRCU notifier chain.
501fe9d4f57SAlexey Dobriyan  *	Must be called from process context.
502fe9d4f57SAlexey Dobriyan  *
503fe9d4f57SAlexey Dobriyan  *	Returns zero on success or %-ENOENT on failure.
504fe9d4f57SAlexey Dobriyan  */
505fe9d4f57SAlexey Dobriyan int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
506fe9d4f57SAlexey Dobriyan 		struct notifier_block *n)
507fe9d4f57SAlexey Dobriyan {
508fe9d4f57SAlexey Dobriyan 	int ret;
509fe9d4f57SAlexey Dobriyan 
510fe9d4f57SAlexey Dobriyan 	/*
511fe9d4f57SAlexey Dobriyan 	 * This code gets used during boot-up, when task switching is
512fe9d4f57SAlexey Dobriyan 	 * not yet working and interrupts must remain disabled.  At
513fe9d4f57SAlexey Dobriyan 	 * such times we must not call mutex_lock().
514fe9d4f57SAlexey Dobriyan 	 */
515fe9d4f57SAlexey Dobriyan 	if (unlikely(system_state == SYSTEM_BOOTING))
516fe9d4f57SAlexey Dobriyan 		return notifier_chain_unregister(&nh->head, n);
517fe9d4f57SAlexey Dobriyan 
518fe9d4f57SAlexey Dobriyan 	mutex_lock(&nh->mutex);
519fe9d4f57SAlexey Dobriyan 	ret = notifier_chain_unregister(&nh->head, n);
520fe9d4f57SAlexey Dobriyan 	mutex_unlock(&nh->mutex);
521fe9d4f57SAlexey Dobriyan 	synchronize_srcu(&nh->srcu);
522fe9d4f57SAlexey Dobriyan 	return ret;
523fe9d4f57SAlexey Dobriyan }
524fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
525fe9d4f57SAlexey Dobriyan 
526fe9d4f57SAlexey Dobriyan /**
52770d93298SPeter Zijlstra  *	srcu_notifier_call_chain - Call functions in an SRCU notifier chain
528fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the SRCU notifier chain
529fe9d4f57SAlexey Dobriyan  *	@val: Value passed unmodified to notifier function
530fe9d4f57SAlexey Dobriyan  *	@v: Pointer passed unmodified to notifier function
531fe9d4f57SAlexey Dobriyan  *
532fe9d4f57SAlexey Dobriyan  *	Calls each function in a notifier chain in turn.  The functions
533fe9d4f57SAlexey Dobriyan  *	run in a process context, so they are allowed to block.
534fe9d4f57SAlexey Dobriyan  *
535fe9d4f57SAlexey Dobriyan  *	If the return value of the notifier can be and'ed
536fe9d4f57SAlexey Dobriyan  *	with %NOTIFY_STOP_MASK then srcu_notifier_call_chain()
537fe9d4f57SAlexey Dobriyan  *	will return immediately, with the return value of
538fe9d4f57SAlexey Dobriyan  *	the notifier function which halted execution.
539fe9d4f57SAlexey Dobriyan  *	Otherwise the return value is the return value
540fe9d4f57SAlexey Dobriyan  *	of the last notifier function called.
541fe9d4f57SAlexey Dobriyan  */
54270d93298SPeter Zijlstra int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
54370d93298SPeter Zijlstra 		unsigned long val, void *v)
544fe9d4f57SAlexey Dobriyan {
545fe9d4f57SAlexey Dobriyan 	int ret;
546fe9d4f57SAlexey Dobriyan 	int idx;
547fe9d4f57SAlexey Dobriyan 
548fe9d4f57SAlexey Dobriyan 	idx = srcu_read_lock(&nh->srcu);
54970d93298SPeter Zijlstra 	ret = notifier_call_chain(&nh->head, val, v, -1, NULL);
550fe9d4f57SAlexey Dobriyan 	srcu_read_unlock(&nh->srcu, idx);
551fe9d4f57SAlexey Dobriyan 	return ret;
552fe9d4f57SAlexey Dobriyan }
553fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
554fe9d4f57SAlexey Dobriyan 
555fe9d4f57SAlexey Dobriyan /**
556fe9d4f57SAlexey Dobriyan  *	srcu_init_notifier_head - Initialize an SRCU notifier head
557fe9d4f57SAlexey Dobriyan  *	@nh: Pointer to head of the srcu notifier chain
558fe9d4f57SAlexey Dobriyan  *
559fe9d4f57SAlexey Dobriyan  *	Unlike other sorts of notifier heads, SRCU notifier heads require
560fe9d4f57SAlexey Dobriyan  *	dynamic initialization.  Be sure to call this routine before
561fe9d4f57SAlexey Dobriyan  *	calling any of the other SRCU notifier routines for this head.
562fe9d4f57SAlexey Dobriyan  *
563fe9d4f57SAlexey Dobriyan  *	If an SRCU notifier head is deallocated, it must first be cleaned
564fe9d4f57SAlexey Dobriyan  *	up by calling srcu_cleanup_notifier_head().  Otherwise the head's
565fe9d4f57SAlexey Dobriyan  *	per-cpu data (used by the SRCU mechanism) will leak.
566fe9d4f57SAlexey Dobriyan  */
567fe9d4f57SAlexey Dobriyan void srcu_init_notifier_head(struct srcu_notifier_head *nh)
568fe9d4f57SAlexey Dobriyan {
569fe9d4f57SAlexey Dobriyan 	mutex_init(&nh->mutex);
570fe9d4f57SAlexey Dobriyan 	if (init_srcu_struct(&nh->srcu) < 0)
571fe9d4f57SAlexey Dobriyan 		BUG();
572fe9d4f57SAlexey Dobriyan 	nh->head = NULL;
573fe9d4f57SAlexey Dobriyan }
574fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(srcu_init_notifier_head);
575fe9d4f57SAlexey Dobriyan 
57683fe27eaSPranith Kumar #endif /* CONFIG_SRCU */
57783fe27eaSPranith Kumar 
578fe9d4f57SAlexey Dobriyan static ATOMIC_NOTIFIER_HEAD(die_chain);
579fe9d4f57SAlexey Dobriyan 
580b40a2cb6SMasami Hiramatsu int notrace notify_die(enum die_val val, const char *str,
581fe9d4f57SAlexey Dobriyan 	       struct pt_regs *regs, long err, int trap, int sig)
582fe9d4f57SAlexey Dobriyan {
583fe9d4f57SAlexey Dobriyan 	struct die_args args = {
584fe9d4f57SAlexey Dobriyan 		.regs	= regs,
585fe9d4f57SAlexey Dobriyan 		.str	= str,
586fe9d4f57SAlexey Dobriyan 		.err	= err,
587fe9d4f57SAlexey Dobriyan 		.trapnr	= trap,
588fe9d4f57SAlexey Dobriyan 		.signr	= sig,
589fe9d4f57SAlexey Dobriyan 
590fe9d4f57SAlexey Dobriyan 	};
5915778077dSLinus Torvalds 	RCU_LOCKDEP_WARN(!rcu_is_watching(),
592e727c7d7SAndy Lutomirski 			   "notify_die called but RCU thinks we're quiescent");
593fe9d4f57SAlexey Dobriyan 	return atomic_notifier_call_chain(&die_chain, val, &args);
594fe9d4f57SAlexey Dobriyan }
595b40a2cb6SMasami Hiramatsu NOKPROBE_SYMBOL(notify_die);
596fe9d4f57SAlexey Dobriyan 
597fe9d4f57SAlexey Dobriyan int register_die_notifier(struct notifier_block *nb)
598fe9d4f57SAlexey Dobriyan {
599fe9d4f57SAlexey Dobriyan 	return atomic_notifier_chain_register(&die_chain, nb);
600fe9d4f57SAlexey Dobriyan }
601fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(register_die_notifier);
602fe9d4f57SAlexey Dobriyan 
603fe9d4f57SAlexey Dobriyan int unregister_die_notifier(struct notifier_block *nb)
604fe9d4f57SAlexey Dobriyan {
605fe9d4f57SAlexey Dobriyan 	return atomic_notifier_chain_unregister(&die_chain, nb);
606fe9d4f57SAlexey Dobriyan }
607fe9d4f57SAlexey Dobriyan EXPORT_SYMBOL_GPL(unregister_die_notifier);
608