diff mbox

[v2,1/1] kvm: Make VM ioctl do a vzalloc instead of a kzalloc

Message ID 20180503175917.67937-1-marcorr@google.com (mailing list archive)
State New, archived
Headers show

Commit Message

Marc Orr May 3, 2018, 5:59 p.m. UTC
The kvm struct is (currently) tens of kilo-bytes, which turns out to be a
large amount of memory to allocate contiguously via kzalloc. Thus, this
patch changes the kzalloc to a vzalloc, so that the memory allocation is
less likely to fail in resource-constrained environments.

Signed-off-by: Marc Orr <marcorr@google.com>
Change-Id: Ide392e51991142d1325e06351231ac685e11d820
---
 arch/x86/kvm/svm.c       | 4 ++--
 arch/x86/kvm/vmx.c       | 4 ++--
 include/linux/kvm_host.h | 5 +++--
 3 files changed, 7 insertions(+), 6 deletions(-)

Comments

Christian Borntraeger May 4, 2018, 9:11 a.m. UTC | #1
you should also add the arm/mips/power maintainers so that they can review their
struct kvm_arch if any of the content is passed directly to the hardware (e.g. with
__pa). A quick looks seems to indicate that there is no issue.

On 05/03/2018 07:59 PM, Marc Orr wrote:
> The kvm struct is (currently) tens of kilo-bytes, which turns out to be a
> large amount of memory to allocate contiguously via kzalloc. Thus, this
> patch changes the kzalloc to a vzalloc, so that the memory allocation is
> less likely to fail in resource-constrained environments.
> 
> Signed-off-by: Marc Orr <marcorr@google.com>

s390 parts seem to work

Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>

> Change-Id: Ide392e51991142d1325e06351231ac685e11d820

what is that?


> ---
>  arch/x86/kvm/svm.c       | 4 ++--
>  arch/x86/kvm/vmx.c       | 4 ++--
>  include/linux/kvm_host.h | 5 +++--
>  3 files changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index b58787daf9f8..f990fda1b2f6 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -1838,13 +1838,13 @@ static void __unregister_enc_region_locked(struct kvm *kvm,
> 
>  static struct kvm *svm_vm_alloc(void)
>  {
> -	struct kvm_svm *kvm_svm = kzalloc(sizeof(struct kvm_svm), GFP_KERNEL);
> +	struct kvm_svm *kvm_svm = vzalloc(sizeof(struct kvm_svm));
>  	return &kvm_svm->kvm;
>  }
> 
>  static void svm_vm_free(struct kvm *kvm)
>  {
> -	kfree(to_kvm_svm(kvm));
> +	vfree(to_kvm_svm(kvm));
>  }
> 
>  static void sev_vm_destroy(struct kvm *kvm)
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index aafcc9881e88..26ab153a293f 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -9949,13 +9949,13 @@ STACK_FRAME_NON_STANDARD(vmx_vcpu_run);
> 
>  static struct kvm *vmx_vm_alloc(void)
>  {
> -	struct kvm_vmx *kvm_vmx = kzalloc(sizeof(struct kvm_vmx), GFP_KERNEL);
> +	struct kvm_vmx *kvm_vmx = vzalloc(sizeof(struct kvm_vmx));
>  	return &kvm_vmx->kvm;
>  }
> 
>  static void vmx_vm_free(struct kvm *kvm)
>  {
> -	kfree(to_kvm_vmx(kvm));
> +	vfree(to_kvm_vmx(kvm));
>  }
> 
>  static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs)
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 6930c63126c7..cf7b6a3a4197 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -19,6 +19,7 @@
>  #include <linux/preempt.h>
>  #include <linux/msi.h>
>  #include <linux/slab.h>
> +#include <linux/vmalloc.h>
>  #include <linux/rcupdate.h>
>  #include <linux/ratelimit.h>
>  #include <linux/err.h>
> @@ -810,12 +811,12 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);
>  #ifndef __KVM_HAVE_ARCH_VM_ALLOC
>  static inline struct kvm *kvm_arch_alloc_vm(void)
>  {
> -	return kzalloc(sizeof(struct kvm), GFP_KERNEL);
> +	return vzalloc(sizeof(struct kvm));
>  }
> 
>  static inline void kvm_arch_free_vm(struct kvm *kvm)
>  {
> -	kfree(kvm);
> +	vfree(kvm);
>  }
>  #endif
>
James Hogan May 4, 2018, 9:28 a.m. UTC | #2
On Fri, May 04, 2018 at 11:11:21AM +0200, Christian Borntraeger wrote:
> you should also add the arm/mips/power maintainers so that they can review their
> struct kvm_arch if any of the content is passed directly to the hardware (e.g. with
> __pa). A quick looks seems to indicate that there is no issue.

