Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> writes: > Sean Christopherson <seanjc@xxxxxxxxxx> writes: > >> On Mon, Mar 15, 2021, Vitaly Kuznetsov wrote: >>> Create an infrastructure for tracking Hyper-V TSC page status, i.e. if it >>> was updated from guest/host side or if we've failed to set it up (because >>> e.g. guest wrote some garbage to HV_X64_MSR_REFERENCE_TSC) and there's no >>> need to retry. >>> >>> Also, in a hypothetical situation when we are in 'always catchup' mode for >>> TSC we can now avoid contending 'hv->hv_lock' on every guest enter by >>> setting the state to HV_TSC_PAGE_BROKEN after compute_tsc_page_parameters() >>> returns false. >>> >>> Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> >>> --- >>> diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c >>> index eefb85b86fe8..2a8d078b16cb 100644 >>> --- a/arch/x86/kvm/hyperv.c >>> +++ b/arch/x86/kvm/hyperv.c >>> @@ -1087,7 +1087,7 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm, >>> BUILD_BUG_ON(sizeof(tsc_seq) != sizeof(hv->tsc_ref.tsc_sequence)); >>> BUILD_BUG_ON(offsetof(struct ms_hyperv_tsc_page, tsc_sequence) != 0); >>> >>> - if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE)) >>> + if (hv->hv_tsc_page_status == HV_TSC_PAGE_BROKEN) >>> return; >>> >>> mutex_lock(&hv->hv_lock); >> >> ... >> >>> @@ -1133,6 +1133,12 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm, >>> hv->tsc_ref.tsc_sequence = tsc_seq; >>> kvm_write_guest(kvm, gfn_to_gpa(gfn), >>> &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)); >>> + >>> + hv->hv_tsc_page_status = HV_TSC_PAGE_SET; >>> + goto out_unlock; >>> + >>> +out_err: >>> + hv->hv_tsc_page_status = HV_TSC_PAGE_BROKEN; >>> out_unlock: >>> mutex_unlock(&hv->hv_lock); >>> } >>> @@ -1193,8 +1199,13 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, >>> } >>> case HV_X64_MSR_REFERENCE_TSC: >>> hv->hv_tsc_page = data; >>> - if (hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE) >>> + if (hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE) { >>> + if (!host) >>> + hv->hv_tsc_page_status = HV_TSC_PAGE_GUEST_CHANGED; >>> + else >>> + hv->hv_tsc_page_status = HV_TSC_PAGE_HOST_CHANGED; >> >> Writing the status without taking hv->hv_lock could cause the update to be lost, >> e.g. if a different vCPU fails kvm_hv_setup_tsc_page() at the same time, its >> write to set status to HV_TSC_PAGE_BROKEN would race with this write. >> > > Oh, right you are, the lock was somewhere in my brain :-) Will do in > v2. Actually no, kvm_hv_set_msr_pw() is only called from kvm_hv_set_msr_common() with hv->hv_lock held so we're already synchronized. ... and of course I figured that our by putting another mutex_lock()/mutex_unlock() here and then wondering why everything hangs :-) > >>> kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); >>> + } >>> break; >>> case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: >>> return kvm_hv_msr_set_crash_data(kvm, >>> -- >>> 2.30.2 >>> >> -- Vitaly