All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vitaly Kuznetsov <vkuznets@redhat.com>
To: Sean Christopherson <seanjc@google.com>
Cc: kvm@vger.kernel.org, Paolo Bonzini <pbonzini@redhat.com>,
	Wanpeng Li <wanpengli@tencent.com>,
	Jim Mattson <jmattson@google.com>,
	Michael Kelley <mikelley@microsoft.com>,
	Siddharth Chandrasekaran <sidcha@amazon.de>,
	linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 02/34] KVM: x86: hyper-v: Introduce TLB flush ring
Date: Tue, 17 May 2022 15:31:58 +0200	[thread overview]
Message-ID: <87pmkcuvxt.fsf@redhat.com> (raw)
In-Reply-To: <YoKnOqR68SaaPCdT@google.com>

Sean Christopherson <seanjc@google.com> writes:

> On Thu, Apr 14, 2022, Vitaly Kuznetsov wrote:
>> To allow flushing individual GVAs instead of always flushing the whole
>> VPID a per-vCPU structure to pass the requests is needed. Introduce a
>> simple ring write-locked structure to hold two types of entries:
>> individual GVA (GFN + up to 4095 following GFNs in the lower 12 bits)
>> and 'flush all'.
>> 
>> The queuing rule is: if there's not enough space on the ring to put
>> the request and leave at least 1 entry for 'flush all' - put 'flush
>> all' entry.
>> 
>> The size of the ring is arbitrary set to '16'.
>> 
>> Note, kvm_hv_flush_tlb() only queues 'flush all' entries for now so
>> there's very small functional change but the infrastructure is
>> prepared to handle individual GVA flush requests.
>> 
>> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
>> ---
>>  arch/x86/include/asm/kvm_host.h | 16 +++++++
>>  arch/x86/kvm/hyperv.c           | 83 +++++++++++++++++++++++++++++++++
>>  arch/x86/kvm/hyperv.h           | 13 ++++++
>>  arch/x86/kvm/x86.c              |  5 +-
>>  arch/x86/kvm/x86.h              |  1 +
>>  5 files changed, 116 insertions(+), 2 deletions(-)
>> 
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index 1de3ad9308d8..b4dd2ff61658 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -578,6 +578,20 @@ struct kvm_vcpu_hv_synic {
>>  	bool dont_zero_synic_pages;
>>  };
>>  
>> +#define KVM_HV_TLB_FLUSH_RING_SIZE (16)
>> +
>> +struct kvm_vcpu_hv_tlb_flush_entry {
>> +	u64 addr;
>
> "addr" misleading, this is overloaded to be both the virtual address and the count.
> I think we make it a moot point, but it led me astray in thinkin we could use the
> lower 12 bits for flags... until I realized those bits are already in use.
>
>> +	u64 flush_all:1;
>> +	u64 pad:63;
>
> This is rather odd, why not just use a bool?  

My initial plan was to eventually put more flags here, i.e. there are
two additional flags which we don't currently handle:

HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES (as we don't actually look at
 HV_ADDRESS_SPACE_ID)
HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY

> But why even have a "flush_all" field, can't we just use a magic value
> for write_idx to indicate "flush_all"? E.g. either an explicit #define
> or -1.

Sure, a magic value would do too and will allow us to make 'struct
kvm_vcpu_hv_tlb_flush_entry' 8 bytes instead of 16 (for the time being
as if we are to add HV_ADDRESS_SPACE_ID/additional flags the net win is
going to be zero).

