xref: /linux/Documentation/RCU/NMI-RCU.rst (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
16705cae4SMadhuparna Bhowmik.. _NMI_rcu_doc:
26705cae4SMadhuparna Bhowmik
36705cae4SMadhuparna BhowmikUsing RCU to Protect Dynamic NMI Handlers
46705cae4SMadhuparna Bhowmik=========================================
56705cae4SMadhuparna Bhowmik
66705cae4SMadhuparna Bhowmik
76705cae4SMadhuparna BhowmikAlthough RCU is usually used to protect read-mostly data structures,
86705cae4SMadhuparna Bhowmikit is possible to use RCU to provide dynamic non-maskable interrupt
96705cae4SMadhuparna Bhowmikhandlers, as well as dynamic irq handlers.  This document describes
106705cae4SMadhuparna Bhowmikhow to do this, drawing loosely from Zwane Mwaikambo's NMI-timer
11*8750dfe6SPaul E. McKenneywork in an old version of "arch/x86/kernel/traps.c".
126705cae4SMadhuparna Bhowmik
136705cae4SMadhuparna BhowmikThe relevant pieces of code are listed below, each followed by a
146705cae4SMadhuparna Bhowmikbrief explanation::
156705cae4SMadhuparna Bhowmik
166705cae4SMadhuparna Bhowmik	static int dummy_nmi_callback(struct pt_regs *regs, int cpu)
176705cae4SMadhuparna Bhowmik	{
186705cae4SMadhuparna Bhowmik		return 0;
196705cae4SMadhuparna Bhowmik	}
206705cae4SMadhuparna Bhowmik
216705cae4SMadhuparna BhowmikThe dummy_nmi_callback() function is a "dummy" NMI handler that does
226705cae4SMadhuparna Bhowmiknothing, but returns zero, thus saying that it did nothing, allowing
236705cae4SMadhuparna Bhowmikthe NMI handler to take the default machine-specific action::
246705cae4SMadhuparna Bhowmik
256705cae4SMadhuparna Bhowmik	static nmi_callback_t nmi_callback = dummy_nmi_callback;
266705cae4SMadhuparna Bhowmik
276705cae4SMadhuparna BhowmikThis nmi_callback variable is a global function pointer to the current
286705cae4SMadhuparna BhowmikNMI handler::
296705cae4SMadhuparna Bhowmik
306705cae4SMadhuparna Bhowmik	void do_nmi(struct pt_regs * regs, long error_code)
316705cae4SMadhuparna Bhowmik	{
326705cae4SMadhuparna Bhowmik		int cpu;
336705cae4SMadhuparna Bhowmik
346705cae4SMadhuparna Bhowmik		nmi_enter();
356705cae4SMadhuparna Bhowmik
366705cae4SMadhuparna Bhowmik		cpu = smp_processor_id();
376705cae4SMadhuparna Bhowmik		++nmi_count(cpu);
386705cae4SMadhuparna Bhowmik
396705cae4SMadhuparna Bhowmik		if (!rcu_dereference_sched(nmi_callback)(regs, cpu))
406705cae4SMadhuparna Bhowmik			default_do_nmi(regs);
416705cae4SMadhuparna Bhowmik
426705cae4SMadhuparna Bhowmik		nmi_exit();
436705cae4SMadhuparna Bhowmik	}
446705cae4SMadhuparna Bhowmik
456705cae4SMadhuparna BhowmikThe do_nmi() function processes each NMI.  It first disables preemption
466705cae4SMadhuparna Bhowmikin the same way that a hardware irq would, then increments the per-CPU
476705cae4SMadhuparna Bhowmikcount of NMIs.  It then invokes the NMI handler stored in the nmi_callback
486705cae4SMadhuparna Bhowmikfunction pointer.  If this handler returns zero, do_nmi() invokes the
496705cae4SMadhuparna Bhowmikdefault_do_nmi() function to handle a machine-specific NMI.  Finally,
506705cae4SMadhuparna Bhowmikpreemption is restored.
516705cae4SMadhuparna Bhowmik
526705cae4SMadhuparna BhowmikIn theory, rcu_dereference_sched() is not needed, since this code runs
536705cae4SMadhuparna Bhowmikonly on i386, which in theory does not need rcu_dereference_sched()
546705cae4SMadhuparna Bhowmikanyway.  However, in practice it is a good documentation aid, particularly
556705cae4SMadhuparna Bhowmikfor anyone attempting to do something similar on Alpha or on systems
566705cae4SMadhuparna Bhowmikwith aggressive optimizing compilers.
576705cae4SMadhuparna Bhowmik
586705cae4SMadhuparna BhowmikQuick Quiz:
596705cae4SMadhuparna Bhowmik		Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?
606705cae4SMadhuparna Bhowmik
616705cae4SMadhuparna Bhowmik:ref:`Answer to Quick Quiz <answer_quick_quiz_NMI>`
626705cae4SMadhuparna Bhowmik
636705cae4SMadhuparna BhowmikBack to the discussion of NMI and RCU::
646705cae4SMadhuparna Bhowmik
656705cae4SMadhuparna Bhowmik	void set_nmi_callback(nmi_callback_t callback)
666705cae4SMadhuparna Bhowmik	{
676705cae4SMadhuparna Bhowmik		rcu_assign_pointer(nmi_callback, callback);
686705cae4SMadhuparna Bhowmik	}
696705cae4SMadhuparna Bhowmik
706705cae4SMadhuparna BhowmikThe set_nmi_callback() function registers an NMI handler.  Note that any
716705cae4SMadhuparna Bhowmikdata that is to be used by the callback must be initialized up -before-
726705cae4SMadhuparna Bhowmikthe call to set_nmi_callback().  On architectures that do not order
736705cae4SMadhuparna Bhowmikwrites, the rcu_assign_pointer() ensures that the NMI handler sees the
746705cae4SMadhuparna Bhowmikinitialized values::
756705cae4SMadhuparna Bhowmik
766705cae4SMadhuparna Bhowmik	void unset_nmi_callback(void)
776705cae4SMadhuparna Bhowmik	{
786705cae4SMadhuparna Bhowmik		rcu_assign_pointer(nmi_callback, dummy_nmi_callback);
796705cae4SMadhuparna Bhowmik	}
806705cae4SMadhuparna Bhowmik
816705cae4SMadhuparna BhowmikThis function unregisters an NMI handler, restoring the original
826705cae4SMadhuparna Bhowmikdummy_nmi_handler().  However, there may well be an NMI handler
836705cae4SMadhuparna Bhowmikcurrently executing on some other CPU.  We therefore cannot free
846705cae4SMadhuparna Bhowmikup any data structures used by the old NMI handler until execution
856705cae4SMadhuparna Bhowmikof it completes on all other CPUs.
866705cae4SMadhuparna Bhowmik
876705cae4SMadhuparna BhowmikOne way to accomplish this is via synchronize_rcu(), perhaps as
886705cae4SMadhuparna Bhowmikfollows::
896705cae4SMadhuparna Bhowmik
906705cae4SMadhuparna Bhowmik	unset_nmi_callback();
916705cae4SMadhuparna Bhowmik	synchronize_rcu();
926705cae4SMadhuparna Bhowmik	kfree(my_nmi_data);
936705cae4SMadhuparna Bhowmik
946705cae4SMadhuparna BhowmikThis works because (as of v4.20) synchronize_rcu() blocks until all
956705cae4SMadhuparna BhowmikCPUs complete any preemption-disabled segments of code that they were
966705cae4SMadhuparna Bhowmikexecuting.
976705cae4SMadhuparna BhowmikSince NMI handlers disable preemption, synchronize_rcu() is guaranteed
986705cae4SMadhuparna Bhowmiknot to return until all ongoing NMI handlers exit.  It is therefore safe
996705cae4SMadhuparna Bhowmikto free up the handler's data as soon as synchronize_rcu() returns.
1006705cae4SMadhuparna Bhowmik
1016705cae4SMadhuparna BhowmikImportant note: for this to work, the architecture in question must
1026705cae4SMadhuparna Bhowmikinvoke nmi_enter() and nmi_exit() on NMI entry and exit, respectively.
1036705cae4SMadhuparna Bhowmik
1046705cae4SMadhuparna Bhowmik.. _answer_quick_quiz_NMI:
1056705cae4SMadhuparna Bhowmik
1066705cae4SMadhuparna BhowmikAnswer to Quick Quiz:
1076705cae4SMadhuparna Bhowmik	Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?
1086705cae4SMadhuparna Bhowmik
1096705cae4SMadhuparna Bhowmik	The caller to set_nmi_callback() might well have
1106705cae4SMadhuparna Bhowmik	initialized some data that is to be used by the new NMI
1116705cae4SMadhuparna Bhowmik	handler.  In this case, the rcu_dereference_sched() would
1126705cae4SMadhuparna Bhowmik	be needed, because otherwise a CPU that received an NMI
1136705cae4SMadhuparna Bhowmik	just after the new handler was set might see the pointer
1146705cae4SMadhuparna Bhowmik	to the new NMI handler, but the old pre-initialized
1156705cae4SMadhuparna Bhowmik	version of the handler's data.
1166705cae4SMadhuparna Bhowmik
1176705cae4SMadhuparna Bhowmik	This same sad story can happen on other CPUs when using
1186705cae4SMadhuparna Bhowmik	a compiler with aggressive pointer-value speculation
119*8750dfe6SPaul E. McKenney	optimizations.  (But please don't!)
1206705cae4SMadhuparna Bhowmik
1216705cae4SMadhuparna Bhowmik	More important, the rcu_dereference_sched() makes it
1226705cae4SMadhuparna Bhowmik	clear to someone reading the code that the pointer is
1236705cae4SMadhuparna Bhowmik	being protected by RCU-sched.
124