xref: /openbmc/linux/kernel/notifier.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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