diff mbox series

[v2,5/6] kvm: allocate vcpu pointer array separately

Message ID 20210903130808.30142-6-jgross@suse.com (mailing list archive)
State New, archived
Headers show
Series x86/kvm: add boot parameters for max vcpu configs | expand

Commit Message

Jürgen Groß Sept. 3, 2021, 1:08 p.m. UTC
Prepare support of very large vcpu numbers per guest by moving the
vcpu pointer array out of struct kvm.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- rebase to new kvm_arch_free_vm() implementation
---
 arch/arm64/kvm/arm.c            | 21 +++++++++++++++++++--
 arch/x86/include/asm/kvm_host.h |  5 +----
 arch/x86/kvm/x86.c              | 18 ++++++++++++++++++
 include/linux/kvm_host.h        | 17 +++++++++++++++--
 4 files changed, 53 insertions(+), 8 deletions(-)

Comments

Marc Zyngier Sept. 3, 2021, 2:41 p.m. UTC | #1
On Fri, 03 Sep 2021 14:08:06 +0100,
Juergen Gross <jgross@suse.com> wrote:
> 
> Prepare support of very large vcpu numbers per guest by moving the
> vcpu pointer array out of struct kvm.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
> ---
> V2:
> - rebase to new kvm_arch_free_vm() implementation
> ---
>  arch/arm64/kvm/arm.c            | 21 +++++++++++++++++++--
>  arch/x86/include/asm/kvm_host.h |  5 +----
>  arch/x86/kvm/x86.c              | 18 ++++++++++++++++++
>  include/linux/kvm_host.h        | 17 +++++++++++++++--
>  4 files changed, 53 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 38fff5963d9f..8bb5caeba007 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -293,10 +293,27 @@ long kvm_arch_dev_ioctl(struct file *filp,
>  
>  struct kvm *kvm_arch_alloc_vm(void)
>  {
> +	struct kvm *kvm;
> +
> +	if (!has_vhe())
> +		kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
> +	else
> +		kvm = vzalloc(sizeof(struct kvm));
> +
> +	if (!kvm)
> +		return NULL;
> +
>  	if (!has_vhe())
> -		return kzalloc(sizeof(struct kvm), GFP_KERNEL);
> +		kvm->vcpus = kcalloc(KVM_MAX_VCPUS, sizeof(void *), GFP_KERNEL);
> +	else
> +		kvm->vcpus = vzalloc(KVM_MAX_VCPUS * sizeof(void *));
> +
> +	if (!kvm->vcpus) {
> +		kvm_arch_free_vm(kvm);
> +		kvm = NULL;
> +	}
>  
> -	return vzalloc(sizeof(struct kvm));
> +	return kvm;
>  }
>  
>  int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index f16fadfc030a..6c28d0800208 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1517,10 +1517,7 @@ static inline void kvm_ops_static_call_update(void)
>  }
>  
>  #define __KVM_HAVE_ARCH_VM_ALLOC
> -static inline struct kvm *kvm_arch_alloc_vm(void)
> -{
> -	return __vmalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
> -}
> +struct kvm *kvm_arch_alloc_vm(void);
>  
>  #define __KVM_HAVE_ARCH_VM_FREE
>  void kvm_arch_free_vm(struct kvm *kvm);
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index cc552763f0e4..ff142b6dd00c 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -11126,6 +11126,24 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
>  	static_call(kvm_x86_sched_in)(vcpu, cpu);
>  }
>  
> +struct kvm *kvm_arch_alloc_vm(void)
> +{
> +	struct kvm *kvm;
> +
> +	kvm = __vmalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
> +	if (!kvm)
> +		return NULL;
> +
> +	kvm->vcpus = __vmalloc(KVM_MAX_VCPUS * sizeof(void *),
> +			       GFP_KERNEL_ACCOUNT | __GFP_ZERO);
> +	if (!kvm->vcpus) {
> +		vfree(kvm);
> +		kvm = NULL;
> +	}
> +
> +	return kvm;
> +}
> +
>  void kvm_arch_free_vm(struct kvm *kvm)
>  {
>  	kfree(to_kvm_hv(kvm)->hv_pa_pg);
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index d75e9c2a00b1..9e2a5f1c6f54 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -536,7 +536,7 @@ struct kvm {
>  	struct mutex slots_arch_lock;
>  	struct mm_struct *mm; /* userspace tied to this vm */
>  	struct kvm_memslots __rcu *memslots[KVM_ADDRESS_SPACE_NUM];
> -	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
> +	struct kvm_vcpu **vcpus;

At this stage, I really wonder why we are not using an xarray instead.

I wrote this [1] a while ago, and nothing caught fire. It was also a
net deletion of code...

	M.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/vcpu-xarray
Jürgen Groß Sept. 6, 2021, 4:33 a.m. UTC | #2
On 03.09.21 16:41, Marc Zyngier wrote:
> On Fri, 03 Sep 2021 14:08:06 +0100,
> Juergen Gross <jgross@suse.com> wrote:
>>
>> Prepare support of very large vcpu numbers per guest by moving the
>> vcpu pointer array out of struct kvm.
>>
>> Signed-off-by: Juergen Gross <jgross@suse.com>
>> ---
>> V2:
>> - rebase to new kvm_arch_free_vm() implementation
>> ---
>>   arch/arm64/kvm/arm.c            | 21 +++++++++++++++++++--
>>   arch/x86/include/asm/kvm_host.h |  5 +----
>>   arch/x86/kvm/x86.c              | 18 ++++++++++++++++++
>>   include/linux/kvm_host.h        | 17 +++++++++++++++--
>>   4 files changed, 53 insertions(+), 8 deletions(-)
>>
>> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
>> index 38fff5963d9f..8bb5caeba007 100644
>> --- a/arch/arm64/kvm/arm.c
>> +++ b/arch/arm64/kvm/arm.c
>> @@ -293,10 +293,27 @@ long kvm_arch_dev_ioctl(struct file *filp,
>>   
>>   struct kvm *kvm_arch_alloc_vm(void)
>>   {
>> +	struct kvm *kvm;
>> +
>> +	if (!has_vhe())
>> +		kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
>> +	else
>> +		kvm = vzalloc(sizeof(struct kvm));
>> +
>> +	if (!kvm)
>> +		return NULL;
>> +
>>   	if (!has_vhe())
>> -		return kzalloc(sizeof(struct kvm), GFP_KERNEL);
>> +		kvm->vcpus = kcalloc(KVM_MAX_VCPUS, sizeof(void *), GFP_KERNEL);
>> +	else
>> +		kvm->vcpus = vzalloc(KVM_MAX_VCPUS * sizeof(void *));
>> +
>> +	if (!kvm->vcpus) {
>> +		kvm_arch_free_vm(kvm);
>> +		kvm = NULL;
>> +	}
>>   
>> -	return vzalloc(sizeof(struct kvm));
>> +	return kvm;
>>   }
>>   
>>   int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index f16fadfc030a..6c28d0800208 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -1517,10 +1517,7 @@ static inline void kvm_ops_static_call_update(void)
>>   }
>>   
>>   #define __KVM_HAVE_ARCH_VM_ALLOC
>> -static inline struct kvm *kvm_arch_alloc_vm(void)
>> -{
>> -	return __vmalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
>> -}
>> +struct kvm *kvm_arch_alloc_vm(void);
>>   
>>   #define __KVM_HAVE_ARCH_VM_FREE
>>   void kvm_arch_free_vm(struct kvm *kvm);
>> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
>> index cc552763f0e4..ff142b6dd00c 100644
>> --- a/arch/x86/kvm/x86.c
>> +++ b/arch/x86/kvm/x86.c
>> @@ -11126,6 +11126,24 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
>>   	static_call(kvm_x86_sched_in)(vcpu, cpu);
>>   }
>>   
>> +struct kvm *kvm_arch_alloc_vm(void)
>> +{
>> +	struct kvm *kvm;
>> +
>> +	kvm = __vmalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
>> +	if (!kvm)
>> +		return NULL;
>> +
>> +	kvm->vcpus = __vmalloc(KVM_MAX_VCPUS * sizeof(void *),
>> +			       GFP_KERNEL_ACCOUNT | __GFP_ZERO);
>> +	if (!kvm->vcpus) {
>> +		vfree(kvm);
>> +		kvm = NULL;
>> +	}
>> +
>> +	return kvm;
>> +}
>> +
>>   void kvm_arch_free_vm(struct kvm *kvm)
>>   {
>>   	kfree(to_kvm_hv(kvm)->hv_pa_pg);
>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>> index d75e9c2a00b1..9e2a5f1c6f54 100644
>> --- a/include/linux/kvm_host.h
>> +++ b/include/linux/kvm_host.h
>> @@ -536,7 +536,7 @@ struct kvm {
>>   	struct mutex slots_arch_lock;
>>   	struct mm_struct *mm; /* userspace tied to this vm */
>>   	struct kvm_memslots __rcu *memslots[KVM_ADDRESS_SPACE_NUM];
>> -	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
>> +	struct kvm_vcpu **vcpus;
> 
> At this stage, I really wonder why we are not using an xarray instead.
> 
> I wrote this [1] a while ago, and nothing caught fire. It was also a
> net deletion of code...

Indeed, I'd prefer that solution!

Are you fine with me swapping my patch with yours in the series?


Juergen
Marc Zyngier Sept. 6, 2021, 9:46 a.m. UTC | #3
On Mon, 06 Sep 2021 05:33:35 +0100,
Juergen Gross <jgross@suse.com> wrote:
> 
> On 03.09.21 16:41, Marc Zyngier wrote:
>
> > At this stage, I really wonder why we are not using an xarray instead.
> > 
> > I wrote this [1] a while ago, and nothing caught fire. It was also a
> > net deletion of code...
> 
> Indeed, I'd prefer that solution!
> 
> Are you fine with me swapping my patch with yours in the series?

Of course, feel free to grab the whole series. You'll probably need
the initial patches to set the scene for this. On their own, they are
a nice cleanup, and I trust you can write a decent commit message for
the three patches affecting mips/s390/x86.

I would normally do that myself, but my network connectivity is
reduced to almost nothing at the moment.

Thanks,

	M.
Sean Christopherson Sept. 9, 2021, 8:28 p.m. UTC | #4
On Mon, Sep 06, 2021, Marc Zyngier wrote:
> On Mon, 06 Sep 2021 05:33:35 +0100,
> Juergen Gross <jgross@suse.com> wrote:
> > 
> > On 03.09.21 16:41, Marc Zyngier wrote:
> >
> > > At this stage, I really wonder why we are not using an xarray instead.
> > > 
> > > I wrote this [1] a while ago, and nothing caught fire. It was also a
> > > net deletion of code...
> > 
> > Indeed, I'd prefer that solution!
> > 
> > Are you fine with me swapping my patch with yours in the series?
> 
> Of course, feel free to grab the whole series. You'll probably need
> the initial patches to set the scene for this. On their own, they are
> a nice cleanup, and I trust you can write a decent commit message for
> the three patches affecting mips/s390/x86.

It would also be a good idea to convert kvm_for_each_vcpu() to use xa_for_each(),
I assume that's more performant than 2x atomic_read() + xa_load().  Unless I'm
misreading the code, xa_for_each() is guaranteed to iterate in ascending index
order, i.e. preserves the current vcpu0..vcpuN iteration order.
diff mbox series

Patch

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 38fff5963d9f..8bb5caeba007 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -293,10 +293,27 @@  long kvm_arch_dev_ioctl(struct file *filp,
 
 struct kvm *kvm_arch_alloc_vm(void)
 {
+	struct kvm *kvm;
+
+	if (!has_vhe())
+		kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
+	else
+		kvm = vzalloc(sizeof(struct kvm));
+
+	if (!kvm)
+		return NULL;
+
 	if (!has_vhe())
-		return kzalloc(sizeof(struct kvm), GFP_KERNEL);
+		kvm->vcpus = kcalloc(KVM_MAX_VCPUS, sizeof(void *), GFP_KERNEL);
+	else
+		kvm->vcpus = vzalloc(KVM_MAX_VCPUS * sizeof(void *));
+
+	if (!kvm->vcpus) {
+		kvm_arch_free_vm(kvm);
+		kvm = NULL;
+	}
 
-	return vzalloc(sizeof(struct kvm));
+	return kvm;
 }
 
 int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f16fadfc030a..6c28d0800208 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1517,10 +1517,7 @@  static inline void kvm_ops_static_call_update(void)
 }
 
 #define __KVM_HAVE_ARCH_VM_ALLOC
-static inline struct kvm *kvm_arch_alloc_vm(void)
-{
-	return __vmalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
-}
+struct kvm *kvm_arch_alloc_vm(void);
 
 #define __KVM_HAVE_ARCH_VM_FREE
 void kvm_arch_free_vm(struct kvm *kvm);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index cc552763f0e4..ff142b6dd00c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -11126,6 +11126,24 @@  void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
 	static_call(kvm_x86_sched_in)(vcpu, cpu);
 }
 
+struct kvm *kvm_arch_alloc_vm(void)
+{
+	struct kvm *kvm;
+
+	kvm = __vmalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+	if (!kvm)
+		return NULL;
+
+	kvm->vcpus = __vmalloc(KVM_MAX_VCPUS * sizeof(void *),
+			       GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+	if (!kvm->vcpus) {
+		vfree(kvm);
+		kvm = NULL;
+	}
+
+	return kvm;
+}
+
 void kvm_arch_free_vm(struct kvm *kvm)
 {
 	kfree(to_kvm_hv(kvm)->hv_pa_pg);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index d75e9c2a00b1..9e2a5f1c6f54 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -536,7 +536,7 @@  struct kvm {
 	struct mutex slots_arch_lock;
 	struct mm_struct *mm; /* userspace tied to this vm */
 	struct kvm_memslots __rcu *memslots[KVM_ADDRESS_SPACE_NUM];
-	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+	struct kvm_vcpu **vcpus;
 
 	/*
 	 * created_vcpus is protected by kvm->lock, and is incremented
@@ -1042,12 +1042,25 @@  void kvm_arch_pre_destroy_vm(struct kvm *kvm);
  */
 static inline struct kvm *kvm_arch_alloc_vm(void)
 {
-	return kzalloc(sizeof(struct kvm), GFP_KERNEL);
+	struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
+
+	if (!kvm)
+		return NULL;
+
+	kvm->vcpus = kcalloc(KVM_MAX_VCPUS, sizeof(void *), GFP_KERNEL);
+	if (!kvm->vcpus) {
+		kfree(kvm);
+		kvm = NULL;
+	}
+
+	return kvm;
 }
 #endif
 
 static inline void __kvm_arch_free_vm(struct kvm *kvm)
 {
+	if (kvm)
+		kvfree(kvm->vcpus);
 	kvfree(kvm);
 }