kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vitaly Kuznetsov <vkuznets@redhat.com>
To: Haiwei Li <lihaiwei.kernel@gmail.com>
Cc: wanpengli@tencent.com, x86@kernel.org, kvm@vger.kernel.org,
	pbonzini@redhat.com
Subject: Re: Some warnings occur in hyperv.c.
Date: Wed, 18 Mar 2020 10:54:25 +0100	[thread overview]
Message-ID: <87wo7i2dke.fsf@vitty.brq.redhat.com> (raw)
In-Reply-To: <a46510c9-b629-805b-41e8-dbbbf626bd78@gmail.com>

Haiwei Li <lihaiwei.kernel@gmail.com> writes:

> On 2020/3/12 18:47, Vitaly Kuznetsov wrote:
>> Haiwei Li <lihaiwei.kernel@gmail.com> writes:
>> 
>>> Hi, When i build kvm, some warnings occur. Just like:
>>>
>>> /home/kernel/data/linux/arch/x86/kvm//hyperv.c: In function ‘kvm_hv_flush_tlb’:
>>> /home/kernel/data/linux/arch/x86/kvm//hyperv.c:1436:1: warning: the
>>> frame size of 1064 bytes is larger than 1024 bytes
>>> [-Wframe-larger-than=]
>>>   }
>>>   ^
>>> /home/kernel/data/linux/arch/x86/kvm//hyperv.c: In function ‘kvm_hv_send_ipi’:
>>> /home/kernel/data/linux/arch/x86/kvm//hyperv.c:1529:1: warning: the
>>> frame size of 1112 bytes is larger than 1024 bytes
>>> [-Wframe-larger-than=]
>>>   }
>>>   ^
>>>
>>> Then i get the two functions in hyperv.c. Like:
>>>
>>> static u64 kvm_hv_send_ipi(struct kvm_vcpu *current_vcpu, u64 ingpa, u64 outgpa,
>>>                             bool ex, bool fast)
>>> {
>>>          struct kvm *kvm = current_vcpu->kvm;
>>>          struct hv_send_ipi_ex send_ipi_ex;
>>>          struct hv_send_ipi send_ipi;
>>>          u64 vp_bitmap[KVM_HV_MAX_SPARSE_VCPU_SET_BITS];
>>>          DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS);
>>>          unsigned long *vcpu_mask;
>>>          unsigned long valid_bank_mask;
>>>          u64 sparse_banks[64];
>>>          int sparse_banks_len;
>>>          u32 vector;
>>>          bool all_cpus;
>>>
>>> static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa,
>>>                              u16 rep_cnt, bool ex)
>>> {
>>>          struct kvm *kvm = current_vcpu->kvm;
>>>          struct kvm_vcpu_hv *hv_vcpu = &current_vcpu->arch.hyperv;
>>>          struct hv_tlb_flush_ex flush_ex;
>>>          struct hv_tlb_flush flush;
>>>          u64 vp_bitmap[KVM_HV_MAX_SPARSE_VCPU_SET_BITS];
>>>          DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS);
>>>          unsigned long *vcpu_mask;
>>>          u64 valid_bank_mask;
>>>          u64 sparse_banks[64];
>>>          int sparse_banks_len;
>>>          bool all_cpus;
>>>
>>> The definition of sparse_banks for X86_64 is 512 B.  So i tried to
>>> refactor it by
>>> defining it for both tlb and ipi. But no preempt disable in the flow.
>>> How can i do?
>> 
>> I don't think preemption is a problem here if you define a per-vCPU
>> buffer: we can never switch to serving some new request for the same
>> vCPU before finishing the previous one so this is naturally serialized.
>> 
>> To not waste memory I'd suggest you allocate this buffer dinamically
>> upon first usage. We can also have a union for struct
>> hv_tlb_flush*/struct hv_send_ipi* as these also can't be used
>> simultaneously.
>> 
>
> Hi, Vitaly, thanks for your suggestions. I made some modification and 
> basic tests. It works well. I'm not sure the correctness. Will you 
> please do a review? thanks!
>
> From: Haiwei Li <lihaiwei@tencent.com>
>
> When building kvm:
> /home/kernel/data/linux/arch/x86/kvm//hyperv.c: In function 
> ‘kvm_hv_flush_tlb’:
> /home/kernel/data/linux/arch/x86/kvm//hyperv.c:1436:1: warning: the
> frame size of 1064 bytes is larger than 1024 bytes
> [-Wframe-larger-than=]
>   }
>   ^
> /home/kernel/data/linux/arch/x86/kvm//hyperv.c: In function 
> ‘kvm_hv_send_ipi’:
> /home/kernel/data/linux/arch/x86/kvm//hyperv.c:1529:1: warning: the
> frame size of 1112 bytes is larger than 1024 bytes
> [-Wframe-larger-than=]
>   }
>   ^
>
> Pre-allocate 1 variable per cpu for both hv_flush_tlb and hv_send_ipi. 
> Union for struct hv_tlb_flush*/struct hv_send_ipi*.
>
> Signed-off-by: Haiwei Li <lihaiwei@tencent.com>
> ---
>   arch/x86/include/asm/hyperv-tlfs.h | 10 ++++++
>   arch/x86/kvm/hyperv.c              | 67 
> ++++++++++++++++++++------------------
>   2 files changed, 45 insertions(+), 32 deletions(-)
>
> diff --git a/arch/x86/include/asm/hyperv-tlfs.h 
> b/arch/x86/include/asm/hyperv-tlfs.h
> index 92abc1e..f2d53e9 100644
> --- a/arch/x86/include/asm/hyperv-tlfs.h
> +++ b/arch/x86/include/asm/hyperv-tlfs.h
> @@ -854,6 +854,11 @@ struct hv_send_ipi_ex {
>   	struct hv_vpset vp_set;
>   } __packed;
>
> +union hv_send_ipi_type {
> +	struct hv_send_ipi send_ipi;
> +	struct hv_send_ipi_ex send_ipi_ex;
> +};
> +

