On Fri, 2023-05-12 at 16:50 -0700, Sean Christopherson wrote: > Provide dedicated helpers to (un)register virt hooks used during an > emergency crash/reboot, and WARN if there is an attempt to overwrite > the registered callback, or an attempt to do an unpaired unregister. > > Opportunsitically use rcu_assign_pointer() instead of RCU_INIT_POINTER(), > mainly so that the set/unset paths are more symmetrical, but also because > any performance gains from using RCU_INIT_POINTER() are meaningless for > this code. > > Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> Reviewed-by: Kai Huang <kai.huang@xxxxxxxxx> > --- > arch/x86/include/asm/reboot.h | 5 +++-- > arch/x86/kernel/reboot.c | 30 ++++++++++++++++++++++++------ > arch/x86/kvm/vmx/vmx.c | 6 ++---- > 3 files changed, 29 insertions(+), 12 deletions(-) > > diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h > index 2551baec927d..d9a38d379d18 100644 > --- a/arch/x86/include/asm/reboot.h > +++ b/arch/x86/include/asm/reboot.h > @@ -25,8 +25,9 @@ void __noreturn machine_real_restart(unsigned int type); > #define MRR_BIOS 0 > #define MRR_APM 1 > > -typedef void crash_vmclear_fn(void); > -extern crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; > +typedef void (cpu_emergency_virt_cb)(void); > +void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback); > +void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback); > void cpu_emergency_disable_virtualization(void); > > typedef void (*nmi_shootdown_cb)(int, struct pt_regs*); > diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c > index 299b970e5f82..739e09527dbb 100644 > --- a/arch/x86/kernel/reboot.c > +++ b/arch/x86/kernel/reboot.c > @@ -794,17 +794,35 @@ void machine_crash_shutdown(struct pt_regs *regs) > * > * protected by rcu. > */ > -crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss; > -EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss); > +static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback; > + > +void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback) > +{ > + if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback))) > + return; > + > + rcu_assign_pointer(cpu_emergency_virt_callback, callback); > +} > +EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback); > + > +void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback) > +{ > + if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback)) > + return; > + > + rcu_assign_pointer(cpu_emergency_virt_callback, NULL); > + synchronize_rcu(); > +} > +EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback); > > static inline void cpu_crash_vmclear_loaded_vmcss(void) > { > - crash_vmclear_fn *do_vmclear_operation = NULL; > + cpu_emergency_virt_cb *callback; > > rcu_read_lock(); > - do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss); > - if (do_vmclear_operation) > - do_vmclear_operation(); > + callback = rcu_dereference(cpu_emergency_virt_callback); > + if (callback) > + callback(); > rcu_read_unlock(); > } > > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c > index 317f72baf0c3..fc9cdb4114cc 100644 > --- a/arch/x86/kvm/vmx/vmx.c > +++ b/arch/x86/kvm/vmx/vmx.c > @@ -8547,8 +8547,7 @@ static void __vmx_exit(void) > { > allow_smaller_maxphyaddr = false; > > - RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL); > - synchronize_rcu(); > + cpu_emergency_unregister_virt_callback(crash_vmclear_local_loaded_vmcss); > > vmx_cleanup_l1d_flush(); > } > @@ -8598,8 +8597,7 @@ static int __init vmx_init(void) > pi_init_cpu(cpu); > } > > - rcu_assign_pointer(crash_vmclear_loaded_vmcss, > - crash_vmclear_local_loaded_vmcss); > + cpu_emergency_register_virt_callback(crash_vmclear_local_loaded_vmcss); > > vmx_check_vmcs12_offsets(); > > -- > 2.40.1.606.ga4b1b128d6-goog >