MIPS has additional restrictions because it has a software managed TLB,
so we have to be careful where we access vmalloc'd memory, especially
around entry point code which may not expect to receive a TLB refill
exception. I'll have a deeper look later to see if it would obviously
break anything.

Thanks
James

> 
> On 05/03/2018 07:59 PM, Marc Orr wrote:
> > The kvm struct is (currently) tens of kilo-bytes, which turns out to be a
> > large amount of memory to allocate contiguously via kzalloc. Thus, this
> > patch changes the kzalloc to a vzalloc, so that the memory allocation is
> > less likely to fail in resource-constrained environments.
> > 
> > Signed-off-by: Marc Orr <marcorr@google.com>
Marc Zyngier May 4, 2018, 9:30 a.m. UTC | #3
[fixing Christoffer's email address]

Thanks for looping us in.

On 04/05/18 10:11, Christian Borntraeger wrote:
> you should also add the arm/mips/power maintainers so that they can review their
> struct kvm_arch if any of the content is passed directly to the hardware (e.g. with
> __pa). A quick looks seems to indicate that there is no issue.

Well, there is a small issue, at least on arm64. Only VAs that are part
of the linear mapping can easily be mapped at EL2 (so that we can play
our kern_to_hyp_va trick on ARMv8.0 cores), and the kvm structure is
assumed to be physically contiguous.

Switch to a vmalloc'ed structure breaks these two requirements since, as
you noticed it, the kvm struct is more than a single page.

I'd suggest you let each architecture buy into this, or provide a
kmalloc-based kvm_arch_{alloc,free}_vm for architectures that cannot use
the vmalloc area for this. On arm64, we could use vmalloc on VHE-capable
cores, and stick to kmalloc for the rest.

> 
> On 05/03/2018 07:59 PM, Marc Orr wrote:
>> The kvm struct is (currently) tens of kilo-bytes, which turns out to be a
>> large amount of memory to allocate contiguously via kzalloc. Thus, this
>> patch changes the kzalloc to a vzalloc, so that the memory allocation is
>> less likely to fail in resource-constrained environments.
>>
>> Signed-off-by: Marc Orr <marcorr@google.com>
> 
> s390 parts seem to work
> 
> Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
> 
>> Change-Id: Ide392e51991142d1325e06351231ac685e11d820
> 
> what is that?
> 
> 
>> ---
>>  arch/x86/kvm/svm.c       | 4 ++--
>>  arch/x86/kvm/vmx.c       | 4 ++--
>>  include/linux/kvm_host.h | 5 +++--
>>  3 files changed, 7 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
>> index b58787daf9f8..f990fda1b2f6 100644
>> --- a/arch/x86/kvm/svm.c
>> +++ b/arch/x86/kvm/svm.c
>> @@ -1838,13 +1838,13 @@ static void __unregister_enc_region_locked(struct kvm *kvm,
>>
>>  static struct kvm *svm_vm_alloc(void)
>>  {
>> -	struct kvm_svm *kvm_svm = kzalloc(sizeof(struct kvm_svm), GFP_KERNEL);
>> +	struct kvm_svm *kvm_svm = vzalloc(sizeof(struct kvm_svm));
>>  	return &kvm_svm->kvm;
>>  }
>>
>>  static void svm_vm_free(struct kvm *kvm)
>>  {
>> -	kfree(to_kvm_svm(kvm));
>> +	vfree(to_kvm_svm(kvm));
>>  }
>>
>>  static void sev_vm_destroy(struct kvm *kvm)
>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>> index aafcc9881e88..26ab153a293f 100644
>> --- a/arch/x86/kvm/vmx.c
>> +++ b/arch/x86/kvm/vmx.c
>> @@ -9949,13 +9949,13 @@ STACK_FRAME_NON_STANDARD(vmx_vcpu_run);
>>
>>  static struct kvm *vmx_vm_alloc(void)
>>  {
>> -	struct kvm_vmx *kvm_vmx = kzalloc(sizeof(struct kvm_vmx), GFP_KERNEL);
>> +	struct kvm_vmx *kvm_vmx = vzalloc(sizeof(struct kvm_vmx));
>>  	return &kvm_vmx->kvm;
>>  }
>>
>>  static void vmx_vm_free(struct kvm *kvm)
>>  {
>> -	kfree(to_kvm_vmx(kvm));
>> +	vfree(to_kvm_vmx(kvm));
>>  }
>>
>>  static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs)
>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>> index 6930c63126c7..cf7b6a3a4197 100644
>> --- a/include/linux/kvm_host.h
>> +++ b/include/linux/kvm_host.h
>> @@ -19,6 +19,7 @@
>>  #include <linux/preempt.h>
>>  #include <linux/msi.h>
>>  #include <linux/slab.h>
>> +#include <linux/vmalloc.h>
>>  #include <linux/rcupdate.h>
>>  #include <linux/ratelimit.h>
>>  #include <linux/err.h>
>> @@ -810,12 +811,12 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);
>>  #ifndef __KVM_HAVE_ARCH_VM_ALLOC
>>  static inline struct kvm *kvm_arch_alloc_vm(void)
>>  {
>> -	return kzalloc(sizeof(struct kvm), GFP_KERNEL);
>> +	return vzalloc(sizeof(struct kvm));
>>  }
>>
>>  static inline void kvm_arch_free_vm(struct kvm *kvm)
>>  {
>> -	kfree(kvm);
>> +	vfree(kvm);
>>  }
>>  #endif
>>
> 