Please split the patch into two: first to unionize these and
hv_tlb_flush_* structures and second to deal with sparse CPU banks.


>   /* HvFlushGuestPhysicalAddressSpace hypercalls */
>   struct hv_guest_mapping_flush {
>   	u64 address_space;
> @@ -906,6 +911,11 @@ struct hv_tlb_flush_ex {
>   	u64 gva_list[];
>   } __packed;
>
> +union hv_tlb_flush_type {
> +	struct hv_tlb_flush flush;
> +	struct hv_tlb_flush_ex flush_ex;
> +};
> +
>   struct hv_partition_assist_pg {
>   	u32 tlb_lock_count;
>   };
> diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
> index a86fda7..34cd57b 100644
> --- a/arch/x86/kvm/hyperv.c
> +++ b/arch/x86/kvm/hyperv.c
> @@ -1351,30 +1351,33 @@ static __always_inline unsigned long 
> *sparse_set_to_vcpu_mask(
>   	return vcpu_bitmap;
>   }
>
> +static DEFINE_PER_CPU(u64 [64], __hv_sparse_banks);
> +

I don't think it's going to work well: if you make this per-CPU (not
per-vCPU!) you'll have to deal with preemption which can actually
happen (and then requests for different vCPUs and/or even VMs can
collide).

I think it would be better to *dynamically* (lazily?) allocate the
buffer in 'struct kvm_vcpu_hv'.

>   static u64 kvm_hv_flush_tlb(struct kvm_vcpu *current_vcpu, u64 ingpa,
>   			    u16 rep_cnt, bool ex)
>   {
>   	struct kvm *kvm = current_vcpu->kvm;
>   	struct kvm_vcpu_hv *hv_vcpu = &current_vcpu->arch.hyperv;
> -	struct hv_tlb_flush_ex flush_ex;
> -	struct hv_tlb_flush flush;
> +	union hv_tlb_flush_type tlb_flush;
>   	u64 vp_bitmap[KVM_HV_MAX_SPARSE_VCPU_SET_BITS];
>   	DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS);
>   	unsigned long *vcpu_mask;
>   	u64 valid_bank_mask;
> -	u64 sparse_banks[64];
> +	u64 *sparse_banks = this_cpu_ptr(__hv_sparse_banks);
>   	int sparse_banks_len;
>   	bool all_cpus;
>
>   	if (!ex) {
> -		if (unlikely(kvm_read_guest(kvm, ingpa, &flush, sizeof(flush))))
> +		if (unlikely(kvm_read_guest(kvm, ingpa, &tlb_flush.flush,
> +					    sizeof(tlb_flush.flush))))
>   			return HV_STATUS_INVALID_HYPERCALL_INPUT;
>
> -		trace_kvm_hv_flush_tlb(flush.processor_mask,
> -				       flush.address_space, flush.flags);
> +		trace_kvm_hv_flush_tlb(tlb_flush.flush.processor_mask,
> +				       tlb_flush.flush.address_space,
> +				       tlb_flush.flush.flags);
>
>   		valid_bank_mask = BIT_ULL(0);
> -		sparse_banks[0] = flush.processor_mask;
> +		sparse_banks[0] = tlb_flush.flush.processor_mask;
>
>   		/*
>   		 * Work around possible WS2012 bug: it sends hypercalls
> @@ -1383,20 +1386,20 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu 
> *current_vcpu, u64 ingpa,
>   		 * we don't. Let's treat processor_mask == 0 same as
>   		 * HV_FLUSH_ALL_PROCESSORS.
>   		 */
> -		all_cpus = (flush.flags & HV_FLUSH_ALL_PROCESSORS) ||
> -			flush.processor_mask == 0;
> +		all_cpus = (tlb_flush.flush.flags & HV_FLUSH_ALL_PROCESSORS) ||
> +			tlb_flush.flush.processor_mask == 0;
>   	} else {
> -		if (unlikely(kvm_read_guest(kvm, ingpa, &flush_ex,
> -					    sizeof(flush_ex))))
> +		if (unlikely(kvm_read_guest(kvm, ingpa, &tlb_flush.flush_ex,
> +					    sizeof(tlb_flush.flush_ex))))
>   			return HV_STATUS_INVALID_HYPERCALL_INPUT;
>
> -		trace_kvm_hv_flush_tlb_ex(flush_ex.hv_vp_set.valid_bank_mask,
> -					  flush_ex.hv_vp_set.format,
> -					  flush_ex.address_space,
> -					  flush_ex.flags);
> +		trace_kvm_hv_flush_tlb_ex(tlb_flush.flush_ex.hv_vp_set.valid_bank_mask,
> +					  tlb_flush.flush_ex.hv_vp_set.format,
> +					  tlb_flush.flush_ex.address_space,
> +					  tlb_flush.flush_ex.flags);
>
> -		valid_bank_mask = flush_ex.hv_vp_set.valid_bank_mask;
> -		all_cpus = flush_ex.hv_vp_set.format !=
> +		valid_bank_mask = tlb_flush.flush_ex.hv_vp_set.valid_bank_mask;
> +		all_cpus = tlb_flush.flush_ex.hv_vp_set.format !=
>   			HV_GENERIC_SET_SPARSE_4K;
>
>   		sparse_banks_len =
> @@ -1458,24 +1461,24 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu 
> *current_vcpu, u64 ingpa, u64 outgpa,
>   			   bool ex, bool fast)
>   {
>   	struct kvm *kvm = current_vcpu->kvm;
> -	struct hv_send_ipi_ex send_ipi_ex;
> -	struct hv_send_ipi send_ipi;
> +	union hv_send_ipi_type hv_ipi;
>   	u64 vp_bitmap[KVM_HV_MAX_SPARSE_VCPU_SET_BITS];
>   	DECLARE_BITMAP(vcpu_bitmap, KVM_MAX_VCPUS);
>   	unsigned long *vcpu_mask;
>   	unsigned long valid_bank_mask;
> -	u64 sparse_banks[64];
> +	u64 *sparse_banks = this_cpu_ptr(__hv_sparse_banks);
>   	int sparse_banks_len;
>   	u32 vector;
>   	bool all_cpus;
>
>   	if (!ex) {
>   		if (!fast) {
> -			if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi,
> -						    sizeof(send_ipi))))
> +			if (unlikely(kvm_read_guest(kvm, ingpa,
> +						    &hv_ipi.send_ipi,
> +						    sizeof(hv_ipi.send_ipi))))
>   				return HV_STATUS_INVALID_HYPERCALL_INPUT;
> -			sparse_banks[0] = send_ipi.cpu_mask;
> -			vector = send_ipi.vector;
> +			sparse_banks[0] = hv_ipi.send_ipi.cpu_mask;
> +			vector = hv_ipi.send_ipi.vector;
>   		} else {
>   			/* 'reserved' part of hv_send_ipi should be 0 */
>   			if (unlikely(ingpa >> 32 != 0))
> @@ -1488,20 +1491,20 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu 
> *current_vcpu, u64 ingpa, u64 outgpa,
>
>   		trace_kvm_hv_send_ipi(vector, sparse_banks[0]);
>   	} else {
> -		if (unlikely(kvm_read_guest(kvm, ingpa, &send_ipi_ex,
> -					    sizeof(send_ipi_ex))))
> +		if (unlikely(kvm_read_guest(kvm, ingpa, &hv_ipi.send_ipi_ex,
> +					    sizeof(hv_ipi.send_ipi_ex))))
>   			return HV_STATUS_INVALID_HYPERCALL_INPUT;
>
> -		trace_kvm_hv_send_ipi_ex(send_ipi_ex.vector,
> -					 send_ipi_ex.vp_set.format,
> -					 send_ipi_ex.vp_set.valid_bank_mask);
> +		trace_kvm_hv_send_ipi_ex(hv_ipi.send_ipi_ex.vector,
> +				hv_ipi.send_ipi_ex.vp_set.format,
> +				hv_ipi.send_ipi_ex.vp_set.valid_bank_mask);
>
> -		vector = send_ipi_ex.vector;
> -		valid_bank_mask = send_ipi_ex.vp_set.valid_bank_mask;
> +		vector = hv_ipi.send_ipi_ex.vector;
> +		valid_bank_mask = hv_ipi.send_ipi_ex.vp_set.valid_bank_mask;
>   		sparse_banks_len = bitmap_weight(&valid_bank_mask, 64) *
>   			sizeof(sparse_banks[0]);
>
> -		all_cpus = send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL;
> +		all_cpus = hv_ipi.send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL;
>
>   		if (!sparse_banks_len)
>   			goto ret_success;

-- 
Vitaly


      reply	other threads:[~2020-03-18  9:54 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-12 10:20 Some warnings occur in hyperv.c Haiwei Li
2020-03-12 10:47 ` Vitaly Kuznetsov
2020-03-18  0:59   ` Haiwei Li
2020-03-18  9:54     ` Vitaly Kuznetsov [this message]

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=87wo7i2dke.fsf@vitty.brq.redhat.com \
    --to=vkuznets@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=lihaiwei.kernel@gmail.com \
    --cc=pbonzini@redhat.com \
    --cc=wanpengli@tencent.com \
    --cc=x86@kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).