Anthony Liguori wrote: > Now that we have userspace memory allocation, I wanted to play with > ballooning. > The idea is that when a guest "balloons" down, we simply unpin the underlying > physical memory and the host kernel may or may not swap it. To reclaim > ballooned memory, the guest can just start using it and we'll pin it on > demand. > > The following patch is a stab at providing the right infrastructure for > pinning > and automatic repinning. I don't have a lot of comfort in the MMU code so I > thought I'd get some feedback before going much further. > > gpa_to_hpa is a little awkward to hook, but it seems like the right place in > the > code. I'm most uncertain about the SMP safety of the unpinning. Presumably, > I have to hold the kvm lock around the mmu_unshadow and page_cache release to > ensure that another VCPU doesn't fault the page back in after mmu_unshadow? > > Feedback would be greatly appreciated! > > diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h > index 4a52d6e..8abe770 100644 > --- a/drivers/kvm/kvm.h > +++ b/drivers/kvm/kvm.h > @@ -409,6 +409,7 @@ struct kvm_memory_slot { > unsigned long *rmap; > unsigned long *dirty_bitmap; > int user_alloc; /* user allocated memory */ > + unsigned long userspace_addr; > }; > > struct kvm { > @@ -652,6 +653,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, > gva_t gva); > void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); > int kvm_mmu_load(struct kvm_vcpu *vcpu); > void kvm_mmu_unload(struct kvm_vcpu *vcpu); > +int kvm_mmu_unpin(struct kvm *kvm, gfn_t gfn); > > int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); > > diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c > index a0f8366..74105d1 100644 > --- a/drivers/kvm/kvm_main.c > +++ b/drivers/kvm/kvm_main.c > @@ -774,6 +774,7 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, > unsigned long pages_num; > > new.user_alloc = 1; > + new.userspace_addr = mem->userspace_addr; > down_read(¤t->mm->mmap_sem); > > pages_num = get_user_pages(current, current->mm, > @@ -1049,12 +1050,36 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm > *kvm, gfn_t gfn) > struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) > { > struct kvm_memory_slot *slot; > + struct page *page; > + uint64_t slot_index; > > gfn = unalias_gfn(kvm, gfn); > slot = __gfn_to_memslot(kvm, gfn); > if (!slot) > return NULL; > - return slot->phys_mem[gfn - slot->base_gfn]; > + > + slot_index = gfn - slot->base_gfn; > + page = slot->phys_mem[slot_index]; > + if (unlikely(page == NULL)) { > + unsigned long pages_num; > + > + down_read(¤t->mm->mmap_sem); > + > + pages_num = get_user_pages(current, current->mm, > + slot->userspace_addr + > + (slot_index << PAGE_SHIFT), > + 1, 1, 0, &slot->phys_mem[slot_index], > + NULL); > + > + up_read(¤t->mm->mmap_sem); > + > + if (pages_num != 1) > + page = NULL; > + else > + page = slot->phys_mem[slot_index]; > + } > + > + return page; > } > EXPORT_SYMBOL_GPL(gfn_to_page); > > diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c > index f52604a..1820816 100644 > --- a/drivers/kvm/mmu.c > +++ b/drivers/kvm/mmu.c > @@ -25,6 +25,7 @@ > #include <linux/mm.h> > #include <linux/highmem.h> > #include <linux/module.h> > +#include <linux/pagemap.h> > > #include <asm/page.h> > #include <asm/cmpxchg.h> > @@ -820,6 +821,33 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) > } > } > > +int kvm_mmu_unpin(struct kvm *kvm, gfn_t gfn) > +{ > + struct kvm_memory_slot *slot; > + struct page *page; > + > + /* FIXME for each active vcpu */ > + > + gfn = unalias_gfn(kvm, gfn); > + slot = gfn_to_memslot(kvm, gfn); > + if (!gfn) > + return -EINVAL; > + > + /* FIXME: do we need to hold a lock here? */ > + > + /* Remove page from shadow MMU and unpin page */ > + mmu_unshadow(kvm, gfn); > + page = slot->phys_mem[gfn - slot->base_gfn]; > + if (page) { > + if (!PageReserved(page)) > + SetPageDirty(page); > + page_cache_release(page); > + slot->phys_mem[gfn - slot->base_gfn] = NULL; > + } > + > + return 0; > +} > + > static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa) > { > int slot = memslot_id(kvm, gfn_to_memslot(kvm, gpa >> PAGE_SHIFT)); > > ------------------------------------------------------------------------- > kvm_memory_slot
heh, i am working on similir patch, and our gfn_to_page and the change to kvm_memory_slot even by varible names :) few things you have to do to make this work: make gfn_to_page safe always function (return bad_page in case of failure, i have patch for this if you want) hacking the kvm_read_guest_page / kvm_write_guest_page kvm_clear_guest_page to do put_page after the usage of the page secoend, is hacking the rmap to do reverse mapping to every present pte and put_page() the pages at rmap_remove() and this about all, to make this work. ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel