>From fa7e68f0d0be21dff6d4f3ac12bae10247f5574c Mon Sep 17 00:00:00 2001
From: Izik Eidus <izike@qumranet.com>
Date: Wed, 12 Mar 2008 20:05:11 +0200
Subject: [PATCH] KVM: register the kvm mmu cache with the shrinker.

Signed-off-by: Izik Eidus <izike@qumranet.com>
---
 arch/x86/kvm/mmu.c |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index f0cdfba..d0b8b4b 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1940,6 +1940,55 @@ void kvm_mmu_zap_all(struct kvm *kvm)
 	kvm_flush_remote_tlbs(kvm);
 }
 
+void kvm_mmu_remove_one_alloc_mmu_page(struct kvm *kvm)
+{
+	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);
+}
+
+static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask)
+{
+	struct kvm *kvm;
+	int cache_count = 0;
+	int once = 0;
+
+	do {
+		spin_lock(&kvm_lock);
+		if (list_empty(&vm_list)) {
+			spin_unlock(&kvm_lock);
+			return 0;
+		}
+		list_for_each_entry(kvm, &vm_list, vm_list) {
+			int npages;
+
+			spin_lock(&kvm->mmu_lock);
+			npages = kvm->arch.n_alloc_mmu_pages -
+				 kvm->arch.n_free_mmu_pages;
+			if (!once)
+				cache_count += npages - KVM_MIN_ALLOC_MMU_PAGES;
+			if (nr_to_scan > 0 && npages > KVM_MIN_ALLOC_MMU_PAGES) {
+				kvm_mmu_remove_one_alloc_mmu_page(kvm);
+				cache_count--;
+			}
+			nr_to_scan--;
+
+			spin_unlock(&kvm->mmu_lock);
+		}
+		spin_unlock(&kvm_lock);
+		once = 1;
+	} while (nr_to_scan > 0);
+
+	return cache_count;
+}
+
+static struct shrinker mmu_shrinker = {
+	.shrink = mmu_shrink,
+	.seeks = DEFAULT_SEEKS,
+};
+
 void kvm_mmu_module_exit(void)
 {
 	if (pte_chain_cache)
@@ -1948,6 +1997,7 @@ void kvm_mmu_module_exit(void)
 		kmem_cache_destroy(rmap_desc_cache);
 	if (mmu_page_header_cache)
 		kmem_cache_destroy(mmu_page_header_cache);
+	unregister_shrinker(&mmu_shrinker);
 }
 
 int kvm_mmu_module_init(void)
@@ -1969,6 +2019,8 @@ int kvm_mmu_module_init(void)
 	if (!mmu_page_header_cache)
 		goto nomem;
 
+	register_shrinker(&mmu_shrinker);
+
 	return 0;
 
 nomem:
-- 
1.5.3.6

