KVM: Avoid wasting pages for small lpage_info arrays
authorTakuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Sun, 20 May 2012 04:15:07 +0000 (13:15 +0900)
committerAvi Kivity <avi@redhat.com>
Tue, 5 Jun 2012 13:29:49 +0000 (16:29 +0300)
lpage_info is created for each large level even when the memory slot is
not for RAM.  This means that when we add one slot for a PCI device, we
end up allocating at least KVM_NR_PAGE_SIZES - 1 pages by vmalloc().

To make things worse, there is an increasing number of devices which
would result in more pages being wasted this way.

This patch mitigates this problem by using kvm_kvzalloc().

Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/x86.c
include/linux/kvm_host.h
virt/kvm/kvm_main.c

index be6d54929fa7d661c31f65d076c0daad8086d785..f12a52408cdab2478cb86002ae632fca78977182 100644 (file)
@@ -6304,7 +6304,7 @@ void kvm_arch_free_memslot(struct kvm_memory_slot *free,
 
        for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
                if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) {
-                       vfree(free->arch.lpage_info[i]);
+                       kvm_kvfree(free->arch.lpage_info[i]);
                        free->arch.lpage_info[i] = NULL;
                }
        }
@@ -6323,7 +6323,7 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
                                      slot->base_gfn, level) + 1;
 
                slot->arch.lpage_info[i] =
-                       vzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
+                       kvm_kvzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
                if (!slot->arch.lpage_info[i])
                        goto out_free;
 
index c4464356b35b0af21eaafe6cbd1d2d7b4f549814..19b83f6efa4923bb782a6853c71ca1e095364d14 100644 (file)
@@ -535,6 +535,9 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu);
 
 void kvm_free_physmem(struct kvm *kvm);
 
+void *kvm_kvzalloc(unsigned long size);
+void kvm_kvfree(const void *addr);
+
 #ifndef __KVM_HAVE_ARCH_VM_ALLOC
 static inline struct kvm *kvm_arch_alloc_vm(void)
 {
index 1148c96a48178b71488448c5234645090b1a01db..02cb440f802d74627e05a485b2a2dd65119acccc 100644 (file)
@@ -520,7 +520,7 @@ out_err_nodisable:
  * Avoid using vmalloc for a small buffer.
  * Should not be used when the size is statically known.
  */
-static void *kvm_kvzalloc(unsigned long size)
+void *kvm_kvzalloc(unsigned long size)
 {
        if (size > PAGE_SIZE)
                return vzalloc(size);
@@ -528,7 +528,7 @@ static void *kvm_kvzalloc(unsigned long size)
                return kzalloc(size, GFP_KERNEL);
 }
 
-static void kvm_kvfree(const void *addr)
+void kvm_kvfree(const void *addr)
 {
        if (is_vmalloc_addr(addr))
                vfree(addr);