Commit 3ee16c81 authored by Izik Eidus's avatar Izik Eidus Committed by Avi Kivity
Browse files

KVM: MMU: allow the vm to shrink the kvm mmu shadow caches



Allow the Linux memory manager to reclaim memory in the kvm shadow cache.

Signed-off-by: default avatarIzik Eidus <izike@qumranet.com>
Signed-off-by: default avatarAvi Kivity <avi@qumranet.com>
parent 3200f405
Loading
Loading
Loading
Loading
+56 −2
Original line number Diff line number Diff line
@@ -1966,7 +1966,53 @@ void kvm_mmu_zap_all(struct kvm *kvm)
	kvm_flush_remote_tlbs(kvm);
}

void kvm_mmu_module_exit(void)
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;
	struct kvm *kvm_freed = NULL;
	int cache_count = 0;

	spin_lock(&kvm_lock);

	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;
		cache_count += npages;
		if (!kvm_freed && nr_to_scan > 0 && npages > 0) {
			kvm_mmu_remove_one_alloc_mmu_page(kvm);
			cache_count--;
			kvm_freed = kvm;
		}
		nr_to_scan--;

		spin_unlock(&kvm->mmu_lock);
	}
	if (kvm_freed)
		list_move_tail(&kvm_freed->vm_list, &vm_list);

	spin_unlock(&kvm_lock);

	return cache_count;
}

static struct shrinker mmu_shrinker = {
	.shrink = mmu_shrink,
	.seeks = DEFAULT_SEEKS * 10,
};

void mmu_destroy_caches(void)
{
	if (pte_chain_cache)
		kmem_cache_destroy(pte_chain_cache);
@@ -1976,6 +2022,12 @@ void kvm_mmu_module_exit(void)
		kmem_cache_destroy(mmu_page_header_cache);
}

void kvm_mmu_module_exit(void)
{
	mmu_destroy_caches();
	unregister_shrinker(&mmu_shrinker);
}

int kvm_mmu_module_init(void)
{
	pte_chain_cache = kmem_cache_create("kvm_pte_chain",
@@ -1995,10 +2047,12 @@ int kvm_mmu_module_init(void)
	if (!mmu_page_header_cache)
		goto nomem;

	register_shrinker(&mmu_shrinker);

	return 0;

nomem:
	kvm_mmu_module_exit();
	mmu_destroy_caches();
	return -ENOMEM;
}