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