doc: Converted NMI-RCU.txt to NMI-RCU.rst.
This patch converts NMI-RCU from txt to rst format. Also adds NMI-RCU in the index.rst file. Signed-off-by: Madhuparna Bhowmik <madhuparnabhowmik04@gmail.com> [ paulmck: Apply feedback from Phong Tran. ] Tested-by: Phong Tran <tranmanphong@gmail.com> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
parent
9ffdd79824
commit
6705cae433
|
@ -1,4 +1,7 @@
|
||||||
|
.. _NMI_rcu_doc:
|
||||||
|
|
||||||
Using RCU to Protect Dynamic NMI Handlers
|
Using RCU to Protect Dynamic NMI Handlers
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
|
||||||
Although RCU is usually used to protect read-mostly data structures,
|
Although RCU is usually used to protect read-mostly data structures,
|
||||||
|
@ -9,7 +12,7 @@ work in "arch/x86/oprofile/nmi_timer_int.c" and in
|
||||||
"arch/x86/kernel/traps.c".
|
"arch/x86/kernel/traps.c".
|
||||||
|
|
||||||
The relevant pieces of code are listed below, each followed by a
|
The relevant pieces of code are listed below, each followed by a
|
||||||
brief explanation.
|
brief explanation::
|
||||||
|
|
||||||
static int dummy_nmi_callback(struct pt_regs *regs, int cpu)
|
static int dummy_nmi_callback(struct pt_regs *regs, int cpu)
|
||||||
{
|
{
|
||||||
|
@ -18,12 +21,12 @@ brief explanation.
|
||||||
|
|
||||||
The dummy_nmi_callback() function is a "dummy" NMI handler that does
|
The dummy_nmi_callback() function is a "dummy" NMI handler that does
|
||||||
nothing, but returns zero, thus saying that it did nothing, allowing
|
nothing, but returns zero, thus saying that it did nothing, allowing
|
||||||
the NMI handler to take the default machine-specific action.
|
the NMI handler to take the default machine-specific action::
|
||||||
|
|
||||||
static nmi_callback_t nmi_callback = dummy_nmi_callback;
|
static nmi_callback_t nmi_callback = dummy_nmi_callback;
|
||||||
|
|
||||||
This nmi_callback variable is a global function pointer to the current
|
This nmi_callback variable is a global function pointer to the current
|
||||||
NMI handler.
|
NMI handler::
|
||||||
|
|
||||||
void do_nmi(struct pt_regs * regs, long error_code)
|
void do_nmi(struct pt_regs * regs, long error_code)
|
||||||
{
|
{
|
||||||
|
@ -53,11 +56,12 @@ anyway. However, in practice it is a good documentation aid, particularly
|
||||||
for anyone attempting to do something similar on Alpha or on systems
|
for anyone attempting to do something similar on Alpha or on systems
|
||||||
with aggressive optimizing compilers.
|
with aggressive optimizing compilers.
|
||||||
|
|
||||||
Quick Quiz: Why might the rcu_dereference_sched() be necessary on Alpha,
|
Quick Quiz:
|
||||||
given that the code referenced by the pointer is read-only?
|
Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?
|
||||||
|
|
||||||
|
:ref:`Answer to Quick Quiz <answer_quick_quiz_NMI>`
|
||||||
|
|
||||||
Back to the discussion of NMI and RCU...
|
Back to the discussion of NMI and RCU::
|
||||||
|
|
||||||
void set_nmi_callback(nmi_callback_t callback)
|
void set_nmi_callback(nmi_callback_t callback)
|
||||||
{
|
{
|
||||||
|
@ -68,7 +72,7 @@ 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-
|
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
|
the call to set_nmi_callback(). On architectures that do not order
|
||||||
writes, the rcu_assign_pointer() ensures that the NMI handler sees the
|
writes, the rcu_assign_pointer() ensures that the NMI handler sees the
|
||||||
initialized values.
|
initialized values::
|
||||||
|
|
||||||
void unset_nmi_callback(void)
|
void unset_nmi_callback(void)
|
||||||
{
|
{
|
||||||
|
@ -82,7 +86,7 @@ up any data structures used by the old NMI handler until execution
|
||||||
of it completes on all other CPUs.
|
of it completes on all other CPUs.
|
||||||
|
|
||||||
One way to accomplish this is via synchronize_rcu(), perhaps as
|
One way to accomplish this is via synchronize_rcu(), perhaps as
|
||||||
follows:
|
follows::
|
||||||
|
|
||||||
unset_nmi_callback();
|
unset_nmi_callback();
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
|
@ -98,24 +102,23 @@ to free up the handler's data as soon as synchronize_rcu() returns.
|
||||||
Important note: for this to work, the architecture in question must
|
Important note: for this to work, the architecture in question must
|
||||||
invoke nmi_enter() and nmi_exit() on NMI entry and exit, respectively.
|
invoke nmi_enter() and nmi_exit() on NMI entry and exit, respectively.
|
||||||
|
|
||||||
|
.. _answer_quick_quiz_NMI:
|
||||||
|
|
||||||
Answer to Quick Quiz
|
Answer to Quick Quiz:
|
||||||
|
Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?
|
||||||
|
|
||||||
Why might the rcu_dereference_sched() be necessary on Alpha, given
|
The caller to set_nmi_callback() might well have
|
||||||
that the code referenced by the pointer is read-only?
|
initialized some data that is to be used by the new NMI
|
||||||
|
handler. In this case, the rcu_dereference_sched() would
|
||||||
|
be needed, because otherwise a CPU that received an NMI
|
||||||
|
just after the new handler was set might see the pointer
|
||||||
|
to the new NMI handler, but the old pre-initialized
|
||||||
|
version of the handler's data.
|
||||||
|
|
||||||
Answer: The caller to set_nmi_callback() might well have
|
This same sad story can happen on other CPUs when using
|
||||||
initialized some data that is to be used by the new NMI
|
a compiler with aggressive pointer-value speculation
|
||||||
handler. In this case, the rcu_dereference_sched() would
|
optimizations.
|
||||||
be needed, because otherwise a CPU that received an NMI
|
|
||||||
just after the new handler was set might see the pointer
|
|
||||||
to the new NMI handler, but the old pre-initialized
|
|
||||||
version of the handler's data.
|
|
||||||
|
|
||||||
This same sad story can happen on other CPUs when using
|
More important, the rcu_dereference_sched() makes it
|
||||||
a compiler with aggressive pointer-value speculation
|
clear to someone reading the code that the pointer is
|
||||||
optimizations.
|
being protected by RCU-sched.
|
||||||
|
|
||||||
More important, the rcu_dereference_sched() makes it
|
|
||||||
clear to someone reading the code that the pointer is
|
|
||||||
being protected by RCU-sched.
|
|
|
@ -10,6 +10,7 @@ RCU concepts
|
||||||
arrayRCU
|
arrayRCU
|
||||||
rcu
|
rcu
|
||||||
listRCU
|
listRCU
|
||||||
|
NMI-RCU
|
||||||
UP
|
UP
|
||||||
|
|
||||||
Design/Memory-Ordering/Tree-RCU-Memory-Ordering
|
Design/Memory-Ordering/Tree-RCU-Memory-Ordering
|
||||||
|
|
Loading…
Reference in New Issue