KVM: MMU: handle n_free_mmu_pages > n_alloc_mmu_pages in kvm_mmu_change_mmu_pages
authorMarcelo Tosatti <mtosatti@redhat.com>
Wed, 22 Jul 2009 16:05:49 +0000 (13:05 -0300)
committerAvi Kivity <avi@redhat.com>
Wed, 5 Aug 2009 10:59:43 +0000 (13:59 +0300)
kvm_mmu_change_mmu_pages mishandles the case where n_alloc_mmu_pages is
smaller then n_free_mmu_pages, by not checking if the result of
the subtraction is negative.

Its a valid condition which can happen if a large number of pages has
been recently freed.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/mmu.c

index 7030b5f911bff0df9019a1c080bf3b5561086780..49a10d0083004a89b31071c2edea062747ffae6b 100644 (file)
@@ -1407,24 +1407,25 @@ static int kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp)
  */
 void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages)
 {
+       int used_pages;
+
+       used_pages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages;
+       used_pages = max(0, used_pages);
+
        /*
         * If we set the number of mmu pages to be smaller be than the
         * number of actived pages , we must to free some mmu pages before we
         * change the value
         */
 
-       if ((kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages) >
-           kvm_nr_mmu_pages) {
-               int n_used_mmu_pages = kvm->arch.n_alloc_mmu_pages
-                                      - kvm->arch.n_free_mmu_pages;
-
-               while (n_used_mmu_pages > kvm_nr_mmu_pages) {
+       if (used_pages > kvm_nr_mmu_pages) {
+               while (used_pages > kvm_nr_mmu_pages) {
                        struct kvm_mmu_page *page;
 
                        page = container_of(kvm->arch.active_mmu_pages.prev,
                                            struct kvm_mmu_page, link);
                        kvm_mmu_zap_page(kvm, page);
-                       n_used_mmu_pages--;
+                       used_pages--;
                }
                kvm->arch.n_free_mmu_pages = 0;
        }