Thanks,

	M.
Paolo Bonzini May 7, 2018, 4:21 p.m. UTC | #4
On 04/05/2018 11:30, Marc Zyngier wrote:
>> you should also add the arm/mips/power maintainers so that they can review their
>> struct kvm_arch if any of the content is passed directly to the hardware (e.g. with
>> __pa). A quick looks seems to indicate that there is no issue.
> Well, there is a small issue, at least on arm64. Only VAs that are part
> of the linear mapping can easily be mapped at EL2 (so that we can play
> our kern_to_hyp_va trick on ARMv8.0 cores), and the kvm structure is
> assumed to be physically contiguous.
> 
> Switch to a vmalloc'ed structure breaks these two requirements since, as
> you noticed it, the kvm struct is more than a single page.
> 
> I'd suggest you let each architecture buy into this, or provide a
> kmalloc-based kvm_arch_{alloc,free}_vm for architectures that cannot use
> the vmalloc area for this. On arm64, we could use vmalloc on VHE-capable
> cores, and stick to kmalloc for the rest.
> 

Alternatively you could have a #define __KVM_KMALLOC_STRUCT_KVM and
define it in arch/arm*/include/asm/kvm_host.h.

Paolo
Marc Orr May 7, 2018, 10:25 p.m. UTC | #5
I just sent out v3, which updates the patch to maintain the kzalloc
behavior for arm & arm64. Please review that one going forward.

>> Change-Id: Ide392e51991142d1325e06351231ac685e11d820

> what is that?
Woops. That's meta-data inserted my git hooks. Thanks for catching this!

Thanks,
Marc
diff mbox

Patch

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index b58787daf9f8..f990fda1b2f6 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1838,13 +1838,13 @@  static void __unregister_enc_region_locked(struct kvm *kvm,
 
 static struct kvm *svm_vm_alloc(void)
 {
-	struct kvm_svm *kvm_svm = kzalloc(sizeof(struct kvm_svm), GFP_KERNEL);
+	struct kvm_svm *kvm_svm = vzalloc(sizeof(struct kvm_svm));
 	return &kvm_svm->kvm;
 }
 
 static void svm_vm_free(struct kvm *kvm)
 {
-	kfree(to_kvm_svm(kvm));
+	vfree(to_kvm_svm(kvm));
 }
 
 static void sev_vm_destroy(struct kvm *kvm)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index aafcc9881e88..26ab153a293f 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -9949,13 +9949,13 @@  STACK_FRAME_NON_STANDARD(vmx_vcpu_run);
 
 static struct kvm *vmx_vm_alloc(void)
 {
-	struct kvm_vmx *kvm_vmx = kzalloc(sizeof(struct kvm_vmx), GFP_KERNEL);
+	struct kvm_vmx *kvm_vmx = vzalloc(sizeof(struct kvm_vmx));
 	return &kvm_vmx->kvm;
 }
 
 static void vmx_vm_free(struct kvm *kvm)
 {
-	kfree(to_kvm_vmx(kvm));
+	vfree(to_kvm_vmx(kvm));
 }
 
 static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 6930c63126c7..cf7b6a3a4197 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -19,6 +19,7 @@ 
 #include <linux/preempt.h>
 #include <linux/msi.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/rcupdate.h>
 #include <linux/ratelimit.h>
 #include <linux/err.h>
@@ -810,12 +811,12 @@  int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);
 #ifndef __KVM_HAVE_ARCH_VM_ALLOC
 static inline struct kvm *kvm_arch_alloc_vm(void)
 {
-	return kzalloc(sizeof(struct kvm), GFP_KERNEL);
+	return vzalloc(sizeof(struct kvm));
 }
 
 static inline void kvm_arch_free_vm(struct kvm *kvm)
 {
-	kfree(kvm);
+	vfree(kvm);
 }
 #endif