Use READ_ONCE() and WRITE_ONCE() for runtime accesses to poll_evtchn. This marks the intentionally concurrent scalar accesses and prevents the compiler from splitting, merging, or inventing accesses. kvm_xen_schedop_poll() publishes the single port, or -1 for multiple ports, before setting poll_mask and halting the vCPU. Event delivery can call kvm_xen_check_poller() on another CPU while the vCPU thread publishes that value or resets the field to zero after returning from kvm_vcpu_halt(): vCPU thread event delivery thread ----------- --------------------- poll_evtchn = port set_bit(poll_mask) kvm_vcpu_halt() poll_evtchn = READ poll_evtchn = 0 clear_bit(poll_mask) The plain read and writes therefore race. KCSAN reported: BUG: KCSAN: data-race in kvm_xen_hypercall / kvm_xen_set_evtchn_fast read to 0xffff888112f55af0 of 4 bytes by task 98: kvm_xen_set_evtchn_fast+0x204/0x7c0 kvm_xen_hvm_evtchn_send+0xab/0x100 kvm_arch_vm_ioctl+0xb31/0xd90 kvm_vm_ioctl+0xf42/0x16c0 write to 0xffff888112f55af0 of 4 bytes by task 96: kvm_xen_hypercall+0xd8d/0xf50 kvm_emulate_hypercall+0x157/0x1d0 vmx_handle_exit+0x40f/0xae0 vcpu_run+0x137f/0x27d0 kvm_arch_vcpu_ioctl_run+0x5a5/0x970 The field is an aligned int on x86. Access annotations preserve the existing matching, callback, and poll-mask control flow while making the single-copy access requirement explicit. Fixes: 1a65105a5aba ("KVM: x86/xen: handle PV spinlocks slowpath") Cc: stable@vger.kernel.org Signed-off-by: Chengfeng Ye --- arch/x86/kvm/xen.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index eae17141773a..cd15d2379616 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -1536,9 +1536,9 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode, } if (sched_poll.nr_ports == 1) - vcpu->arch.xen.poll_evtchn = port; + WRITE_ONCE(vcpu->arch.xen.poll_evtchn, port); else - vcpu->arch.xen.poll_evtchn = -1; + WRITE_ONCE(vcpu->arch.xen.poll_evtchn, -1); set_bit(vcpu->vcpu_idx, vcpu->kvm->arch.xen.poll_mask); @@ -1557,7 +1557,7 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode, kvm_set_mp_state(vcpu, KVM_MP_STATE_RUNNABLE); } - vcpu->arch.xen.poll_evtchn = 0; + WRITE_ONCE(vcpu->arch.xen.poll_evtchn, 0); *r = 0; out: /* Really, this is only needed in case of timeout */ @@ -1773,7 +1773,7 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu) static void kvm_xen_check_poller(struct kvm_vcpu *vcpu, int port) { - int poll_evtchn = vcpu->arch.xen.poll_evtchn; + int poll_evtchn = READ_ONCE(vcpu->arch.xen.poll_evtchn); if ((poll_evtchn == port || poll_evtchn == -1) && test_and_clear_bit(vcpu->vcpu_idx, vcpu->kvm->arch.xen.poll_mask)) { base-commit: 388b607d107c07aaade04c7f22f344cab6bdccd3 -- 2.43.0