>
> Writers set write_idx to -1 to indicate "flush all", vCPU/reader goes straight
> to "flush all" if write_idx is -1/invalid.  That way, future writes can simply do
> nothing until read_idx == write_idx, and the vCPU/reader avoids unnecessary flushes
> if there's a "flush all" pending and other valid entries in the ring.
>
> And it allows deferring the "flush all" until the ring is truly full (unless there's
> an off-by-one / wraparound edge case I'm missing, which is likely...).

Thanks for the patch! I am, however, going to look at Maxim's suggestion
to use 'kfifo' to avoid all these uncertainties, funky locking etc. At
first glance it has everything I need here.

>
> ---
>  arch/x86/include/asm/kvm_host.h |  8 +-----
>  arch/x86/kvm/hyperv.c           | 47 +++++++++++++--------------------
>  2 files changed, 19 insertions(+), 36 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index b6b9a71a4591..bb45cc383ce4 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -605,16 +605,10 @@ enum hv_tlb_flush_rings {
>  	HV_NR_TLB_FLUSH_RINGS,
>  };
>
> -struct kvm_vcpu_hv_tlb_flush_entry {
> -	u64 addr;
> -	u64 flush_all:1;
> -	u64 pad:63;
> -};
> -
>  struct kvm_vcpu_hv_tlb_flush_ring {
>  	int read_idx, write_idx;
>  	spinlock_t write_lock;
> -	struct kvm_vcpu_hv_tlb_flush_entry entries[KVM_HV_TLB_FLUSH_RING_SIZE];
> +	u64 entries[KVM_HV_TLB_FLUSH_RING_SIZE];
>  };
>
>  /* Hyper-V per vcpu emulation context */
> diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
> index 1d6927538bc7..56f06cf85282 100644
> --- a/arch/x86/kvm/hyperv.c
> +++ b/arch/x86/kvm/hyperv.c
> @@ -1837,10 +1837,13 @@ static int kvm_hv_get_tlb_flush_entries(struct kvm *kvm, struct kvm_hv_hcall *hc
>  static inline int hv_tlb_flush_ring_free(struct kvm_vcpu_hv *hv_vcpu,
>  					 int read_idx, int write_idx)
>  {
> +	if (write_idx < 0)
> +		return 0;
> +
>  	if (write_idx >= read_idx)
> -		return KVM_HV_TLB_FLUSH_RING_SIZE - (write_idx - read_idx) - 1;
> +		return KVM_HV_TLB_FLUSH_RING_SIZE - (write_idx - read_idx);
>
> -	return read_idx - write_idx - 1;
> +	return read_idx - write_idx;
>  }
>
>  static void hv_tlb_flush_ring_enqueue(struct kvm_vcpu *vcpu,
> @@ -1869,6 +1872,9 @@ static void hv_tlb_flush_ring_enqueue(struct kvm_vcpu *vcpu,
>  	 */
>  	write_idx = tlb_flush_ring->write_idx;
>
> +	if (write_idx < 0 && read_idx == write_idx)
> +		read_idx = write_idx = 0;
> +
>  	ring_free = hv_tlb_flush_ring_free(hv_vcpu, read_idx, write_idx);
>  	/* Full ring always contains 'flush all' entry */
>  	if (!ring_free)
> @@ -1879,21 +1885,13 @@ static void hv_tlb_flush_ring_enqueue(struct kvm_vcpu *vcpu,
>  	 * entry in case another request comes in. In case there's not enough
>  	 * space, just put 'flush all' entry there.
>  	 */
> -	if (!count || count >= ring_free - 1 || !entries) {
> -		tlb_flush_ring->entries[write_idx].addr = 0;
> -		tlb_flush_ring->entries[write_idx].flush_all = 1;
> -		/*
> -		 * Advance write index only after filling in the entry to
> -		 * synchronize with lockless reader.
> -		 */
> -		smp_wmb();
> -		tlb_flush_ring->write_idx = (write_idx + 1) % KVM_HV_TLB_FLUSH_RING_SIZE;
> +	if (!count || count > ring_free - 1 || !entries) {
> +		tlb_flush_ring->write_idx = -1;
>  		goto out_unlock;
>  	}
>
>  	for (i = 0; i < count; i++) {
> -		tlb_flush_ring->entries[write_idx].addr = entries[i];
> -		tlb_flush_ring->entries[write_idx].flush_all = 0;
> +		tlb_flush_ring->entries[write_idx] = entries[i];
>  		write_idx = (write_idx + 1) % KVM_HV_TLB_FLUSH_RING_SIZE;
>  	}
>  	/*
> @@ -1911,7 +1909,6 @@ void kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
>  {
>  	struct kvm_vcpu_hv_tlb_flush_ring *tlb_flush_ring;
>  	struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
> -	struct kvm_vcpu_hv_tlb_flush_entry *entry;
>  	int read_idx, write_idx;
>  	u64 address;
>  	u32 count;
> @@ -1940,26 +1937,18 @@ void kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
>  	/* Pairs with smp_wmb() in hv_tlb_flush_ring_enqueue() */
>  	smp_rmb();
>
> +	if (write_idx < 0) {
> +		kvm_vcpu_flush_tlb_guest(vcpu);
> +		goto out_empty_ring;
> +	}
> +
>  	for (i = read_idx; i != write_idx; i = (i + 1) % KVM_HV_TLB_FLUSH_RING_SIZE) {
> -		entry = &tlb_flush_ring->entries[i];
> -
> -		if (entry->flush_all)
> -			goto out_flush_all;
> -
> -		/*
> -		 * Lower 12 bits of 'address' encode the number of additional
> -		 * pages to flush.
> -		 */
> -		address = entry->addr & PAGE_MASK;
> -		count = (entry->addr & ~PAGE_MASK) + 1;
> +		address = tlb_flush_ring->entries[i] & PAGE_MASK;
> +		count = (tlb_flush_ring->entries[i] & ~PAGE_MASK) + 1;
>  		for (j = 0; j < count; j++)
>  			static_call(kvm_x86_flush_tlb_gva)(vcpu, address + j * PAGE_SIZE);
>  	}
>  	++vcpu->stat.tlb_flush;
> -	goto out_empty_ring;
> -
> -out_flush_all:
> -	kvm_vcpu_flush_tlb_guest(vcpu);
>
>  out_empty_ring:
>  	tlb_flush_ring->read_idx = write_idx;
>
> base-commit: 62592c7c742ae78eb1f1005a63965ece19e6effe
> --
>

-- 
Vitaly


  reply	other threads:[~2022-05-17 13:32 UTC|newest]

Thread overview: 102+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-14 13:19 [PATCH v3 00/34] KVM: x86: hyper-v: Fine-grained TLB flush + L2 TLB flush feature Vitaly Kuznetsov
2022-04-14 13:19 ` [PATCH v3 01/34] KVM: x86: hyper-v: Resurrect dedicated KVM_REQ_HV_TLB_FLUSH flag Vitaly Kuznetsov
2022-05-11 11:18   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 02/34] KVM: x86: hyper-v: Introduce TLB flush ring Vitaly Kuznetsov
2022-05-11 11:19   ` Maxim Levitsky
2022-05-16 14:29     ` Vitaly Kuznetsov
2022-05-16 19:34   ` Sean Christopherson
2022-05-17 13:31     ` Vitaly Kuznetsov [this message]
2022-04-14 13:19 ` [PATCH v3 03/34] KVM: x86: hyper-v: Add helper to read hypercall data for array Vitaly Kuznetsov
2022-05-11 11:20   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 04/34] KVM: x86: hyper-v: Handle HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST{,EX} calls gently Vitaly Kuznetsov
2022-05-11 11:22   ` Maxim Levitsky
2022-05-18  9:39     ` Vitaly Kuznetsov
2022-05-18 14:18       ` Sean Christopherson
2022-05-18 14:43         ` Vitaly Kuznetsov
2022-05-18 14:55           ` Sean Christopherson
2022-05-16 19:41   ` Sean Christopherson
2022-05-17 13:41     ` Vitaly Kuznetsov
2022-04-14 13:19 ` [PATCH v3 05/34] KVM: x86: hyper-v: Expose support for extended gva ranges for flush hypercalls Vitaly Kuznetsov
2022-05-11 11:23   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 06/34] KVM: x86: Prepare kvm_hv_flush_tlb() to handle L2's GPAs Vitaly Kuznetsov
2022-05-11 11:23   ` Maxim Levitsky
2022-05-11 11:23   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 07/34] x86/hyperv: Introduce HV_MAX_SPARSE_VCPU_BANKS/HV_VCPUS_PER_SPARSE_BANK constants Vitaly Kuznetsov
2022-04-25 15:47   ` Wei Liu
2022-04-25 17:34     ` Michael Kelley (LINUX)
2022-04-25 19:09   ` Christophe JAILLET
2022-04-25 19:16   ` Christophe JAILLET
2022-05-03 14:59     ` Vitaly Kuznetsov
2022-05-03 11:11   ` Wei Liu
2022-05-11 11:23   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 08/34] KVM: x86: hyper-v: Use HV_MAX_SPARSE_VCPU_BANKS/HV_VCPUS_PER_SPARSE_BANK instead of raw '64' Vitaly Kuznetsov
2022-05-11 11:24   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 09/34] KVM: x86: hyper-v: Don't use sparse_set_to_vcpu_mask() in kvm_hv_send_ipi() Vitaly Kuznetsov
2022-05-11 11:24   ` Maxim Levitsky
2022-05-16 19:52     ` Sean Christopherson
2022-04-14 13:19 ` [PATCH v3 10/34] KVM: x86: hyper-v: Create a separate ring for L2 TLB flush Vitaly Kuznetsov
2022-05-11 11:24   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 11/34] KVM: x86: hyper-v: Use preallocated buffer in 'struct kvm_vcpu_hv' instead of on-stack 'sparse_banks' Vitaly Kuznetsov
2022-05-11 11:25   ` Maxim Levitsky
2022-05-16 20:05   ` Sean Christopherson
2022-05-17 13:51     ` Vitaly Kuznetsov
2022-05-17 14:04       ` Sean Christopherson
2022-05-17 14:19         ` Vitaly Kuznetsov
2022-04-14 13:19 ` [PATCH v3 12/34] KVM: nVMX: Keep track of hv_vm_id/hv_vp_id when eVMCS is in use Vitaly Kuznetsov
2022-05-11 11:25   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 13/34] KVM: nSVM: Keep track of Hyper-V hv_vm_id/hv_vp_id Vitaly Kuznetsov
2022-05-11 11:27   ` Maxim Levitsky
2022-05-18 12:25     ` Vitaly Kuznetsov
2022-05-18 12:45       ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 14/34] KVM: x86: Introduce .post_hv_l2_tlb_flush() nested hook Vitaly Kuznetsov
2022-05-11 11:32   ` Maxim Levitsky
2022-05-18 12:43     ` Vitaly Kuznetsov
2022-05-18 12:49       ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 15/34] KVM: x86: hyper-v: Introduce kvm_hv_is_tlb_flush_hcall() Vitaly Kuznetsov
2022-05-11 11:25   ` Maxim Levitsky
2022-05-16 20:09   ` Sean Christopherson
2022-04-14 13:19 ` [PATCH v3 16/34] KVM: x86: hyper-v: L2 TLB flush Vitaly Kuznetsov
2022-05-11 11:29   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 17/34] KVM: x86: hyper-v: Introduce fast kvm_hv_l2_tlb_flush_exposed() check Vitaly Kuznetsov
2022-05-11 11:30   ` Maxim Levitsky
2022-05-19 13:25     ` Vitaly Kuznetsov
2022-05-19 13:28       ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 18/34] x86/hyperv: Fix 'struct hv_enlightened_vmcs' definition Vitaly Kuznetsov
2022-05-11 11:30   ` Maxim Levitsky
2022-04-14 13:19 ` [PATCH v3 19/34] KVM: nVMX: hyper-v: Enable L2 TLB flush Vitaly Kuznetsov
2022-05-11 11:31   ` Maxim Levitsky
2022-05-16 20:16     ` Sean Christopherson
2022-04-14 13:19 ` [PATCH v3 20/34] KVM: x86: KVM_REQ_TLB_FLUSH_CURRENT is a superset of KVM_REQ_HV_TLB_FLUSH too Vitaly Kuznetsov
2022-05-11 11:33   ` Maxim Levitsky
2022-05-19  9:12     ` Vitaly Kuznetsov
2022-05-19 23:44       ` Sean Christopherson
2022-04-14 13:20 ` [PATCH v3 21/34] KVM: nSVM: hyper-v: Enable L2 TLB flush Vitaly Kuznetsov
2022-05-11 11:33   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 22/34] KVM: x86: Expose Hyper-V L2 TLB flush feature Vitaly Kuznetsov
2022-05-11 11:34   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 23/34] KVM: selftests: Better XMM read/write helpers Vitaly Kuznetsov
2022-05-11 11:34   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 24/34] KVM: selftests: Hyper-V PV IPI selftest Vitaly Kuznetsov
2022-05-11 11:35   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 25/34] KVM: selftests: Make it possible to replace PTEs with __virt_pg_map() Vitaly Kuznetsov
2022-05-11 11:34   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 26/34] KVM: selftests: Hyper-V PV TLB flush selftest Vitaly Kuznetsov
2022-05-11 12:17   ` Maxim Levitsky
2022-05-24 14:51     ` Vitaly Kuznetsov
2022-04-14 13:20 ` [PATCH v3 27/34] KVM: selftests: Sync 'struct hv_enlightened_vmcs' definition with hyperv-tlfs.h Vitaly Kuznetsov
2022-05-11 12:17   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 28/34] KVM: selftests: nVMX: Allocate Hyper-V partition assist page Vitaly Kuznetsov
2022-05-11 12:17   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 29/34] KVM: selftests: nSVM: Allocate Hyper-V partition assist and VP assist pages Vitaly Kuznetsov
2022-05-11 12:17   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 30/34] KVM: selftests: Sync 'struct hv_vp_assist_page' definition with hyperv-tlfs.h Vitaly Kuznetsov
2022-05-11 12:18   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 31/34] KVM: selftests: evmcs_test: Introduce L2 TLB flush test Vitaly Kuznetsov
2022-05-11 12:18   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 32/34] KVM: selftests: Move Hyper-V VP assist page enablement out of evmcs.h Vitaly Kuznetsov
2022-05-11 12:18   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 33/34] KVM: selftests: hyperv_svm_test: Introduce L2 TLB flush test Vitaly Kuznetsov
2022-05-11 12:19   ` Maxim Levitsky
2022-04-14 13:20 ` [PATCH v3 34/34] KVM: x86: Rename 'enable_direct_tlbflush' to 'enable_l2_tlb_flush' Vitaly Kuznetsov
2022-05-11 12:18   ` Maxim Levitsky
2022-05-03 15:01 ` [PATCH v3 00/34] KVM: x86: hyper-v: Fine-grained TLB flush + L2 TLB flush feature Vitaly Kuznetsov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87pmkcuvxt.fsf@redhat.com \
    --to=vkuznets@redhat.com \
    --cc=jmattson@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-hyperv@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mikelley@microsoft.com \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    --cc=sidcha@amazon.de \
    --cc=wanpengli@tencent.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.