€•BDŒsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ/translations/zh_CN/RCU/NMI-RCU”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/zh_TW/RCU/NMI-RCU”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/it_IT/RCU/NMI-RCU”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/ja_JP/RCU/NMI-RCU”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/ko_KR/RCU/NMI-RCU”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ/translations/sp_SP/RCU/NMI-RCU”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒtarget”“”)”}”(hŒ.. _NMI_rcu_doc:”h]”h}”(h]”h ]”h"]”h$]”h&]”Œrefid”Œ nmi-rcu-doc”uh1h¡h KhhhžhhŸŒ9/var/lib/git/docbuild/linux/Documentation/RCU/NMI-RCU.rst”ubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒ)Using RCU to Protect Dynamic NMI Handlers”h]”hŒ)Using RCU to Protect Dynamic NMI Handlers”…””}”(hh·hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hµhh²hžhhŸh¯h KubhŒ paragraph”“”)”}”(hXBAlthough RCU is usually used to protect read-mostly data structures, it is possible to use RCU to provide dynamic non-maskable interrupt handlers, as well as dynamic irq handlers. This document describes how to do this, drawing loosely from Zwane Mwaikambo's NMI-timer work in an old version of "arch/x86/kernel/traps.c".”h]”hXHAlthough RCU is usually used to protect read-mostly data structures, it is possible to use RCU to provide dynamic non-maskable interrupt handlers, as well as dynamic irq handlers. This document describes how to do this, drawing loosely from Zwane Mwaikambo’s NMI-timer work in an old version of “arch/x86/kernel/traps.c”.”…””}”(hhÇhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h Khh²hžhubhÆ)”}”(hŒTThe relevant pieces of code are listed below, each followed by a brief explanation::”h]”hŒSThe relevant pieces of code are listed below, each followed by a brief explanation:”…””}”(hhÕhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h K hh²hžhubhŒ literal_block”“”)”}”(hŒRstatic int dummy_nmi_callback(struct pt_regs *regs, int cpu) { return 0; }”h]”hŒRstatic int dummy_nmi_callback(struct pt_regs *regs, int cpu) { return 0; }”…””}”hhåsbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hãhŸh¯h Khh²hžhubhÆ)”}”(hŒÇThe dummy_nmi_callback() function is a "dummy" NMI handler that does nothing, but returns zero, thus saying that it did nothing, allowing the NMI handler to take the default machine-specific action::”h]”hŒÊThe dummy_nmi_callback() function is a “dummy” NMI handler that does nothing, but returns zero, thus saying that it did nothing, allowing the NMI handler to take the default machine-specific action:”…””}”(hhõhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h Khh²hžhubhä)”}”(hŒ8static nmi_callback_t nmi_callback = dummy_nmi_callback;”h]”hŒ8static nmi_callback_t nmi_callback = dummy_nmi_callback;”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hóhôuh1hãhŸh¯h Khh²hžhubhÆ)”}”(hŒTThis nmi_callback variable is a global function pointer to the current NMI handler::”h]”hŒSThis nmi_callback variable is a global function pointer to the current NMI handler:”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h Khh²hžhubhä)”}”(hXvoid do_nmi(struct pt_regs * regs, long error_code) { int cpu; nmi_enter(); cpu = smp_processor_id(); ++nmi_count(cpu); if (!rcu_dereference_sched(nmi_callback)(regs, cpu)) default_do_nmi(regs); nmi_exit(); }”h]”hXvoid do_nmi(struct pt_regs * regs, long error_code) { int cpu; nmi_enter(); cpu = smp_processor_id(); ++nmi_count(cpu); if (!rcu_dereference_sched(nmi_callback)(regs, cpu)) default_do_nmi(regs); nmi_exit(); }”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”hóhôuh1hãhŸh¯h Khh²hžhubhÆ)”}”(hX}The do_nmi() function processes each NMI. It first disables preemption in the same way that a hardware irq would, then increments the per-CPU count of NMIs. It then invokes the NMI handler stored in the nmi_callback function pointer. If this handler returns zero, do_nmi() invokes the default_do_nmi() function to handle a machine-specific NMI. Finally, preemption is restored.”h]”hX}The do_nmi() function processes each NMI. It first disables preemption in the same way that a hardware irq would, then increments the per-CPU count of NMIs. It then invokes the NMI handler stored in the nmi_callback function pointer. If this handler returns zero, do_nmi() invokes the default_do_nmi() function to handle a machine-specific NMI. Finally, preemption is restored.”…””}”(hj-hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h K-hh²hžhubhÆ)”}”(hX@In theory, rcu_dereference_sched() is not needed, since this code runs only on i386, which in theory does not need rcu_dereference_sched() anyway. However, in practice it is a good documentation aid, particularly for anyone attempting to do something similar on Alpha or on systems with aggressive optimizing compilers.”h]”hX@In theory, rcu_dereference_sched() is not needed, since this code runs only on i386, which in theory does not need rcu_dereference_sched() anyway. However, in practice it is a good documentation aid, particularly for anyone attempting to do something similar on Alpha or on systems with aggressive optimizing compilers.”…””}”(hj;hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h K4hh²hžhubhŒdefinition_list”“”)”}”(hhh]”hŒdefinition_list_item”“”)”}”(hŒ…Quick Quiz: Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only? ”h]”(hŒterm”“”)”}”(hŒ Quick Quiz:”h]”hŒ Quick Quiz:”…””}”(hjVhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jThŸh¯h K;hjPubhŒ definition”“”)”}”(hhh]”hÆ)”}”(hŒxWhy might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?”h]”hŒxWhy might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?”…””}”(hjihžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h K;hjfubah}”(h]”h ]”h"]”h$]”h&]”uh1jdhjPubeh}”(h]”h ]”h"]”h$]”h&]”uh1jNhŸh¯h K;hjKubah}”(h]”h ]”h"]”h$]”h&]”uh1jIhh²hžhhŸh¯h NubhÆ)”}”(hŒ3:ref:`Answer to Quick Quiz `”h]”h)”}”(hj‹h]”hŒinline”“”)”}”(hj‹h]”hŒAnswer to Quick Quiz”…””}”(hj’hžhhŸNh Nubah}”(h]”h ]”(Œxref”Œstd”Œstd-ref”eh"]”h$]”h&]”uh1jhjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”Œ RCU/NMI-RCU”Œ refdomain”jŒreftype”Œref”Œ refexplicit”ˆŒrefwarn”ˆŒ reftarget”Œanswer_quick_quiz_nmi”uh1hhŸh¯h K=hj‰ubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h K=hh²hžhubhÆ)”}”(hŒ'Back to the discussion of NMI and RCU::”h]”hŒ&Back to the discussion of NMI and RCU:”…””}”(hj·hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h K?hh²hžhubhä)”}”(hŒfvoid set_nmi_callback(nmi_callback_t callback) { rcu_assign_pointer(nmi_callback, callback); }”h]”hŒfvoid set_nmi_callback(nmi_callback_t callback) { rcu_assign_pointer(nmi_callback, callback); }”…””}”hjÅsbah}”(h]”h ]”h"]”h$]”h&]”hóhôuh1hãhŸh¯h KAhh²hžhubhÆ)”}”(hX0The set_nmi_callback() function registers an NMI handler. Note that any data that is to be used by the callback must be initialized up -before- the call to set_nmi_callback(). On architectures that do not order writes, the rcu_assign_pointer() ensures that the NMI handler sees the initialized values::”h]”hX/The set_nmi_callback() function registers an NMI handler. Note that any data that is to be used by the callback must be initialized up -before- the call to set_nmi_callback(). On architectures that do not order writes, the rcu_assign_pointer() ensures that the NMI handler sees the initialized values:”…””}”(hjÓhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h KFhh²hžhubhä)”}”(hŒ_void unset_nmi_callback(void) { rcu_assign_pointer(nmi_callback, dummy_nmi_callback); }”h]”hŒ_void unset_nmi_callback(void) { rcu_assign_pointer(nmi_callback, dummy_nmi_callback); }”…””}”hjásbah}”(h]”h ]”h"]”h$]”h&]”hóhôuh1hãhŸh¯h KLhh²hžhubhÆ)”}”(hX'This function unregisters an NMI handler, restoring the original dummy_nmi_handler(). However, there may well be an NMI handler currently executing on some other CPU. We therefore cannot free up any data structures used by the old NMI handler until execution of it completes on all other CPUs.”h]”hX'This function unregisters an NMI handler, restoring the original dummy_nmi_handler(). However, there may well be an NMI handler currently executing on some other CPU. We therefore cannot free up any data structures used by the old NMI handler until execution of it completes on all other CPUs.”…””}”(hjïhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h KQhh²hžhubhÆ)”}”(hŒIOne way to accomplish this is via synchronize_rcu(), perhaps as follows::”h]”hŒHOne way to accomplish this is via synchronize_rcu(), perhaps as follows:”…””}”(hjýhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÅhŸh¯h KWhh²hžhubhä)”}”(hŒ