[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <87h69dg4og.fsf@redhat.com>
Date: Tue, 15 Oct 2024 10:18:23 +0200
From: Vitaly Kuznetsov <vkuznets@...hat.com>
To: Nikolas Wipper <nik.wipper@....de>, Nikolas Wipper <nikwip@...zon.de>
Cc: Nicolas Saenz Julienne <nsaenz@...zon.com>, Alexander Graf
<graf@...zon.de>, James Gowans <jgowans@...zon.com>,
nh-open-source@...zon.com, Sean Christopherson <seanjc@...gle.com>, Paolo
Bonzini <pbonzini@...hat.com>, Thomas Gleixner <tglx@...utronix.de>, Ingo
Molnar <mingo@...hat.com>, Borislav Petkov <bp@...en8.de>, Dave Hansen
<dave.hansen@...ux.intel.com>, linux-kernel@...r.kernel.org,
kvm@...r.kernel.org, x86@...nel.org, linux-doc@...r.kernel.org,
linux-kselftest@...r.kernel.org
Subject: Re: [PATCH 2/7] KVM: x86: Implement Hyper-V's vCPU suspended state
Nikolas Wipper <nik.wipper@....de> writes:
> On 10.10.24 10:57, Vitaly Kuznetsov wrote:
...
>>> int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu);
>>> +
>>> +static inline bool kvm_hv_vcpu_suspended(struct kvm_vcpu *vcpu)
>>> +{
>>> + return vcpu->arch.hyperv_enabled &&
>>> + READ_ONCE(vcpu->arch.hyperv->suspended);
>>
>> I don't think READ_ONCE() means anything here, does it?
>>
>
> It does prevent compiler optimisations and is actually required[1]. Also
> it makes clear that this variable is shared, and may be accessed from
> remote CPUs.
>
> [1] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0124r6.html#Variable%20Access
It certainly does no harm but I think if we follow 'Loads from and
stores to shared (but non-atomic) variables should be protected with the
READ_ONCE(), WRITE_ONCE()' rule literally we will need to sprinkle them
all over KVM/kernel ;-) And personally, this makes reading the code
harder.
To my (very limited) knowledge, we really need READ_ONCE()s when we need
to have some sort of a serialization, e.g. the moment when this read
happens actually makes a difference. If we can e.g. use a local variable
in the beginning of a function and replace all READ_ONCE()s with
reading this local variable -- then we don't need READ_ONCE()s and are
OK with possible compiler optimizations. Similar (reversed) thoughts go
to WRITE_ONCE().
I think it's OK to keep them but it would be nice (not mandatory IMO,
but nice) to have a comment describing which particular synchronization
we are achieving (== the compiler optimization scenario we are protecting
against).
In this particular case, kvm_hv_vcpu_suspended() is inline so I briefly
looked at all kvm_hv_vcpu_suspended() call sites (there are three) in
your series but couldn't think of a place where the READ_ONCE() makes a
real difference. kvm_hv_hypercall_complete() looks pretty safe
anyway. kvm_hv_vcpu_unsuspend_tlb_flush() will be simplified
significantly if we merge 'suspended' with 'waiting_on': instead of
kvm_for_each_vcpu(i, v, vcpu->kvm) {
vcpu_hv = to_hv_vcpu(v);
if (kvm_hv_vcpu_suspended(v) &&
READ_ONCE(vcpu_hv->waiting_on) == vcpu->vcpu_id) {
...
you will have just
kvm_for_each_vcpu(i, v, vcpu->kvm) {
vcpu_hv = to_hv_vcpu(v);
if (vcpu_hv && vcpu_hv->waiting_on == vcpu->vcpu_id) {
...
(and yes, I also think that READ_ONCE() is superfluous here, as real
(non-speculative) write below can't happen _before_ the check )
The last one, kvm_vcpu_running(), should also be indifferent to
READ_ONCE() in kvm_hv_vcpu_suspended(). I may had missed something, of
course, but I hope you got my line of thought.
--
Vitaly
Powered by blists - more mailing lists