From: Ben Luo <bn0418@xxxxxxxxx> Introduce kvm_xchg_guest_cached to exchange value with guest page atomically. Signed-off-by: Yang Zhang <yang.zhang.wz@xxxxxxxxx> Signed-off-by: Quan Xu <quan.xu0@xxxxxxxxx> Signed-off-by: Ben Luo <bn0418@xxxxxxxxx> --- include/linux/kvm_host.h | 3 +++ virt/kvm/kvm_main.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 0 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 6882538..32949ed 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -688,6 +688,9 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, void *data, int offset, unsigned long len); int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc, gpa_t gpa, unsigned long len); +unsigned long kvm_xchg_guest_cached(struct kvm *kvm, + struct gfn_to_hva_cache *ghc, unsigned long offset, + unsigned long new, int size); int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len); int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len); struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 9deb5a2..3149e17 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2010,6 +2010,48 @@ int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, } EXPORT_SYMBOL_GPL(kvm_read_guest_cached); +unsigned long kvm_xchg_guest_cached(struct kvm *kvm, + struct gfn_to_hva_cache *ghc, unsigned long offset, + unsigned long new, int size) +{ + unsigned long r; + void *kva; + struct page *page; + kvm_pfn_t pfn; + + WARN_ON(offset > ghc->len); + + pfn = gfn_to_pfn_atomic(kvm, ghc->gpa >> PAGE_SHIFT); + page = kvm_pfn_to_page(pfn); + + if (is_error_page(page)) + return -EFAULT; + + kva = kmap_atomic(page) + offset_in_page(ghc->gpa) + offset; + switch (size) { + case 1: + r = xchg((char *)kva, new); + break; + case 2: + r = xchg((short *)kva, new); + break; + case 4: + r = xchg((int *)kva, new); + break; + case 8: + r = xchg((long *)kva, new); + break; + default: + kunmap_atomic(kva); + return -EFAULT; + } + + kunmap_atomic(kva); + mark_page_dirty_in_slot(ghc->memslot, ghc->gpa >> PAGE_SHIFT); + + return r; +} + int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len) { const void *zero_page = (const void *) __va(page_to_phys(ZERO_PAGE(0))); -- 1.7.1