NMI-RCU.rst 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. .. _NMI_rcu_doc:
  2. Using RCU to Protect Dynamic NMI Handlers
  3. =========================================
  4. Although RCU is usually used to protect read-mostly data structures,
  5. it is possible to use RCU to provide dynamic non-maskable interrupt
  6. handlers, as well as dynamic irq handlers. This document describes
  7. how to do this, drawing loosely from Zwane Mwaikambo's NMI-timer
  8. work in "arch/x86/oprofile/nmi_timer_int.c" and in
  9. "arch/x86/kernel/traps.c".
  10. The relevant pieces of code are listed below, each followed by a
  11. brief explanation::
  12. static int dummy_nmi_callback(struct pt_regs *regs, int cpu)
  13. {
  14. return 0;
  15. }
  16. The dummy_nmi_callback() function is a "dummy" NMI handler that does
  17. nothing, but returns zero, thus saying that it did nothing, allowing
  18. the NMI handler to take the default machine-specific action::
  19. static nmi_callback_t nmi_callback = dummy_nmi_callback;
  20. This nmi_callback variable is a global function pointer to the current
  21. NMI handler::
  22. void do_nmi(struct pt_regs * regs, long error_code)
  23. {
  24. int cpu;
  25. nmi_enter();
  26. cpu = smp_processor_id();
  27. ++nmi_count(cpu);
  28. if (!rcu_dereference_sched(nmi_callback)(regs, cpu))
  29. default_do_nmi(regs);
  30. nmi_exit();
  31. }
  32. The do_nmi() function processes each NMI. It first disables preemption
  33. in the same way that a hardware irq would, then increments the per-CPU
  34. count of NMIs. It then invokes the NMI handler stored in the nmi_callback
  35. function pointer. If this handler returns zero, do_nmi() invokes the
  36. default_do_nmi() function to handle a machine-specific NMI. Finally,
  37. preemption is restored.
  38. In theory, rcu_dereference_sched() is not needed, since this code runs
  39. only on i386, which in theory does not need rcu_dereference_sched()
  40. anyway. However, in practice it is a good documentation aid, particularly
  41. for anyone attempting to do something similar on Alpha or on systems
  42. with aggressive optimizing compilers.
  43. Quick Quiz:
  44. Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?
  45. :ref:`Answer to Quick Quiz <answer_quick_quiz_NMI>`
  46. Back to the discussion of NMI and RCU::
  47. void set_nmi_callback(nmi_callback_t callback)
  48. {
  49. rcu_assign_pointer(nmi_callback, callback);
  50. }
  51. The set_nmi_callback() function registers an NMI handler. Note that any
  52. data that is to be used by the callback must be initialized up -before-
  53. the call to set_nmi_callback(). On architectures that do not order
  54. writes, the rcu_assign_pointer() ensures that the NMI handler sees the
  55. initialized values::
  56. void unset_nmi_callback(void)
  57. {
  58. rcu_assign_pointer(nmi_callback, dummy_nmi_callback);
  59. }
  60. This function unregisters an NMI handler, restoring the original
  61. dummy_nmi_handler(). However, there may well be an NMI handler
  62. currently executing on some other CPU. We therefore cannot free
  63. up any data structures used by the old NMI handler until execution
  64. of it completes on all other CPUs.
  65. One way to accomplish this is via synchronize_rcu(), perhaps as
  66. follows::
  67. unset_nmi_callback();
  68. synchronize_rcu();
  69. kfree(my_nmi_data);
  70. This works because (as of v4.20) synchronize_rcu() blocks until all
  71. CPUs complete any preemption-disabled segments of code that they were
  72. executing.
  73. Since NMI handlers disable preemption, synchronize_rcu() is guaranteed
  74. not to return until all ongoing NMI handlers exit. It is therefore safe
  75. to free up the handler's data as soon as synchronize_rcu() returns.
  76. Important note: for this to work, the architecture in question must
  77. invoke nmi_enter() and nmi_exit() on NMI entry and exit, respectively.
  78. .. _answer_quick_quiz_NMI:
  79. Answer to Quick Quiz:
  80. Why might the rcu_dereference_sched() be necessary on Alpha, given that the code referenced by the pointer is read-only?
  81. The caller to set_nmi_callback() might well have
  82. initialized some data that is to be used by the new NMI
  83. handler. In this case, the rcu_dereference_sched() would
  84. be needed, because otherwise a CPU that received an NMI
  85. just after the new handler was set might see the pointer
  86. to the new NMI handler, but the old pre-initialized
  87. version of the handler's data.
  88. This same sad story can happen on other CPUs when using
  89. a compiler with aggressive pointer-value speculation
  90. optimizations.
  91. More important, the rcu_dereference_sched() makes it
  92. clear to someone reading the code that the pointer is
  93. being protected by RCU-sched.