From patchwork Fri Jul 16 02:13:07 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lai Jiangshan X-Patchwork-Id: 112351 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o6G2Ds3Y006982 for ; Fri, 16 Jul 2010 02:13:56 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935459Ab0GPCNU (ORCPT ); Thu, 15 Jul 2010 22:13:20 -0400 Received: from cn.fujitsu.com ([222.73.24.84]:49817 "EHLO song.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-OK) by vger.kernel.org with ESMTP id S935455Ab0GPCMp (ORCPT ); Thu, 15 Jul 2010 22:12:45 -0400 Received: from tang.cn.fujitsu.com (tang.cn.fujitsu.com [10.167.250.3]) by song.cn.fujitsu.com (Postfix) with ESMTP id BFC5B170115; Fri, 16 Jul 2010 10:12:43 +0800 (CST) Received: from fnst.cn.fujitsu.com (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id o6G29t59032161; Fri, 16 Jul 2010 10:09:55 +0800 Received: from [10.167.141.204] (unknown [10.167.141.204]) by fnst.cn.fujitsu.com (Postfix) with ESMTPA id 19B4A1CC1F7; Fri, 16 Jul 2010 10:13:06 +0800 (CST) Message-ID: <4C3FC033.3000605@cn.fujitsu.com> Date: Fri, 16 Jul 2010 10:13:07 +0800 From: Lai Jiangshan User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.9) Gecko/20100423 Thunderbird/3.0.4 MIME-Version: 1.0 To: LKML , kvm@vger.kernel.org, Avi Kivity , Marcelo Tosatti , Nick Piggin Subject: [PATCH 5/6] kvm, x86: use ro page and don't copy shared page Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Fri, 16 Jul 2010 02:13:56 +0000 (UTC) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 8ba9b0d..6382140 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1832,6 +1832,45 @@ static void kvm_unsync_pages(struct kvm_vcpu *vcpu, gfn_t gfn) } } +/* get a current mapped page fast, and test whether the page is writable. */ +static struct page *get_user_page_and_protection(unsigned long addr, + int *writable) +{ + struct page *page[1]; + + if (__get_user_pages_fast(addr, 1, 1, page) == 1) { + *writable = 1; + return page[0]; + } + if (__get_user_pages_fast(addr, 1, 0, page) == 1) { + *writable = 0; + return page[0]; + } + return NULL; +} + +static pfn_t kvm_get_pfn_for_page_fault(struct kvm *kvm, gfn_t gfn, + int write_fault, int *host_writable) +{ + unsigned long addr; + struct page *page; + + if (!write_fault) { + addr = gfn_to_hva(kvm, gfn); + if (kvm_is_error_hva(addr)) { + get_page(bad_page); + return page_to_pfn(bad_page); + } + + page = get_user_page_and_protection(addr, host_writable); + if (page) + return page_to_pfn(page); + } + + *host_writable = 1; + return kvm_get_pfn_for_gfn(kvm, gfn); +} + static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn, bool can_unsync) { @@ -2085,6 +2124,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) int level; pfn_t pfn; unsigned long mmu_seq; + int host_writable; level = mapping_level(vcpu, gfn); @@ -2099,7 +2139,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) mmu_seq = vcpu->kvm->mmu_notifier_seq; smp_rmb(); - pfn = kvm_get_pfn_for_gfn(vcpu->kvm, gfn); + pfn = kvm_get_pfn_for_page_fault(vcpu->kvm, gfn, write, &host_writable); /* mmio */ if (is_error_pfn(pfn)) @@ -2109,7 +2149,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) if (mmu_notifier_retry(vcpu, mmu_seq)) goto out_unlock; kvm_mmu_free_some_pages(vcpu); - r = __direct_map(vcpu, v, write, level, gfn, pfn, true); + r = __direct_map(vcpu, v, write, level, gfn, pfn, host_writable); spin_unlock(&vcpu->kvm->mmu_lock); @@ -2307,6 +2347,8 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, int level; gfn_t gfn = gpa >> PAGE_SHIFT; unsigned long mmu_seq; + int write_fault = error_code & PFERR_WRITE_MASK; + int host_writable; ASSERT(vcpu); ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa)); @@ -2321,15 +2363,16 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, mmu_seq = vcpu->kvm->mmu_notifier_seq; smp_rmb(); - pfn = kvm_get_pfn_for_gfn(vcpu->kvm, gfn); + pfn = kvm_get_pfn_for_page_fault(vcpu->kvm, gfn, write_fault, + &host_writable); if (is_error_pfn(pfn)) return kvm_handle_bad_page(vcpu->kvm, gfn, pfn); spin_lock(&vcpu->kvm->mmu_lock); if (mmu_notifier_retry(vcpu, mmu_seq)) goto out_unlock; kvm_mmu_free_some_pages(vcpu); - r = __direct_map(vcpu, gpa, error_code & PFERR_WRITE_MASK, - level, gfn, pfn, true); + r = __direct_map(vcpu, gpa, write_fault, + level, gfn, pfn, host_writable); spin_unlock(&vcpu->kvm->mmu_lock); return r; diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index a9dbaa0..1874f51 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -430,6 +430,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, pfn_t pfn; int level = PT_PAGE_TABLE_LEVEL; unsigned long mmu_seq; + int host_writable; pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code); kvm_mmu_audit(vcpu, "pre page fault"); @@ -461,7 +462,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, mmu_seq = vcpu->kvm->mmu_notifier_seq; smp_rmb(); - pfn = kvm_get_pfn_for_gfn(vcpu->kvm, walker.gfn); + pfn = kvm_get_pfn_for_page_fault(vcpu->kvm, walker.gfn, write_fault, + &host_writable); /* mmio */ if (is_error_pfn(pfn)) @@ -472,7 +474,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, goto out_unlock; kvm_mmu_free_some_pages(vcpu); sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, - level, &write_pt, pfn, true); + level, &write_pt, pfn, host_writable); (void)sptep; pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __func__, sptep, *sptep, write_pt); diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index 738e659..a4ce19f 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -274,6 +275,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write, return nr; } +EXPORT_SYMBOL_GPL(__get_user_pages_fast); /** * get_user_pages_fast() - pin user pages in memory