1
+ .. _NMI_rcu_doc :
2
+
1
3
Using RCU to Protect Dynamic NMI Handlers
4
+ =========================================
2
5
3
6
4
7
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
9
12
"arch/x86/kernel/traps.c".
10
13
11
14
The relevant pieces of code are listed below, each followed by a
12
- brief explanation.
15
+ brief explanation::
13
16
14
17
static int dummy_nmi_callback(struct pt_regs *regs, int cpu)
15
18
{
@@ -18,12 +21,12 @@ brief explanation.
18
21
19
22
The dummy_nmi_callback() function is a "dummy" NMI handler that does
20
23
nothing, but returns zero, thus saying that it did nothing, allowing
21
- the NMI handler to take the default machine-specific action.
24
+ the NMI handler to take the default machine-specific action::
22
25
23
26
static nmi_callback_t nmi_callback = dummy_nmi_callback;
24
27
25
28
This nmi_callback variable is a global function pointer to the current
26
- NMI handler.
29
+ NMI handler::
27
30
28
31
void do_nmi(struct pt_regs * regs, long error_code)
29
32
{
@@ -53,11 +56,12 @@ anyway. However, in practice it is a good documentation aid, particularly
53
56
for anyone attempting to do something similar on Alpha or on systems
54
57
with aggressive optimizing compilers.
55
58
56
- Quick Quiz: Why might the rcu_dereference_sched() be necessary on Alpha,
57
- given that the code referenced by the pointer is read-only?
59
+ Quick Quiz:
60
+ Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?
58
61
62
+ :ref: `Answer to Quick Quiz <answer_quick_quiz_NMI >`
59
63
60
- Back to the discussion of NMI and RCU...
64
+ Back to the discussion of NMI and RCU::
61
65
62
66
void set_nmi_callback(nmi_callback_t callback)
63
67
{
@@ -68,7 +72,7 @@ The set_nmi_callback() function registers an NMI handler. Note that any
68
72
data that is to be used by the callback must be initialized up -before-
69
73
the call to set_nmi_callback(). On architectures that do not order
70
74
writes, the rcu_assign_pointer() ensures that the NMI handler sees the
71
- initialized values.
75
+ initialized values::
72
76
73
77
void unset_nmi_callback(void)
74
78
{
@@ -82,7 +86,7 @@ up any data structures used by the old NMI handler until execution
82
86
of it completes on all other CPUs.
83
87
84
88
One way to accomplish this is via synchronize_rcu(), perhaps as
85
- follows:
89
+ follows::
86
90
87
91
unset_nmi_callback();
88
92
synchronize_rcu();
@@ -98,24 +102,23 @@ to free up the handler's data as soon as synchronize_rcu() returns.
98
102
Important note: for this to work, the architecture in question must
99
103
invoke nmi_enter() and nmi_exit() on NMI entry and exit, respectively.
100
104
105
+ .. _answer_quick_quiz_NMI :
101
106
102
- Answer to Quick Quiz
103
-
104
- Why might the rcu_dereference_sched() be necessary on Alpha, given
105
- that the code referenced by the pointer is read-only?
107
+ Answer to Quick Quiz:
108
+ Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?
106
109
107
- Answer: The caller to set_nmi_callback() might well have
108
- initialized some data that is to be used by the new NMI
109
- handler. In this case, the rcu_dereference_sched() would
110
- be needed, because otherwise a CPU that received an NMI
111
- just after the new handler was set might see the pointer
112
- to the new NMI handler, but the old pre-initialized
113
- version of the handler's data.
110
+ The caller to set_nmi_callback() might well have
111
+ initialized some data that is to be used by the new NMI
112
+ handler. In this case, the rcu_dereference_sched() would
113
+ be needed, because otherwise a CPU that received an NMI
114
+ just after the new handler was set might see the pointer
115
+ to the new NMI handler, but the old pre-initialized
116
+ version of the handler's data.
114
117
115
- This same sad story can happen on other CPUs when using
116
- a compiler with aggressive pointer-value speculation
117
- optimizations.
118
+ This same sad story can happen on other CPUs when using
119
+ a compiler with aggressive pointer-value speculation
120
+ optimizations.
118
121
119
- More important, the rcu_dereference_sched() makes it
120
- clear to someone reading the code that the pointer is
121
- being protected by RCU-sched.
122
+ More important, the rcu_dereference_sched() makes it
123
+ clear to someone reading the code that the pointer is
124
+ being protected by RCU-sched.
0 commit comments