1 .. _NMI_rcu_doc: 2 3 Using RCU to Protect Dynamic NMI Handlers 4 ========================================= 5 6 7 Although RCU is usually used to protect read-m 8 it is possible to use RCU to provide dynamic n 9 handlers, as well as dynamic irq handlers. Th 10 how to do this, drawing loosely from Zwane Mwa 11 work in an old version of "arch/x86/kernel/tra 12 13 The relevant pieces of code are listed below, 14 brief explanation:: 15 16 static int dummy_nmi_callback(struct p 17 { 18 return 0; 19 } 20 21 The dummy_nmi_callback() function is a "dummy" 22 nothing, but returns zero, thus saying that it 23 the NMI handler to take the default machine-sp 24 25 static nmi_callback_t nmi_callback = d 26 27 This nmi_callback variable is a global functio 28 NMI handler:: 29 30 void do_nmi(struct pt_regs * regs, lon 31 { 32 int cpu; 33 34 nmi_enter(); 35 36 cpu = smp_processor_id(); 37 ++nmi_count(cpu); 38 39 if (!rcu_dereference_sched(nmi 40 default_do_nmi(regs); 41 42 nmi_exit(); 43 } 44 45 The do_nmi() function processes each NMI. It 46 in the same way that a hardware irq would, the 47 count of NMIs. It then invokes the NMI handle 48 function pointer. If this handler returns zer 49 default_do_nmi() function to handle a machine- 50 preemption is restored. 51 52 In theory, rcu_dereference_sched() is not need 53 only on i386, which in theory does not need rc 54 anyway. However, in practice it is a good doc 55 for anyone attempting to do something similar 56 with aggressive optimizing compilers. 57 58 Quick Quiz: 59 Why might the rcu_dereference_ 60 61 :ref:`Answer to Quick Quiz <answer_quick_quiz_ 62 63 Back to the discussion of NMI and RCU:: 64 65 void set_nmi_callback(nmi_callback_t c 66 { 67 rcu_assign_pointer(nmi_callbac 68 } 69 70 The set_nmi_callback() function registers an N 71 data that is to be used by the callback must b 72 the call to set_nmi_callback(). On architectu 73 writes, the rcu_assign_pointer() ensures that 74 initialized values:: 75 76 void unset_nmi_callback(void) 77 { 78 rcu_assign_pointer(nmi_callbac 79 } 80 81 This function unregisters an NMI handler, rest 82 dummy_nmi_handler(). However, there may well 83 currently executing on some other CPU. We the 84 up any data structures used by the old NMI han 85 of it completes on all other CPUs. 86 87 One way to accomplish this is via synchronize_ 88 follows:: 89 90 unset_nmi_callback(); 91 synchronize_rcu(); 92 kfree(my_nmi_data); 93 94 This works because (as of v4.20) synchronize_r 95 CPUs complete any preemption-disabled segments 96 executing. 97 Since NMI handlers disable preemption, synchro 98 not to return until all ongoing NMI handlers e 99 to free up the handler's data as soon as synch 100 101 Important note: for this to work, the architec 102 invoke nmi_enter() and nmi_exit() on NMI entry 103 104 .. _answer_quick_quiz_NMI: 105 106 Answer to Quick Quiz: 107 Why might the rcu_dereference_sched() 108 109 The caller to set_nmi_callback() might 110 initialized some data that is to be us 111 handler. In this case, the rcu_derefe 112 be needed, because otherwise a CPU tha 113 just after the new handler was set mig 114 to the new NMI handler, but the old pr 115 version of the handler's data. 116 117 This same sad story can happen on othe 118 a compiler with aggressive pointer-val 119 optimizations. (But please don't!) 120 121 More important, the rcu_dereference_sc 122 clear to someone reading the code that 123 being protected by RCU-sched.
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.