RFC: Nested-p2m cleanups and locking changes
PATCH 1/1 RFC: Nested-p2m cleanups and locking changes
This patch series tidies up a few bits ofthe nested p2m code. The main thing it does is reorganize the locking so that most of the changes to nested p2m tables happen only under the p2m lock, and the nestedp2m lock is only needed to reassign p2m tables to new cr3 values.
Unfortunately I'm having terrible trouble trying to run Xen under Xen to test these, so this version of the series is only compile-tested. I'm just posting them for feedback from Christoph on whether this approach seems reasonable.
Cheers,
Tim.
PATCH 1/1 Nested p2m: implement "flush" as a first-class action
# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1308758648 -3600
# Node ID c323e69a0a08ce9f1e54d2e2fa2edd9845bc8efe
# Parent b7e5a25663329254cba539e21f4fbd5b32c67556 Nested p2m: implement "flush" as a first-class action rather than using the teardown and init functions.
This makes the locking clearer and avoids an expensive scan of all pfns that's only needed for non-nested p2ms. It also moves the tlb flush into the proper place in the flush logic, avoiding a possible race against other CPUs.
xen/arch/x86/hvm/nestedhvm.c +0 -6
@@ -119,12 +119,6 @@ nestedhvm_vmcx_flushtlb(struct p2m_domaicpus_clear (p2m->p2m_dirty_cpumask); } -void -nestedhvm_vmcx_flushtlbdomain (struct domain *d) -{ -on_selected_cpus (d->domain_dirty_cpumask, nestedhvm_flushtlb_ipi, d,1 ); -} -bool_t nestedhvm_is_n2 (struct vcpu *v) {
xen/arch/x86/mm/p2m.c +37 -23
94 lines not on this page · raw message
xen/include/asm-x86/hvm/nestedhvm.h +0 -1
@@ -61,7 +61,6 @@ unsigned long *nestedhvm_vcpu_iomap_get( (!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress)void nestedhvm_vmcx_flushtlb (struct p2m_domain *p2m); -void nestedhvm_vmcx_flushtlbdomain (struct domain *d);bool_t nestedhvm_is_n2 (struct vcpu *v);
Re: [PATCH 1 of 4] Nested p2m: implement "flush" as a first-class action
This patch crashes the host (and it doesn't disappear with the other patches applied):
(XEN) Assertion 'pfn_to_pdx(ma >> PAGE_SHIFT) < (DIRECTMAP_SIZE >> PAGE_SHIFT)' failed at /data/xen/xen-nestedhvm-patches.hg/xen/include/asm:99
(XEN) ----[ Xen-4.2-unstable x86_64 debug=y Tainted: C ]----
(XEN) CPU: 1
(XEN) RIP: e008:[<ffff82c4801d2007>] p2m_flush_locked+0x1a8/0x2be
(XEN) RFLAGS: 0000000000010212 CONTEXT: hypervisor
(XEN) rax: 0000000000000000 rbx: ffff830421db1d90 rcx: 0000000000000000 (XEN) rdx: f82f608076a60000 rsi: 000f82f608076a60 rdi: 0000000000000000 (XEN) rbp: ffff830425217a08 rsp: ffff8304252179c8 r8: 0000000000000000 (XEN) r9: 0000000000000004 r10: 00000000fffffffb r11: 0000000000000003 (XEN) r12: ffff830421db1d90 r13: ffff82f608076a60 r14: ffff830403bbebe8 (XEN) r15: ffff830403bbe000 cr0: 000000008005003b cr4: 00000000000406f0 (XEN) cr3: 0000000420f2b000 cr2: 000000000045f000 (XEN) ds: 0017 es: 0017 fs: 0000 gs: 0000 ss: e010 cs: e008 (XEN) Xen stack trace from rsp=ffff8304252179c8: (XEN) ffff830403bbebe8 ffff830421db1d90 ffff830421db1d90 0000000000000000 (XEN) ffff830403bbe000 ffff830403bbebe8 ffff830403bbebe8 ffff830403bbeab0 (XEN) ffff830425217a38 ffff82c4801d2599 0000000000000001 0000000000000067 (XEN) ffff830403bbeab0 ffff830403af4000 ffff830425217a88 ffff82c480208a8c (XEN) 0000000125941810 ffff830403bbe000 0000000000000000 ffff830425217b18 (XEN) ffff830421db1cc0 00000000000ff000 ffffffffffffffff 0000000000000000 (XEN) ffff830425217a98 ffff82c4801ce585 ffff830425217b68 ffff82c4801d4b4e (XEN) 0000000000000200 1000000000000000 ffff830425217b28 ffff830425217b20 (XEN) 0000000000000001 ffff830425217ae8 ffff830425217ef8 ffff830403af4000 (XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000 (XEN) 0000000000000000 0000000000000000 0000000000000000 ffff830403af4000 (XEN) 0000000000403af4 ffff82c4801d5ec1 ffff830425217bfc ffffffffffffffff (XEN) 0000000000000000 0000000000000001 00000000000ff000 ffff830421db1cc0 (XEN) ffff830425217bb8 ffff82c4801d02d1 0000000100000007 ffff830403bbe000 (XEN) 0000000125217bc8 ffff8280019fafc0 ffff82c400cfd7e0 000000000033f5f8 (XEN) ffff830421db1cc0 0000000000000001 ffff830425217c28 ffff82c4801d053d (XEN) ffff830425217bfc ffff830425217bf8 0000000025217bf0 00000000000ff000 (XEN) 0000000000000001 ffff830425217c10 0000000000000007 ffff830421db1cc0 (XEN) ffff830421db1cc0 ffff830425217f18 ffff82c4802e1260 0000000000000000 (XEN) ffff830425217c78 ffff82c4801d11fa 000000000033f5f7 00000000000ff000 (XEN) Xen call trace: (XEN) [<ffff82c4801d2007>] p2m_flush_locked+0x1a8/0x2be (XEN) [<ffff82c4801d2599>] p2m_flush_nestedp2m+0xea/0x140 (XEN) [<ffff82c480208a8c>] hap_write_p2m_entry+0x223/0x246 (XEN) [<ffff82c4801ce585>] paging_write_p2m_entry+0x6e/0x75 (XEN) [<ffff82c4801d4b4e>] p2m_set_entry+0x42b/0x6a8 (XEN) [<ffff82c4801d02d1>] set_p2m_entry+0xf2/0x140 (XEN) [<ffff82c4801d053d>] p2m_remove_page+0x1dd/0x1ec (XEN) [<ffff82c4801d11fa>] guest_physmap_remove_page+0x109/0x148 (XEN) [<ffff82c480168000>] arch_memory_op+0x6af/0x1039 (XEN) [<ffff82c4801134fb>] do_memory_op+0x1bd7/0x1c2c (XEN) [<ffff82c480217708>] syscall_enter+0xc8/0x122
(XEN)
(XEN)
(XEN) ****************************************
Christoph
Quoted 144 lines · Tim Deegan
# HG changeset patch
# User Tim Deegan<[email protected]>
# Date 1308758648 -3600
# Node IDc323e69a0a08ce9f1e54d2e2fa2edd9845bc8efe
# Parentb7e5a25663329254cba539e21f4fbd5b32c67556Nested p2m: implement "flush" as a first-class action rather than using the teardown and init functions.
This makes the locking clearer and avoids an expensive scan of all pfns that's only needed for non-nested p2ms. It also moves the tlb flush into the proper place in the flush logic, avoiding a possible race against other CPUs.Signed-off-by Tim Deegan<[email protected]>diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/hvm/nestedhvm.cxen/arch/x86/hvm/nestedhvm.c +0
-6@@ -119,12 +119,6 @@ nestedhvm_vmcx_flushtlb(struct p2m_domaicpus_clear (p2m->p2m_dirty_cpumask); } -void -nestedhvm_vmcx_flushtlbdomain (struct domain *d) -{ -on_selected_cpus (d->domain_dirty_cpumask, nestedhvm_flushtlb_ipi, d,1 ); -} -bool_t nestedhvm_is_n2 (struct vcpu *v) {diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c +37
-23@@ -1050,20 +1050,41 @@ p2m_getlru_nestedp2m(struct domain *d, sreturn lrup2m; } -static int +/* Reset this p2m table to be empty */ +static void p2m_flush_locked (struct p2m_domain *p2m) { -ASSERT (p2m); -if (p2m->cr3 ==CR3_EADDR ) -/* Microoptimisation: p2m is already empty. -* => about 0.3% speedup of overall system performance. -*/ -return 0 ; +struct page_info *top, *pg; +struct domain *d = p2m->domain; +void *p; -p2m_teardown (p2m); -p2m_initialise (p2m->domain, p2m); - p2m->write_p2m_entry = nestedp2m_write_p2m_entry; -return p2m_alloc_table (p2m); +p2m_lock (p2m); + +/* "Host" p2m tables can have shared entries&c that need a bit more +* care when discarding them */ +ASSERT (p2m_is_nestedp2m (p2m)); +ASSERT (page_list_empty (&p2m->pod.super)); +ASSERT (page_list_empty (&p2m->pod.single)); + +/* This is no longer a valid nested p2m for any address space */ + p2m->cr3 =CR3_EADDR ; + +/* Zap the top level of the trie */ + top =mfn_to_page (pagetable_get_mfn (p2m_get_pagetable (p2m))); + p =map_domain_page (top); +clear_page (p); +unmap_domain_page (p); + +/* Make sure nobody else is using this p2m table */ +nestedhvm_vmcx_flushtlb (p2m); + +/* Free the rest of the trie pages back to the paging pool */ +while ( (pg =page_list_remove_head (&p2m->pages)) ) +if ( pg != top ) + d->arch.paging.free_page (d, pg); +page_list_add (top,&p2m->pages); + +p2m_unlock (p2m); }void @@ -1074,9 +1095,8 @@ p2m_flush(struct vcpu *v, struct p2m_domASSERT (v->domain == d);vcpu_nestedhvm (v).nv_p2m =NULL ;nestedp2m_lock (d); -BUG_ON (p2m_flush_locked (p2m) !=0 ); +p2m_flush_locked (p2m);hvm_asid_flush_vcpu (v); -nestedhvm_vmcx_flushtlb (p2m);nestedp2m_unlock (d); }@@ -1086,12 +1106,8 @@ p2m_flush_nestedp2m(struct domain *d)int i;nestedp2m_lock (d); -for (i =0 ; i<MAX_NESTEDP2M ; i++) { -struct p2m_domain *p2m = d->arch.nested_p2m[i]; -BUG_ON (p2m_flush_locked (p2m) !=0 ); -cpus_clear (p2m->p2m_dirty_cpumask); - } -nestedhvm_vmcx_flushtlbdomain (d); +for ( i =0 ; i<MAX_NESTEDP2M ; i++ ) +p2m_flush_locked (d->arch.nested_p2m[i]);nestedp2m_unlock (d); }@@ -1104,7 +1120,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64volatile struct nestedvcpu *nv =&vcpu_nestedhvm (v);struct domain *d;struct p2m_domain *p2m; -int i, rv; +int i;if (cr3 ==0 || cr3 ==CR3_EADDR ) cr3 = v->arch.hvm_vcpu.guest_cr[3 ];@@ -1136,9 +1152,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64*/ for (i =0 ; i<MAX_NESTEDP2M ; i++) { p2m =p2m_getlru_nestedp2m (d,NULL ); - rv =p2m_flush_locked (p2m); -if (rv ==0 ) -break ; +p2m_flush_locked (p2m); } nv->nv_p2m = p2m; p2m->cr3 = cr3;diff -r
b7e5a2566332-rc323e69a0a08xen/include/asm-x86/hvm/nestedhvm.hxen/include/asm-x86/hvm/nestedhvm.h +0
-1@@ -61,7 +61,6 @@ unsigned long *nestedhvm_vcpu_iomap_get( (!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress)void nestedhvm_vmcx_flushtlb (struct p2m_domain *p2m); -void nestedhvm_vmcx_flushtlbdomain (struct domain *d);bool_t nestedhvm_is_n2 (struct vcpu *v);
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: Re: [PATCH 1 of 4] Nested p2m: implement "flush" as a first-class action
Quoted 3 lines · Christoph Egger
This patch crashes the host (and it doesn't disappear with the other patches applied):
err.. it crashes the host when the l1 guest boots the hvmloader invokes the VGA BIOS.
Quoted 201 lines
(XEN) Assertion '
pfn_to_pdx(ma>> PAGE_SHIFT)< (DIRECTMAP_SIZE>>PAGE_SHIFT)'
failed atxen/include/asm/x86_64/page.h:99
(XEN) ----[ Xen-4.2-unstablex86_64debug=y Tainted: C ]----
(XEN) CPU: 1
(XEN) RIP: e008:[<ffff82c4801d2007>]p2m_flush_locked+0x1a8/0x2be
(XEN) RFLAGS: 0000000000010212 CONTEXT: hypervisor(XEN) rax: 0000000000000000 rbx: ffff830421db1d90 rcx: 0000000000000000 (XEN) rdx: f82f608076a60000 rsi: 000f82f608076a60 rdi: 0000000000000000 (XEN) rbp: ffff830425217a08 rsp: ffff8304252179c8 r8: 0000000000000000 (XEN) r9: 0000000000000004 r10: 00000000fffffffb r11: 0000000000000003 (XEN) r12: ffff830421db1d90 r13: ffff82f608076a60 r14: ffff830403bbebe8 (XEN) r15: ffff830403bbe000 cr0: 000000008005003b cr4: 00000000000406f0 (XEN) cr3: 0000000420f2b000 cr2: 000000000045f000 (XEN) ds: 0017 es: 0017 fs: 0000 gs: 0000 ss: e010 cs: e008 (XEN) Xen stack trace from rsp=ffff8304252179c8: (XEN) ffff830403bbebe8 ffff830421db1d90 ffff830421db1d90 0000000000000000 (XEN) ffff830403bbe000 ffff830403bbebe8 ffff830403bbebe8 ffff830403bbeab0 (XEN) ffff830425217a38 ffff82c4801d2599 0000000000000001 0000000000000067 (XEN) ffff830403bbeab0 ffff830403af4000 ffff830425217a88 ffff82c480208a8c (XEN) 0000000125941810 ffff830403bbe000 0000000000000000 ffff830425217b18 (XEN) ffff830421db1cc0 00000000000ff000 ffffffffffffffff 0000000000000000 (XEN) ffff830425217a98 ffff82c4801ce585 ffff830425217b68 ffff82c4801d4b4e (XEN) 0000000000000200 1000000000000000 ffff830425217b28 ffff830425217b20 (XEN) 0000000000000001 ffff830425217ae8 ffff830425217ef8 ffff830403af4000 (XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000 (XEN) 0000000000000000 0000000000000000 0000000000000000 ffff830403af4000 (XEN) 0000000000403af4 ffff82c4801d5ec1 ffff830425217bfc ffffffffffffffff (XEN) 0000000000000000 0000000000000001 00000000000ff000 ffff830421db1cc0 (XEN) ffff830425217bb8 ffff82c4801d02d1 0000000100000007 ffff830403bbe000 (XEN) 0000000125217bc8 ffff8280019fafc0 ffff82c400cfd7e0 000000000033f5f8 (XEN) ffff830421db1cc0 0000000000000001 ffff830425217c28 ffff82c4801d053d (XEN) ffff830425217bfc ffff830425217bf8 0000000025217bf0 00000000000ff000 (XEN) 0000000000000001 ffff830425217c10 0000000000000007 ffff830421db1cc0 (XEN) ffff830421db1cc0 ffff830425217f18 ffff82c4802e1260 0000000000000000 (XEN) ffff830425217c78 ffff82c4801d11fa 000000000033f5f7 00000000000ff000 (XEN) Xen call trace: (XEN) [<ffff82c4801d2007>] p2m_flush_locked+0x1a8/0x2be (XEN) [<ffff82c4801d2599>] p2m_flush_nestedp2m+0xea/0x140 (XEN) [<ffff82c480208a8c>] hap_write_p2m_entry+0x223/0x246 (XEN) [<ffff82c4801ce585>] paging_write_p2m_entry+0x6e/0x75 (XEN) [<ffff82c4801d4b4e>] p2m_set_entry+0x42b/0x6a8 (XEN) [<ffff82c4801d02d1>] set_p2m_entry+0xf2/0x140 (XEN) [<ffff82c4801d053d>] p2m_remove_page+0x1dd/0x1ec (XEN) [<ffff82c4801d11fa>] guest_physmap_remove_page+0x109/0x148 (XEN) [<ffff82c480168000>] arch_memory_op+0x6af/0x1039 (XEN) [<ffff82c4801134fb>] do_memory_op+0x1bd7/0x1c2c (XEN) [<ffff82c480217708>] syscall_enter+0xc8/0x122(XEN)
(XEN)
(XEN) ****************************************Christoph
Quoted 144 lines · Tim Deegan
# HG changeset patch
# User Tim Deegan<[email protected]>
# Date 1308758648 -3600
# Node IDc323e69a0a08ce9f1e54d2e2fa2edd9845bc8efe
# Parentb7e5a25663329254cba539e21f4fbd5b32c67556Nested p2m: implement "flush" as a first-class action rather than using the teardown and init functions.
This makes the locking clearer and avoids an expensive scan of all pfns that's only needed for non-nested p2ms. It also moves the tlb flush into the proper place in the flush logic, avoiding a possible race against other CPUs.Signed-off-by Tim Deegan<[email protected]>diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/hvm/nestedhvm.cxen/arch/x86/hvm/nestedhvm.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/hvm/nestedhvm.c Tue Jun 21 18:28:53 2011 +0100 +0
-6@@ -119,12 +119,6 @@ nestedhvm_vmcx_flushtlb(struct p2m_domai cpus_clear(p2m->p2m_dirty_cpumask); } -void -nestedhvm_vmcx_flushtlbdomain(struct domain *d) -{ - on_selected_cpus(d->domain_dirty_cpumask, nestedhvm_flushtlb_ipi, d, 1); -} - bool_t nestedhvm_is_n2(struct vcpu *v) {diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +37
-23@@ -1050,20 +1050,41 @@ p2m_getlru_nestedp2m(struct domain *d, s return lrup2m; } -static int +/* Reset this p2m table to be empty */ +static void p2m_flush_locked(struct p2m_domain *p2m) { - ASSERT(p2m); - if (p2m->cr3 == CR3_EADDR) - /* Microoptimisation: p2m is already empty. - * => about 0.3% speedup of overall system performance. - */ - return 0; + struct page_info *top, *pg; + struct domain *d = p2m->domain; + void *p; - p2m_teardown(p2m); - p2m_initialise(p2m->domain, p2m); - p2m->write_p2m_entry = nestedp2m_write_p2m_entry; - return p2m_alloc_table(p2m); + p2m_lock(p2m); + + /* "Host" p2m tables can have shared entries&c that need a bit more + * care when discarding them */ + ASSERT(p2m_is_nestedp2m(p2m)); + ASSERT(page_list_empty(&p2m->pod.super)); + ASSERT(page_list_empty(&p2m->pod.single)); + + /* This is no longer a valid nested p2m for any address space */ + p2m->cr3 = CR3_EADDR; + + /* Zap the top level of the trie */ + top = mfn_to_page(pagetable_get_mfn(p2m_get_pagetable(p2m))); + p = map_domain_page(top); + clear_page(p); + unmap_domain_page(p); + + /* Make sure nobody else is using this p2m table */ + nestedhvm_vmcx_flushtlb(p2m); + + /* Free the rest of the trie pages back to the paging pool */ + while ( (pg = page_list_remove_head(&p2m->pages)) ) + if ( pg != top ) + d->arch.paging.free_page(d, pg); + page_list_add(top,&p2m->pages); + + p2m_unlock(p2m); } void@@ -1074,9 +1095,8 @@ p2m_flush(struct vcpu *v, struct p2m_dom ASSERT(v->domain == d); vcpu_nestedhvm(v).nv_p2m = NULL; nestedp2m_lock(d); - BUG_ON(p2m_flush_locked(p2m) != 0); + p2m_flush_locked(p2m); hvm_asid_flush_vcpu(v); - nestedhvm_vmcx_flushtlb(p2m); nestedp2m_unlock(d); }@@ -1086,12 +1106,8 @@ p2m_flush_nestedp2m(struct domain *d) int i; nestedp2m_lock(d); - for (i = 0; i< MAX_NESTEDP2M; i++) { - struct p2m_domain *p2m = d->arch.nested_p2m[i]; - BUG_ON(p2m_flush_locked(p2m) != 0); - cpus_clear(p2m->p2m_dirty_cpumask); - } - nestedhvm_vmcx_flushtlbdomain(d); + for ( i = 0; i< MAX_NESTEDP2M; i++ ) + p2m_flush_locked(d->arch.nested_p2m[i]); nestedp2m_unlock(d); }@@ -1104,7 +1120,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 volatile struct nestedvcpu *nv =&vcpu_nestedhvm(v); struct domain *d; struct p2m_domain *p2m; - int i, rv; + int i; if (cr3 == 0 || cr3 == CR3_EADDR) cr3 = v->arch.hvm_vcpu.guest_cr[3];@@ -1136,9 +1152,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 */ for (i = 0; i< MAX_NESTEDP2M; i++) { p2m = p2m_getlru_nestedp2m(d, NULL); - rv = p2m_flush_locked(p2m); - if (rv == 0) - break; + p2m_flush_locked(p2m); } nv->nv_p2m = p2m; p2m->cr3 = cr3;diff -r
b7e5a2566332-rc323e69a0a08xen/include/asm-x86/hvm/nestedhvm.hxen/include/asm-x86/hvm/nestedhvm.h Wed Jun 22 17:04:08 2011 +0100 renamed from xen/include/asm-x86/hvm/nestedhvm.h Tue Jun 21 18:28:53 2011 +0100 +0
-1@@ -61,7 +61,6 @@ unsigned long *nestedhvm_vcpu_iomap_get( (!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress) void nestedhvm_vmcx_flushtlb(struct p2m_domain *p2m); -void nestedhvm_vmcx_flushtlbdomain(struct domain *d); bool_t nestedhvm_is_n2(struct vcpu *v);
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: Re: [PATCH 1 of 4] Nested p2m: implement "flush" as a first-class action
I have a fix for this crash. See inline.
Christoph
Quoted 102 lines · Christoph Egger
Quoted 3 lines · Christoph Egger
This patch crashes the host (and it doesn't disappear with the other patches applied):
err.. it crashes the host when the l1 guest boots the hvmloader invokes the VGA BIOS.
Quoted 94 lines
(XEN) Assertion '
pfn_to_pdx(ma>> PAGE_SHIFT)< (DIRECTMAP_SIZE>>PAGE_SHIFT)'
failed atxen/include/asm/x86_64/page.h:99
(XEN) ----[ Xen-4.2-unstablex86_64debug=y Tainted: C ]----
(XEN) CPU: 1
(XEN) RIP: e008:[<ffff82c4801d2007>]p2m_flush_locked+0x1a8/0x2be
(XEN) RFLAGS: 0000000000010212 CONTEXT: hypervisor(XEN) rax: 0000000000000000 rbx: ffff830421db1d90 rcx: 0000000000000000 (XEN) rdx: f82f608076a60000 rsi: 000f82f608076a60 rdi: 0000000000000000 (XEN) rbp: ffff830425217a08 rsp: ffff8304252179c8 r8: 0000000000000000 (XEN) r9: 0000000000000004 r10: 00000000fffffffb r11: 0000000000000003 (XEN) r12: ffff830421db1d90 r13: ffff82f608076a60 r14: ffff830403bbebe8 (XEN) r15: ffff830403bbe000 cr0: 000000008005003b cr4: 00000000000406f0 (XEN) cr3: 0000000420f2b000 cr2: 000000000045f000 (XEN) ds: 0017 es: 0017 fs: 0000 gs: 0000 ss: e010 cs: e008 (XEN) Xen stack trace from rsp=ffff8304252179c8: (XEN) ffff830403bbebe8 ffff830421db1d90 ffff830421db1d90 0000000000000000 (XEN) ffff830403bbe000 ffff830403bbebe8 ffff830403bbebe8 ffff830403bbeab0 (XEN) ffff830425217a38 ffff82c4801d2599 0000000000000001 0000000000000067 (XEN) ffff830403bbeab0 ffff830403af4000 ffff830425217a88 ffff82c480208a8c (XEN) 0000000125941810 ffff830403bbe000 0000000000000000 ffff830425217b18 (XEN) ffff830421db1cc0 00000000000ff000 ffffffffffffffff 0000000000000000 (XEN) ffff830425217a98 ffff82c4801ce585 ffff830425217b68 ffff82c4801d4b4e (XEN) 0000000000000200 1000000000000000 ffff830425217b28 ffff830425217b20 (XEN) 0000000000000001 ffff830425217ae8 ffff830425217ef8 ffff830403af4000 (XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000 (XEN) 0000000000000000 0000000000000000 0000000000000000 ffff830403af4000 (XEN) 0000000000403af4 ffff82c4801d5ec1 ffff830425217bfc ffffffffffffffff (XEN) 0000000000000000 0000000000000001 00000000000ff000 ffff830421db1cc0 (XEN) ffff830425217bb8 ffff82c4801d02d1 0000000100000007 ffff830403bbe000 (XEN) 0000000125217bc8 ffff8280019fafc0 ffff82c400cfd7e0 000000000033f5f8 (XEN) ffff830421db1cc0 0000000000000001 ffff830425217c28 ffff82c4801d053d (XEN) ffff830425217bfc ffff830425217bf8 0000000025217bf0 00000000000ff000 (XEN) 0000000000000001 ffff830425217c10 0000000000000007 ffff830421db1cc0 (XEN) ffff830421db1cc0 ffff830425217f18 ffff82c4802e1260 0000000000000000 (XEN) ffff830425217c78 ffff82c4801d11fa 000000000033f5f7 00000000000ff000 (XEN) Xen call trace: (XEN) [<ffff82c4801d2007>] p2m_flush_locked+0x1a8/0x2be (XEN) [<ffff82c4801d2599>] p2m_flush_nestedp2m+0xea/0x140 (XEN) [<ffff82c480208a8c>] hap_write_p2m_entry+0x223/0x246 (XEN) [<ffff82c4801ce585>] paging_write_p2m_entry+0x6e/0x75 (XEN) [<ffff82c4801d4b4e>] p2m_set_entry+0x42b/0x6a8 (XEN) [<ffff82c4801d02d1>] set_p2m_entry+0xf2/0x140 (XEN) [<ffff82c4801d053d>] p2m_remove_page+0x1dd/0x1ec (XEN) [<ffff82c4801d11fa>] guest_physmap_remove_page+0x109/0x148 (XEN) [<ffff82c480168000>] arch_memory_op+0x6af/0x1039 (XEN) [<ffff82c4801134fb>] do_memory_op+0x1bd7/0x1c2c (XEN) [<ffff82c480217708>] syscall_enter+0xc8/0x122(XEN)
(XEN)
(XEN) ****************************************Christoph
Quoted 37 lines · Tim Deegan
# HG changeset patch
# User Tim Deegan<[email protected]>
# Date 1308758648 -3600
# Node IDc323e69a0a08ce9f1e54d2e2fa2edd9845bc8efe
# Parentb7e5a25663329254cba539e21f4fbd5b32c67556Nested p2m: implement "flush" as a first-class action rather than using the teardown and init functions.
This makes the locking clearer and avoids an expensive scan of all pfns that's only needed for non-nested p2ms. It also moves the tlb flush into the proper place in the flush logic, avoiding a possible race against other CPUs.Signed-off-by Tim Deegan<[email protected]>diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/hvm/nestedhvm.cxen/arch/x86/hvm/nestedhvm.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/hvm/nestedhvm.c Tue Jun 21 18:28:53 2011 +0100 +0
-6@@ -119,12 +119,6 @@ nestedhvm_vmcx_flushtlb(struct p2m_domai cpus_clear(p2m->p2m_dirty_cpumask); } -void -nestedhvm_vmcx_flushtlbdomain(struct domain *d) -{ - on_selected_cpus(d->domain_dirty_cpumask, nestedhvm_flushtlb_ipi, d, 1); -} - bool_t nestedhvm_is_n2(struct vcpu *v) {diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +0
-0@@ -1050,20 +1050,41 @@ p2m_getlru_nestedp2m(struct domain *d, s return lrup2m; }
Quoted 14 lines
Quoted 6 lines
Quoted 6 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +2
-2-static int +/* Reset this p2m table to be empty */ +static void p2m_flush_locked(struct p2m_domain *p2m) { - ASSERT(p2m);Quoted 8 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 p2m_getlru_nestedp2m(struct domain *d, s · line 1059
Quoted 8 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +3
-5- if (p2m->cr3 == CR3_EADDR) - /* Microoptimisation: p2m is already empty. - * => about 0.3% speedup of overall system performance. - */ - return 0; + struct page_info *top, *pg; + struct domain *d = p2m->domain; + void *p;
+ mfn_t top_mfn;
Quoted 17 lines
Quoted 17 lines
Quoted 7 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +2
-4- p2m_teardown(p2m); - p2m_initialise(p2m->domain, p2m); - p2m->write_p2m_entry = nestedp2m_write_p2m_entry; - return p2m_alloc_table(p2m); + p2m_lock(p2m); +xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 p2m_getlru_nestedp2m(struct domain *d, s · line 1071
Quoted 10 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +10
-0+ /* "Host" p2m tables can have shared entries&c that need a bit more + * care when discarding them */ + ASSERT(p2m_is_nestedp2m(p2m)); + ASSERT(page_list_empty(&p2m->pod.super)); + ASSERT(page_list_empty(&p2m->pod.single)); + + /* This is no longer a valid nested p2m for any address space */ + p2m->cr3 = CR3_EADDR; + + /* Zap the top level of the trie */
+ top_mfn = pagetable_get_mfn(p2m_get_pagetable(p2m)); + top = mfn_to_page(top_mfn); + p = map_domain_page(mfn_x(top_mfn));
Quoted 74 lines
Quoted 74 lines
Quoted 74 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +18
-12+ clear_page(p); + unmap_domain_page(p); + + /* Make sure nobody else is using this p2m table */ + nestedhvm_vmcx_flushtlb(p2m); + + /* Free the rest of the trie pages back to the paging pool */ + while ( (pg = page_list_remove_head(&p2m->pages)) ) + if ( pg != top ) + d->arch.paging.free_page(d, pg); + page_list_add(top,&p2m->pages); + + p2m_unlock(p2m); } void@@ -1074,9 +1095,8 @@ p2m_flush(struct vcpu *v, struct p2m_dom ASSERT(v->domain == d); vcpu_nestedhvm(v).nv_p2m = NULL; nestedp2m_lock(d); - BUG_ON(p2m_flush_locked(p2m) != 0); + p2m_flush_locked(p2m); hvm_asid_flush_vcpu(v); - nestedhvm_vmcx_flushtlb(p2m); nestedp2m_unlock(d); }@@ -1086,12 +1106,8 @@ p2m_flush_nestedp2m(struct domain *d) int i; nestedp2m_lock(d); - for (i = 0; i< MAX_NESTEDP2M; i++) { - struct p2m_domain *p2m = d->arch.nested_p2m[i]; - BUG_ON(p2m_flush_locked(p2m) != 0); - cpus_clear(p2m->p2m_dirty_cpumask); - } - nestedhvm_vmcx_flushtlbdomain(d); + for ( i = 0; i< MAX_NESTEDP2M; i++ ) + p2m_flush_locked(d->arch.nested_p2m[i]); nestedp2m_unlock(d); }@@ -1104,7 +1120,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 volatile struct nestedvcpu *nv =&vcpu_nestedhvm(v); struct domain *d; struct p2m_domain *p2m; - int i, rv; + int i; if (cr3 == 0 || cr3 == CR3_EADDR) cr3 = v->arch.hvm_vcpu.guest_cr[3];@@ -1136,9 +1152,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 */ for (i = 0; i< MAX_NESTEDP2M; i++) { p2m = p2m_getlru_nestedp2m(d, NULL); - rv = p2m_flush_locked(p2m); - if (rv == 0) - break; + p2m_flush_locked(p2m); } nv->nv_p2m = p2m; p2m->cr3 = cr3;diff -r
b7e5a2566332-rc323e69a0a08xen/include/asm-x86/hvm/nestedhvm.hxen/include/asm-x86/hvm/nestedhvm.h Wed Jun 22 17:04:08 2011 +0100 renamed from xen/include/asm-x86/hvm/nestedhvm.h Tue Jun 21 18:28:53 2011 +0100 +0
-1@@ -61,7 +61,6 @@ unsigned long *nestedhvm_vcpu_iomap_get( (!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress) void nestedhvm_vmcx_flushtlb(struct p2m_domain *p2m); -void nestedhvm_vmcx_flushtlbdomain(struct domain *d); bool_t nestedhvm_is_n2(struct vcpu *v);
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: Re: [PATCH 1 of 4] Nested p2m: implement "flush" as a first-class action
Now I see a significant slowdown of the L2 guest with multiple vcpus. The reason is I see 10 times more IPIs for each vcpu with p2m_flush_nestedp2m().
Please add back nestedhvm_vmcx_flushtlbdomain().
Christoph
Quoted 221 lines · Christoph Egger
I have a fix for this crash. See inline.
Christoph
Quoted 102 lines · Christoph Egger
Quoted 3 lines · Christoph Egger
This patch crashes the host (and it doesn't disappear with the other patches applied):
err.. it crashes the host when the l1 guest boots the hvmloader invokes the VGA BIOS.
Quoted 94 lines
(XEN) Assertion '
pfn_to_pdx(ma>> PAGE_SHIFT)< (DIRECTMAP_SIZE>>PAGE_SHIFT)'
failed atxen/include/asm/x86_64/page.h:99
(XEN) ----[ Xen-4.2-unstablex86_64debug=y Tainted: C ]----
(XEN) CPU: 1
(XEN) RIP: e008:[<ffff82c4801d2007>]p2m_flush_locked+0x1a8/0x2be
(XEN) RFLAGS: 0000000000010212 CONTEXT: hypervisor(XEN) rax: 0000000000000000 rbx: ffff830421db1d90 rcx: 0000000000000000 (XEN) rdx: f82f608076a60000 rsi: 000f82f608076a60 rdi: 0000000000000000 (XEN) rbp: ffff830425217a08 rsp: ffff8304252179c8 r8: 0000000000000000 (XEN) r9: 0000000000000004 r10: 00000000fffffffb r11: 0000000000000003 (XEN) r12: ffff830421db1d90 r13: ffff82f608076a60 r14: ffff830403bbebe8 (XEN) r15: ffff830403bbe000 cr0: 000000008005003b cr4: 00000000000406f0 (XEN) cr3: 0000000420f2b000 cr2: 000000000045f000 (XEN) ds: 0017 es: 0017 fs: 0000 gs: 0000 ss: e010 cs: e008 (XEN) Xen stack trace from rsp=ffff8304252179c8: (XEN) ffff830403bbebe8 ffff830421db1d90 ffff830421db1d90 0000000000000000 (XEN) ffff830403bbe000 ffff830403bbebe8 ffff830403bbebe8 ffff830403bbeab0 (XEN) ffff830425217a38 ffff82c4801d2599 0000000000000001 0000000000000067 (XEN) ffff830403bbeab0 ffff830403af4000 ffff830425217a88 ffff82c480208a8c (XEN) 0000000125941810 ffff830403bbe000 0000000000000000 ffff830425217b18 (XEN) ffff830421db1cc0 00000000000ff000 ffffffffffffffff 0000000000000000 (XEN) ffff830425217a98 ffff82c4801ce585 ffff830425217b68 ffff82c4801d4b4e (XEN) 0000000000000200 1000000000000000 ffff830425217b28 ffff830425217b20 (XEN) 0000000000000001 ffff830425217ae8 ffff830425217ef8 ffff830403af4000 (XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000 (XEN) 0000000000000000 0000000000000000 0000000000000000 ffff830403af4000 (XEN) 0000000000403af4 ffff82c4801d5ec1 ffff830425217bfc ffffffffffffffff (XEN) 0000000000000000 0000000000000001 00000000000ff000 ffff830421db1cc0 (XEN) ffff830425217bb8 ffff82c4801d02d1 0000000100000007 ffff830403bbe000 (XEN) 0000000125217bc8 ffff8280019fafc0 ffff82c400cfd7e0 000000000033f5f8 (XEN) ffff830421db1cc0 0000000000000001 ffff830425217c28 ffff82c4801d053d (XEN) ffff830425217bfc ffff830425217bf8 0000000025217bf0 00000000000ff000 (XEN) 0000000000000001 ffff830425217c10 0000000000000007 ffff830421db1cc0 (XEN) ffff830421db1cc0 ffff830425217f18 ffff82c4802e1260 0000000000000000 (XEN) ffff830425217c78 ffff82c4801d11fa 000000000033f5f7 00000000000ff000 (XEN) Xen call trace: (XEN) [<ffff82c4801d2007>] p2m_flush_locked+0x1a8/0x2be (XEN) [<ffff82c4801d2599>] p2m_flush_nestedp2m+0xea/0x140 (XEN) [<ffff82c480208a8c>] hap_write_p2m_entry+0x223/0x246 (XEN) [<ffff82c4801ce585>] paging_write_p2m_entry+0x6e/0x75 (XEN) [<ffff82c4801d4b4e>] p2m_set_entry+0x42b/0x6a8 (XEN) [<ffff82c4801d02d1>] set_p2m_entry+0xf2/0x140 (XEN) [<ffff82c4801d053d>] p2m_remove_page+0x1dd/0x1ec (XEN) [<ffff82c4801d11fa>] guest_physmap_remove_page+0x109/0x148 (XEN) [<ffff82c480168000>] arch_memory_op+0x6af/0x1039 (XEN) [<ffff82c4801134fb>] do_memory_op+0x1bd7/0x1c2c (XEN) [<ffff82c480217708>] syscall_enter+0xc8/0x122(XEN)
(XEN)
(XEN) ****************************************Christoph
Quoted 37 lines · Tim Deegan
# HG changeset patch
# User Tim Deegan<[email protected]>
# Date 1308758648 -3600
# Node IDc323e69a0a08ce9f1e54d2e2fa2edd9845bc8efe
# Parentb7e5a25663329254cba539e21f4fbd5b32c67556Nested p2m: implement "flush" as a first-class action rather than using the teardown and init functions.
This makes the locking clearer and avoids an expensive scan of all pfns that's only needed for non-nested p2ms. It also moves the tlb flush into the proper place in the flush logic, avoiding a possible race against other CPUs.Signed-off-by Tim Deegan<[email protected]>diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/hvm/nestedhvm.cxen/arch/x86/hvm/nestedhvm.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/hvm/nestedhvm.c Tue Jun 21 18:28:53 2011 +0100 +0
-6@@ -119,12 +119,6 @@ nestedhvm_vmcx_flushtlb(struct p2m_domai cpus_clear(p2m->p2m_dirty_cpumask); } -void -nestedhvm_vmcx_flushtlbdomain(struct domain *d) -{ - on_selected_cpus(d->domain_dirty_cpumask, nestedhvm_flushtlb_ipi, d, 1); -} - bool_t nestedhvm_is_n2(struct vcpu *v) {diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +0
-0@@ -1050,20 +1050,41 @@ p2m_getlru_nestedp2m(struct domain *d, s return lrup2m; }Quoted 14 lines
Quoted 6 lines
Quoted 6 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +2
-2-static int +/* Reset this p2m table to be empty */ +static void p2m_flush_locked(struct p2m_domain *p2m) { - ASSERT(p2m);Quoted 8 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 p2m_getlru_nestedp2m(struct domain *d, s · line 1059
Quoted 8 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +3
-5- if (p2m->cr3 == CR3_EADDR) - /* Microoptimisation: p2m is already empty. - * => about 0.3% speedup of overall system performance. - */ - return 0; + struct page_info *top, *pg; + struct domain *d = p2m->domain; + void *p;+
mfn_ttop_mfn;Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +12
-4- p2m_teardown(p2m); - p2m_initialise(p2m->domain, p2m); - p2m->write_p2m_entry = nestedp2m_write_p2m_entry; - return p2m_alloc_table(p2m); + p2m_lock(p2m); + + /* "Host" p2m tables can have shared entries&c that need a bit more + * care when discarding them */ + ASSERT(p2m_is_nestedp2m(p2m)); + ASSERT(page_list_empty(&p2m->pod.super)); + ASSERT(page_list_empty(&p2m->pod.single)); + + /* This is no longer a valid nested p2m for any address space */ + p2m->cr3 = CR3_EADDR; + + /* Zap the top level of the trie */(quoted diff) +3
-0+ top_mfn = pagetable_get_mfn(p2m_get_pagetable(p2m)); + top = mfn_to_page(top_mfn); + p = map_domain_page(mfn_x(top_mfn));Quoted 75 lines
Quoted 75 lines
Quoted 75 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +18
-12+ clear_page(p); + unmap_domain_page(p); + + /* Make sure nobody else is using this p2m table */ + nestedhvm_vmcx_flushtlb(p2m); + + /* Free the rest of the trie pages back to the paging pool */ + while ( (pg = page_list_remove_head(&p2m->pages)) ) + if ( pg != top ) + d->arch.paging.free_page(d, pg); + page_list_add(top,&p2m->pages); + + p2m_unlock(p2m); } void@@ -1074,9 +1095,8 @@ p2m_flush(struct vcpu *v, struct p2m_dom ASSERT(v->domain == d); vcpu_nestedhvm(v).nv_p2m = NULL; nestedp2m_lock(d); - BUG_ON(p2m_flush_locked(p2m) != 0); + p2m_flush_locked(p2m); hvm_asid_flush_vcpu(v); - nestedhvm_vmcx_flushtlb(p2m); nestedp2m_unlock(d); }@@ -1086,12 +1106,8 @@ p2m_flush_nestedp2m(struct domain *d) int i; nestedp2m_lock(d); - for (i = 0; i< MAX_NESTEDP2M; i++) { - struct p2m_domain *p2m = d->arch.nested_p2m[i]; - BUG_ON(p2m_flush_locked(p2m) != 0); - cpus_clear(p2m->p2m_dirty_cpumask); - } - nestedhvm_vmcx_flushtlbdomain(d); + for ( i = 0; i< MAX_NESTEDP2M; i++ ) + p2m_flush_locked(d->arch.nested_p2m[i]); nestedp2m_unlock(d); }@@ -1104,7 +1120,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 volatile struct nestedvcpu *nv =&vcpu_nestedhvm(v); struct domain *d; struct p2m_domain *p2m; - int i, rv; + int i; if (cr3 == 0 || cr3 == CR3_EADDR) cr3 = v->arch.hvm_vcpu.guest_cr[3];@@ -1136,9 +1152,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 */ for (i = 0; i< MAX_NESTEDP2M; i++) { p2m = p2m_getlru_nestedp2m(d, NULL); - rv = p2m_flush_locked(p2m); - if (rv == 0) - break; + p2m_flush_locked(p2m); } nv->nv_p2m = p2m; p2m->cr3 = cr3;diff -r
b7e5a2566332-rc323e69a0a08xen/include/asm-x86/hvm/nestedhvm.hxen/include/asm-x86/hvm/nestedhvm.h Wed Jun 22 17:04:08 2011 +0100 renamed from xen/include/asm-x86/hvm/nestedhvm.h Tue Jun 21 18:28:53 2011 +0100 +0
-1@@ -61,7 +61,6 @@ unsigned long *nestedhvm_vcpu_iomap_get( (!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress) void nestedhvm_vmcx_flushtlb(struct p2m_domain *p2m); -void nestedhvm_vmcx_flushtlbdomain(struct domain *d); bool_t nestedhvm_is_n2(struct vcpu *v);
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: Re: [PATCH 1 of 4] Nested p2m: implement "flush" as a first-class action
Quoted 6 lines · Christoph Egger
Now I see a significant slowdown of the L2 guest with multiple vcpus. The reason is I see 10 times more IPIs for each vcpu with
p2m_flush_nestedp2m().Please add back
nestedhvm_vmcx_flushtlbdomain().
It wasn't safe. You need to kick other CPUs off the p2m table before you free its memory. But I'll look into avoiding those IPIs.
Tim.
Quoted 237 lines · Christoph Egger
Quoted 221 lines
I have a fix for this crash. See inline.
Christoph
Quoted 102 lines · Christoph Egger
Quoted 3 lines · Christoph Egger
This patch crashes the host (and it doesn't disappear with the other patches applied):
err.. it crashes the host when the l1 guest boots the hvmloader invokes the VGA BIOS.
Quoted 94 lines
(XEN) Assertion '
pfn_to_pdx(ma>> PAGE_SHIFT)< (DIRECTMAP_SIZE>>PAGE_SHIFT)'
failed atxen/include/asm/x86_64/page.h:99
(XEN) ----[ Xen-4.2-unstablex86_64debug=y Tainted: C ]----
(XEN) CPU: 1
(XEN) RIP: e008:[<ffff82c4801d2007>]p2m_flush_locked+0x1a8/0x2be
(XEN) RFLAGS: 0000000000010212 CONTEXT: hypervisor(XEN) rax: 0000000000000000 rbx: ffff830421db1d90 rcx: 0000000000000000 (XEN) rdx: f82f608076a60000 rsi: 000f82f608076a60 rdi: 0000000000000000 (XEN) rbp: ffff830425217a08 rsp: ffff8304252179c8 r8: 0000000000000000 (XEN) r9: 0000000000000004 r10: 00000000fffffffb r11: 0000000000000003 (XEN) r12: ffff830421db1d90 r13: ffff82f608076a60 r14: ffff830403bbebe8 (XEN) r15: ffff830403bbe000 cr0: 000000008005003b cr4: 00000000000406f0 (XEN) cr3: 0000000420f2b000 cr2: 000000000045f000 (XEN) ds: 0017 es: 0017 fs: 0000 gs: 0000 ss: e010 cs: e008 (XEN) Xen stack trace from rsp=ffff8304252179c8: (XEN) ffff830403bbebe8 ffff830421db1d90 ffff830421db1d90 0000000000000000 (XEN) ffff830403bbe000 ffff830403bbebe8 ffff830403bbebe8 ffff830403bbeab0 (XEN) ffff830425217a38 ffff82c4801d2599 0000000000000001 0000000000000067 (XEN) ffff830403bbeab0 ffff830403af4000 ffff830425217a88 ffff82c480208a8c (XEN) 0000000125941810 ffff830403bbe000 0000000000000000 ffff830425217b18 (XEN) ffff830421db1cc0 00000000000ff000 ffffffffffffffff 0000000000000000 (XEN) ffff830425217a98 ffff82c4801ce585 ffff830425217b68 ffff82c4801d4b4e (XEN) 0000000000000200 1000000000000000 ffff830425217b28 ffff830425217b20 (XEN) 0000000000000001 ffff830425217ae8 ffff830425217ef8 ffff830403af4000 (XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000 (XEN) 0000000000000000 0000000000000000 0000000000000000 ffff830403af4000 (XEN) 0000000000403af4 ffff82c4801d5ec1 ffff830425217bfc ffffffffffffffff (XEN) 0000000000000000 0000000000000001 00000000000ff000 ffff830421db1cc0 (XEN) ffff830425217bb8 ffff82c4801d02d1 0000000100000007 ffff830403bbe000 (XEN) 0000000125217bc8 ffff8280019fafc0 ffff82c400cfd7e0 000000000033f5f8 (XEN) ffff830421db1cc0 0000000000000001 ffff830425217c28 ffff82c4801d053d (XEN) ffff830425217bfc ffff830425217bf8 0000000025217bf0 00000000000ff000 (XEN) 0000000000000001 ffff830425217c10 0000000000000007 ffff830421db1cc0 (XEN) ffff830421db1cc0 ffff830425217f18 ffff82c4802e1260 0000000000000000 (XEN) ffff830425217c78 ffff82c4801d11fa 000000000033f5f7 00000000000ff000 (XEN) Xen call trace: (XEN) [<ffff82c4801d2007>] p2m_flush_locked+0x1a8/0x2be (XEN) [<ffff82c4801d2599>] p2m_flush_nestedp2m+0xea/0x140 (XEN) [<ffff82c480208a8c>] hap_write_p2m_entry+0x223/0x246 (XEN) [<ffff82c4801ce585>] paging_write_p2m_entry+0x6e/0x75 (XEN) [<ffff82c4801d4b4e>] p2m_set_entry+0x42b/0x6a8 (XEN) [<ffff82c4801d02d1>] set_p2m_entry+0xf2/0x140 (XEN) [<ffff82c4801d053d>] p2m_remove_page+0x1dd/0x1ec (XEN) [<ffff82c4801d11fa>] guest_physmap_remove_page+0x109/0x148 (XEN) [<ffff82c480168000>] arch_memory_op+0x6af/0x1039 (XEN) [<ffff82c4801134fb>] do_memory_op+0x1bd7/0x1c2c (XEN) [<ffff82c480217708>] syscall_enter+0xc8/0x122(XEN)
(XEN)
(XEN) ****************************************Christoph
Quoted 37 lines · Tim Deegan
# HG changeset patch
# User Tim Deegan<[email protected]>
# Date 1308758648 -3600
# Node IDc323e69a0a08ce9f1e54d2e2fa2edd9845bc8efe
# Parentb7e5a25663329254cba539e21f4fbd5b32c67556Nested p2m: implement "flush" as a first-class action rather than using the teardown and init functions.
This makes the locking clearer and avoids an expensive scan of all pfns that's only needed for non-nested p2ms. It also moves the tlb flush into the proper place in the flush logic, avoiding a possible race against other CPUs.Signed-off-by Tim Deegan<[email protected]>diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/hvm/nestedhvm.cxen/arch/x86/hvm/nestedhvm.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/hvm/nestedhvm.c Tue Jun 21 18:28:53 2011 +0100 +0
-6@@ -119,12 +119,6 @@ nestedhvm_vmcx_flushtlb(struct p2m_domai cpus_clear(p2m->p2m_dirty_cpumask); } -void -nestedhvm_vmcx_flushtlbdomain(struct domain *d) -{ - on_selected_cpus(d->domain_dirty_cpumask, nestedhvm_flushtlb_ipi, d, 1); -} - bool_t nestedhvm_is_n2(struct vcpu *v) {diff -r
b7e5a2566332-rc323e69a0a08xen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +0
-0@@ -1050,20 +1050,41 @@ p2m_getlru_nestedp2m(struct domain *d, s return lrup2m; }Quoted 14 lines
Quoted 6 lines
Quoted 6 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +2
-2-static int +/* Reset this p2m table to be empty */ +static void p2m_flush_locked(struct p2m_domain *p2m) { - ASSERT(p2m);Quoted 8 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 p2m_getlru_nestedp2m(struct domain *d, s · line 1059
Quoted 8 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +3
-5- if (p2m->cr3 == CR3_EADDR) - /* Microoptimisation: p2m is already empty. - * => about 0.3% speedup of overall system performance. - */ - return 0; + struct page_info *top, *pg; + struct domain *d = p2m->domain; + void *p;+
mfn_ttop_mfn;Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +12
-4- p2m_teardown(p2m); - p2m_initialise(p2m->domain, p2m); - p2m->write_p2m_entry = nestedp2m_write_p2m_entry; - return p2m_alloc_table(p2m); + p2m_lock(p2m); + + /* "Host" p2m tables can have shared entries&c that need a bit more + * care when discarding them */ + ASSERT(p2m_is_nestedp2m(p2m)); + ASSERT(page_list_empty(&p2m->pod.super)); + ASSERT(page_list_empty(&p2m->pod.single)); + + /* This is no longer a valid nested p2m for any address space */ + p2m->cr3 = CR3_EADDR; + + /* Zap the top level of the trie */(quoted diff) +3
-0+ top_mfn = pagetable_get_mfn(p2m_get_pagetable(p2m)); + top = mfn_to_page(top_mfn); + p = map_domain_page(mfn_x(top_mfn));Quoted 75 lines
Quoted 75 lines
Quoted 75 lines
xen/arch/x86/mm/p2m.c Wed Jun 22 17:04:08 2011 +0100 renamed from xen/arch/x86/mm/p2m.c Tue Jun 21 18:28:53 2011 +0100 +18
-12+ clear_page(p); + unmap_domain_page(p); + + /* Make sure nobody else is using this p2m table */ + nestedhvm_vmcx_flushtlb(p2m); + + /* Free the rest of the trie pages back to the paging pool */ + while ( (pg = page_list_remove_head(&p2m->pages)) ) + if ( pg != top ) + d->arch.paging.free_page(d, pg); + page_list_add(top,&p2m->pages); + + p2m_unlock(p2m); } void@@ -1074,9 +1095,8 @@ p2m_flush(struct vcpu *v, struct p2m_dom ASSERT(v->domain == d); vcpu_nestedhvm(v).nv_p2m = NULL; nestedp2m_lock(d); - BUG_ON(p2m_flush_locked(p2m) != 0); + p2m_flush_locked(p2m); hvm_asid_flush_vcpu(v); - nestedhvm_vmcx_flushtlb(p2m); nestedp2m_unlock(d); }@@ -1086,12 +1106,8 @@ p2m_flush_nestedp2m(struct domain *d) int i; nestedp2m_lock(d); - for (i = 0; i< MAX_NESTEDP2M; i++) { - struct p2m_domain *p2m = d->arch.nested_p2m[i]; - BUG_ON(p2m_flush_locked(p2m) != 0); - cpus_clear(p2m->p2m_dirty_cpumask); - } - nestedhvm_vmcx_flushtlbdomain(d); + for ( i = 0; i< MAX_NESTEDP2M; i++ ) + p2m_flush_locked(d->arch.nested_p2m[i]); nestedp2m_unlock(d); }@@ -1104,7 +1120,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 volatile struct nestedvcpu *nv =&vcpu_nestedhvm(v); struct domain *d; struct p2m_domain *p2m; - int i, rv; + int i; if (cr3 == 0 || cr3 == CR3_EADDR) cr3 = v->arch.hvm_vcpu.guest_cr[3];@@ -1136,9 +1152,7 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 */ for (i = 0; i< MAX_NESTEDP2M; i++) { p2m = p2m_getlru_nestedp2m(d, NULL); - rv = p2m_flush_locked(p2m); - if (rv == 0) - break; + p2m_flush_locked(p2m); } nv->nv_p2m = p2m; p2m->cr3 = cr3;diff -r
b7e5a2566332-rc323e69a0a08xen/include/asm-x86/hvm/nestedhvm.hxen/include/asm-x86/hvm/nestedhvm.h Wed Jun 22 17:04:08 2011 +0100 renamed from xen/include/asm-x86/hvm/nestedhvm.h Tue Jun 21 18:28:53 2011 +0100 +0
-1@@ -61,7 +61,6 @@ unsigned long *nestedhvm_vcpu_iomap_get( (!!vcpu_nestedhvm((v)).nv_vmswitch_in_progress) void nestedhvm_vmcx_flushtlb(struct p2m_domain *p2m); -void nestedhvm_vmcx_flushtlbdomain(struct domain *d); bool_t nestedhvm_is_n2(struct vcpu *v);Signature · 12 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632 _______________________________________________ Xen-devel mailing list [email protected] http://lists.xensource.com/xen-devel
Signature · 3 lines
Tim Deegan <[email protected]> Principal Software Engineer, Xen Platform Team Citrix Systems UK Ltd. (Company #02937203, SL9 0BG)
PATCH 1/1 Nested p2m: remove bogus check of CR3 value
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]> # Date 1308758648 -3600
# Node ID dcb8ae5e3eaf6516c889087dfb15efa41a1ac3e9 # Parent c323e69a0a08ce9f1e54d2e2fa2edd9845bc8efe Nested p2m: remove bogus check of CR3 value.
0 is a valid CR3 value; CR3_EADDR isn't but there's nothing stopping a guest from putting it in its VMCB. The special case was broken anyway since AFAICT "p2m->cr3" is a nester-cr3 (i.e. p2m-table) value and guest_cr[3] is an actual-cr3 (pagetable) value.
xen/arch/x86/mm/p2m.c +2 -2
@@ -1122,8 +1122,8 @@ p2m_get_nestedp2m(struct vcpu *v, uint64struct p2m_domain *p2m;int i; -if (cr3 ==0 || cr3 ==CR3_EADDR ) - cr3 = v->arch.hvm_vcpu.guest_cr[3 ]; +/* Mask out low bits; this avoids collisions with CR3_EADDR */ + cr3 &= ~(0xfffull );if (nv->nv_flushp2m && nv->nv_p2m) { nv->nv_p2m =NULL ;
PATCH 1/1 Nested p2m: clarify logic in p2m_get_nestedp2m()
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]> # Date 1308758648 -3600
# Node ID b265371addbbc8a58c95a269fe3cd0fdc866aaa3 # Parent dcb8ae5e3eaf6516c889087dfb15efa41a1ac3e9 Nested p2m: clarify logic in p2m_get_nestedp2m()
This just makes the behaviour of this function a bit more explicit. It may be that it also needs to be changed. :)
xen/arch/x86/mm/p2m.c +3 -5
@@ -1131,11 +1131,9 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 d = v->domain;nestedp2m_lock (d); -for (i =0 ; i <MAX_NESTEDP2M ; i++) { - p2m = d->arch.nested_p2m[i]; -if ((p2m->cr3 != cr3 && p2m->cr3 !=CR3_EADDR ) || (p2m != nv->nv_p2m)) -continue ; - + p2m = nv->nv_p2m; +if ( p2m && (p2m->cr3 == cr3 || p2m->cr3 ==CR3_EADDR ) ) + { nv->nv_flushp2m =0 ;p2m_getlru_nestedp2m (d, p2m); nv->nv_p2m = p2m;
Re: [PATCH 3 of 4] Nested p2m: clarify logic in p2m_get_nestedp2m()
Quoted 21 lines · Tim Deegan
# HG changeset patch
# User Tim Deegan<[email protected]>
# Date 1308758648 -3600
# Node IDb265371addbbc8a58c95a269fe3cd0fdc866aaa3# Parentdcb8ae5e3eaf6516c889087dfb15efa41a1ac3e9Nested p2m: clarify logic inp2m_get_nestedp2m()This just makes the behaviour of this function a bit more explicit. It may be that it also needs to be changed. :)
Signed-off-by Tim Deegan<[email protected]>diff -r
dcb8ae5e3eaf-rb265371addbbxen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c +0
-1@@ -1131,11 +1131,9 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 d = v->domain;nestedp2m_lock (d); -for (i =0 ; i<MAX_NESTEDP2M ; i++) {
xen/arch/x86/mm/p2m.c p2m_get_nestedp2m(struct vcpu *v, uint64 · line 1139
Quoted 10 lines
xen/arch/x86/mm/p2m.c +3
-4- p2m = d->arch.nested_p2m[i]; -if ((p2m->cr3 != cr3&& p2m->cr3 !=CR3_EADDR ) || (p2m != nv->nv_p2m)) -continue ; - + p2m = nv->nv_p2m; +if ( p2m&& (p2m->cr3 == cr3 || p2m->cr3 ==CR3_EADDR ) ) + { nv->nv_flushp2m =0 ;p2m_getlru_nestedp2m (d, p2m); nv->nv_p2m = p2m;
Ok, thanks.
In p2m_get_nestedp2m() replace this code hunk
for (i = 0; i < MAX_NESTEDP2M; i++) {
p2m = p2m_getlru_nestedp2m(d, NULL);
p2m_flush_locked(p2m);
}with
p2m = p2m_getlru_nestedp2m(d, NULL);
p2m_flush_locked(p2m);The 'i'' variable is unused then. This fixes an endless loop of nested page faults I observe with SMP l2 guests.
The nested page fault loop happens in conjunction with the change in patch 4 in nestedhap_fix_p2m().
Christoph
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: [PATCH 3 of 4] Nested p2m: clarify logic in p2m_get_nestedp2m()
Quoted 30 lines · Christoph Egger
Quoted 9 lines
diff -r
dcb8ae5e3eaf-rb265371addbbxen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c +0
-1@@ -1131,11 +1131,9 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 d = v->domain;nestedp2m_lock (d); -for (i =0 ; i<MAX_NESTEDP2M ; i++) {xen/arch/x86/mm/p2m.c p2m_get_nestedp2m(struct vcpu *v, uint64 · line 1139
Quoted 10 lines
xen/arch/x86/mm/p2m.c +3
-4- p2m = d->arch.nested_p2m[i]; -if ((p2m->cr3 != cr3&& p2m->cr3 !=CR3_EADDR ) || (p2m != nv->nv_p2m)) -continue ; - + p2m = nv->nv_p2m; +if ( p2m&& (p2m->cr3 == cr3 || p2m->cr3 ==CR3_EADDR ) ) + { nv->nv_flushp2m =0 ;p2m_getlru_nestedp2m (d, p2m); nv->nv_p2m = p2m;Ok, thanks.
In
p2m_get_nestedp2m()replace this code hunkfor (i = 0; i < MAX_NESTEDP2M; i++) { p2m = p2m_getlru_nestedp2m(d, NULL); p2m_flush_locked(p2m); }
Quoted 4 lines
with
p2m = p2m_getlru_nestedp2m(d, NULL); p2m_flush_locked(p2m);
That seems like an improvement. I'll put it into my queue.
More generally, I think that you need to figure out exactly what behaviour you want from this function. For example in the current code there's no way that two vcpus with the same ncr3 value can share a nested-p2m. Is that deliberate?
Cheers,
Tim.
Signature · 3 lines
Tim Deegan <[email protected]> Principal Software Engineer, Xen Platform Team Citrix Systems UK Ltd. (Company #02937203, SL9 0BG)
Re: [PATCH 3 of 4] Nested p2m: clarify logic in p2m_get_nestedp2m()
Quoted 36 lines · Tim Deegan
Quoted 30 lines · Christoph Egger
Quoted 9 lines
diff -r
dcb8ae5e3eaf-rb265371addbbxen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c +0
-1@@ -1131,11 +1131,9 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 d = v->domain;nestedp2m_lock (d); -for (i =0 ; i<MAX_NESTEDP2M ; i++) {xen/arch/x86/mm/p2m.c p2m_get_nestedp2m(struct vcpu *v, uint64 · line 1139
Quoted 10 lines
xen/arch/x86/mm/p2m.c +3
-4- p2m = d->arch.nested_p2m[i]; -if ((p2m->cr3 != cr3&& p2m->cr3 !=CR3_EADDR ) || (p2m != nv->nv_p2m)) -continue ; - + p2m = nv->nv_p2m; +if ( p2m&& (p2m->cr3 == cr3 || p2m->cr3 ==CR3_EADDR ) ) + { nv->nv_flushp2m =0 ;p2m_getlru_nestedp2m (d, p2m); nv->nv_p2m = p2m;Ok, thanks.
In
p2m_get_nestedp2m()replace this code hunkfor (i = 0; i< MAX_NESTEDP2M; i++) { p2m = p2m_getlru_nestedp2m(d, NULL); p2m_flush_locked(p2m); }Quoted 4 lines
with
p2m = p2m_getlru_nestedp2m(d, NULL); p2m_flush_locked(p2m);
Quoted 6 lines
That seems like an improvement. I'll put it into my queue.
More generally, I think that you need to figure out exactly what behaviour you want from this function. For example in the current code there's no way that two vcpus with the same ncr3 value can share a nested-p2m. Is that deliberate?
By 'current code' do you mean with or w/o this patch ?
It is deliberate that two vcpus with the same ncr3 share a nested-p2m. But fixing the p2m locking problem in upstream tree has a higher priority right now and we can work on that after the p2m locking issue is fixed upstream.
Christoph
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: [PATCH 3 of 4] Nested p2m: clarify logic in p2m_get_nestedp2m()
Hi,
Quoted 6 lines · Christoph Egger
Quoted 4 lines
More generally, I think that you need to figure out exactly what behaviour you want from this function. For example in the current code there's no way that two vcpus with the same ncr3 value can share a nested-p2m. Is that deliberate?
By 'current code' do you mean with or w/o this patch ?
Both, and all versions of the code from before my current series to the full series applied.
Quoted 1 line
It is deliberate that two vcpus with the same ncr3 share a nested-p2m.
But they don't. The code in current unstable tip does this:
for (i = 0; i < MAX_NESTEDP2M; i++) {
p2m = d->arch.nested_p2m[i];
if ((p2m->cr3 != cr3 && p2m->cr3 != CR3_EADDR) || (p2m != nv->nv_p2m))
continue;
// ... return this p2m
}
/* All p2m's are or were in use. Take the least recent used one,
* flush it and reuse.
*/
for (i = 0; i < MAX_NESTEDP2M; i++) {
p2m = p2m_getlru_nestedp2m(d, NULL);
rv = p2m_flush_locked(p2m);
if (rv == 0)
break;
}
// ... return this p2mThe first loop never returns a p2m that's != nv->nv_p2m. The second loop always returns a fresh, flushed p2m. So there's no way that two different vcpus, starting with nv->nv_p2m == NULL, can ever get the same p2m as each other.
The pseudocode is basically:
- If I have an existing nv_p2m and it hasn't been flushed, reuse it.
- Else flush all np2ms in LRU order and return the last one flushed.
My patch 3/4 doesn't change the logic at all (I think); your latest fix just avoids the over-aggressive flushing of all np2ms.
Quoted 3 lines
But fixing the p2m locking problem in upstream tree has a higher priority right now and we can work on that after the p2m locking issue is fixed upstream.
AFAICS the locking is fixed by the current set of patches (though I'm still not able to run Xen-in-Xen well enough to test them). I can send the full series again for clarity if you like. The outstanding bug is that there are many more IPIs than previously; I suspect that your latest fix will reduce them quite a lot by avoiding a storm of mutually-destructive flush operations. If the performance is still too bad we can add more IPI-avoidance strategies.
Cheers,
Tim.
Signature · 3 lines
Tim Deegan <[email protected]> Principal Software Engineer, Xen Platform Team Citrix Systems UK Ltd. (Company #02937203, SL9 0BG)
Re: [PATCH 3 of 4] Nested p2m: clarify logic in p2m_get_nestedp2m()
Quoted 37 lines · Tim Deegan
Hi,
Quoted 6 lines · Christoph Egger
Quoted 4 lines
More generally, I think that you need to figure out exactly what behaviour you want from this function. For example in the current code there's no way that two vcpus with the same ncr3 value can share a nested-p2m. Is that deliberate?
By 'current code' do you mean with or w/o this patch ?
Both, and all versions of the code from before my current series to the full series applied.
Quoted 1 line
It is deliberate that two vcpus with the same ncr3 share a nested-p2m.
But they don't. The code in current unstable tip does this:
for (i = 0; i< MAX_NESTEDP2M; i++) { p2m = d->arch.nested_p2m[i]; if ((p2m->cr3 != cr3&& p2m->cr3 != CR3_EADDR) || (p2m != nv->nv_p2m)) continue; // ... return this p2m } /* All p2m's are or were in use. Take the least recent used one, * flush it and reuse. */ for (i = 0; i< MAX_NESTEDP2M; i++) { p2m = p2m_getlru_nestedp2m(d, NULL); rv = p2m_flush_locked(p2m); if (rv == 0) break; } // ... return this p2m
Quoted 8 lines
The first loop never returns a p2m that's !=
nv->nv_p2m. The second loop always returns a fresh, flushed p2m. So there's no way that two different vcpus, starting withnv->nv_p2m== NULL, can ever get the same p2m as each other.The pseudocode is basically:
- If I have an existingnv_p2mand it hasn't been flushed, reuse it.
- Else flush all np2ms in LRU order and return the last one flushed.
I see. Thanks.
Quoted 2 lines
My patch 3/4 doesn't change the logic at all (I think); your latest fix just avoids the over-aggressive flushing of all np2ms.
Yes and results in a noticable performance boost.
Quoted 5 lines
Quoted 3 lines
But fixing the p2m locking problem in upstream tree has a higher priority right now and we can work on that after the p2m locking issue is fixed upstream.
AFAICS the locking is fixed by the current set of patches
Yes, I can confirm that. patch 4 fixes it.
Quoted 1 line
(though I'm still not able to run Xen-in-Xen well enough to test them).
Can you describe what problem you are facing? Is it a hanging L1 Dom0 ? Does L1 Dom0 not see the SVM cpuid feature bit?
Quoted 1 line
I can send the full series again for clarity if you like.
Yes, please!
Quoted 3 lines
The outstanding bug is that there are many more IPIs than previously; I suspect that your latest fix will reduce them quite a lot by avoiding a storm of mutually-destructive flush operations.
Yes because p2m_flush_nestedp2m() runs less often.
The number of sent IPIs from p2m_flush_nestedp2m() is still 10 times higher.
Quoted 1 line
If the performance is still too bad we can add more IPI-avoidance strategies.
Yes, this still brings significant performance for L3 guests because both host and l1 guest send less IPIs then.
We can do this performance improvement in a seperate patch series.
Christoph
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
PATCH 1/1 Nested p2m: rework locking around nested-p2m flushes and updates
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1308758840 -3600
# Node ID a168af9b6d2f604c841465e5ed911b7a12b5ba15
# Parent b265371addbbc8a58c95a269fe3cd0fdc866aaa3 Nested p2m: rework locking around nested-p2m flushes and updates.
The nestedp2m_lock now only covers the mapping from nested-cr3 to nested-p2m; the tables themselves may be updated or flushed using only the relevant p2m lock.
This means that the nested-p2m lock is only taken on one path, and always before any p2m locks.
xen/arch/x86/mm/hap/nested_hap.c +13 -9
@@ -96,17 +96,23 @@ nestedp2m_write_p2m_entry(struct p2m_dom/* NESTED VIRT FUNCTIONS */ /********************************************/ static void -nestedhap_fix_p2m (struct p2m_domain *p2m,paddr_t L2_gpa,paddr_t L0_gpa, -p2m_type_t p2mt,p2m_access_t p2ma) +nestedhap_fix_p2m (struct vcpu *v,struct p2m_domain *p2m, +paddr_t L2_gpa,paddr_t L0_gpa, +p2m_type_t p2mt,p2m_access_t p2ma) { -int rv; +int rv =0 ;ASSERT (p2m);ASSERT (p2m->set_entry);p2m_lock (p2m); - rv =set_p2m_entry (p2m, L2_gpa >>PAGE_SHIFT , -page_to_mfn (maddr_to_page (L0_gpa)), -0 /*4K*/ , p2mt, p2ma); + +/* If this p2m table has been flushed or recycled under our feet, +* leave it alone. We'll pick up the right one as we try to +* vmenter the guest. */ +if ( p2m->cr3 ==nhvm_vcpu_hostcr3 (v) ) + rv =set_p2m_entry (p2m, L2_gpa >>PAGE_SHIFT , +page_to_mfn (maddr_to_page (L0_gpa)), +0 /*4K*/ , p2mt, p2ma);p2m_unlock (p2m);if (rv ==0 ) {
@@ -211,12 +217,10 @@ nestedhvm_hap_nested_page_fault(struct vbreak ; } -nestedp2m_lock (d);/* fix p2m_get_pagetable(nested_p2m) */ -nestedhap_fix_p2m (nested_p2m, L2_gpa, L0_gpa, +nestedhap_fix_p2m (v, nested_p2m, L2_gpa, L0_gpa, p2m_ram_rw, p2m_access_rwx/* FIXME: Should use same permission as l1 guest */ ); -nestedp2m_unlock (d);return NESTEDHVM_PAGEFAULT_DONE ; }
xen/arch/x86/mm/mm-locks.h +5 -2
@@ -96,8 +96,11 @@ declare_mm_lock(shr)/* Nested P2M lock (per-domain) * -* A per-domain lock that protects some of the nested p2m datastructures. -* TODO: find out exactly what needs to be covered by this lock */ +* A per-domain lock that protects the mapping from nested-CR3 to +* nested-p2m. In particular it covers: +* - the array of nested-p2m tables, and all LRU activity therein; and +* - setting the "cr3" field of any p2m table to a non-CR3_EADDR value. +* (i.e. assigning a p2m table to be the shadow of that cr3 */ declare_mm_lock(nestedp2m)#define nestedp2m_lock (d) mm_lock(nestedp2m, &(d)->arch.nested_p2m_lock)
xen/arch/x86/mm/p2m.c +22 -19
81 lines not on this page · raw message
xen/include/asm-x86/p2m.h +6 -1
@@ -201,8 +201,13 @@ struct p2m_domain {cpumask_t p2m_dirty_cpumask;struct domain *domain;/* back pointer to domain */ + +/* Nested p2ms only: nested-CR3 value that this p2m shadows. +* This can be cleared to CR3_EADDR under the per-p2m lock but +* needs both the per-p2m lock and the per-domain nestedp2m lock +* to set it to any other value. */ #define CR3_EADDR (~0ULL) -uint64_t cr3;/* to identify this p2m for re-use */ +uint64_t cr3;/* Pages used to construct the p2m */ struct page_list_head pages;
Re: [PATCH 4 of 4] Nested p2m: rework locking around nested-p2m flushes and updates
Quoted 36 lines · Tim Deegan
# HG changeset patch
# User Tim Deegan<[email protected]>
# Date 1308758840 -3600
# Node IDa168af9b6d2f604c841465e5ed911b7a12b5ba15
# Parentb265371addbbc8a58c95a269fe3cd0fdc866aaa3Nested p2m: rework locking around nested-p2m flushes and updates.The
nestedp2m_locknow only covers the mapping from nested-cr3 to nested-p2m; the tables themselves may be updated or flushed using only the relevant p2m lock.This means that the nested-p2m lock is only taken on one path, and always before any p2m locks.
Signed-off-by Tim Deegan<[email protected]>diff -r
b265371addbb-ra168af9b6d2fxen/arch/x86/mm/hap/nested_hap.cxen/arch/x86/mm/hap/nested_hap.c +4
-4@@ -96,17 +96,23 @@ nestedp2m_write_p2m_entry(struct p2m_dom/* NESTED VIRT FUNCTIONS */ /********************************************/ static void -nestedhap_fix_p2m (struct p2m_domain *p2m,paddr_t L2_gpa,paddr_t L0_gpa, -p2m_type_t p2mt,p2m_access_t p2ma) +nestedhap_fix_p2m (struct vcpu *v,struct p2m_domain *p2m, +paddr_t L2_gpa,paddr_t L0_gpa, +p2m_type_t p2mt,p2m_access_t p2ma) { -int rv; +int rv =0 ;ASSERT (p2m);ASSERT (p2m->set_entry);p2m_lock (p2m); - rv = set_p2m_entry(p2m, L2_gpa>> PAGE_SHIFT,
xen/arch/x86/mm/hap/nested_hap.c nestedp2m_write_p2m_entry(struct p2m_dom · line 115
Quoted 10 lines
xen/arch/x86/mm/hap/nested_hap.c +8
-2-page_to_mfn (maddr_to_page (L0_gpa)), - 0 /*4K*/, p2mt, p2ma); + +/* If this p2m table has been flushed or recycled under our feet, +* leave it alone. We'll pick up the right one as we try to +* vmenter the guest. */ +if ( p2m->cr3 ==nhvm_vcpu_hostcr3 (v) ) + rv =set_p2m_entry (p2m, L2_gpa>>PAGE_SHIFT , +page_to_mfn (maddr_to_page (L0_gpa)), +0 /*4K*/ , p2mt, p2ma);
The introduction of this check leads to this crash when the L2 guest initializes its third vcpu:
(XEN) nested_hap.c:121:d1 failed to set entry for 0xebcff0 -> 0x2654bcff0 (XEN) Xen BUG at nested_hap.c:122
(XEN) ----[ Xen-4.2-unstable x86_64 debug=y Tainted: C ]----
(XEN) CPU: 1
(XEN) RIP: e008:[<ffff82c48020aa70>] nestedhvm_hap_nested_page_fault+0x27f/0x29d
(XEN) RFLAGS: 0000000000010292 CONTEXT: hypervisor
(XEN) rax: 0000000000000000 rbx: 0000000000000000 rcx: 0000000000000001 (XEN) rdx: ffff82c48025b2e8 rsi: 000000000000000a rdi: ffff82c48025b2e8 (XEN) rbp: ffff830425217cf8 rsp: ffff830425217ca8 r8: 0000000000000001 (XEN) r9: 0000000000000004 r10: 0000000000000004 r11: 0000000000000004 (XEN) r12: ffff8300cf2a1000 r13: ffff830421db1d90 r14: ffff830421db1d90 (XEN) r15: ffff830421db1d90 cr0: 000000008005003b cr4: 00000000000406f0 (XEN) cr3: 0000000403b02000 cr2: 0000000000000000 (XEN) ds: 0000 es: 0000 fs: 0010 gs: 0010 ss: 0000 cs: e008 (XEN) Xen stack trace from rsp=ffff830425217ca8: (XEN) ffff8300cf2a1000 0000000000ebcff0 00000002654bcff0 00000002654bcff0 (XEN) 00000000d98bcff0 0000000000000000 ffff8300cf2a1000 0000000000ebcff0 (XEN) ffff8300cf2a1000 0000000000ebcff0 ffff830425217d58 ffff82c4801aa78d (XEN) 00000000cf2a1000 ffffffffffffffff 00ff830425217d28 ffff82c4801a66ad (XEN) ffff830425217d58 0000000000000000 0000000000000ebc 0000000000ebcff0 (XEN) ffff8300cf2a1000 ffff83023ec07000 ffff830425217f08 ffff82c4801c0faa (XEN) ffff830400000000 ffff82c48017638e ffff830425217d90 ffff830421db1d90 (XEN) ffff830425217f18<G><0>nested_hap.c:121:d1 failed to set entry for 0x7ff8 ->
0x2644d1ff8
(XEN) 0100000000000293Xen BUG at nested_hap.c:122
Christoph
Quoted 141 lines
xen/arch/x86/mm/hap/nested_hap.c +1
-3p2m_unlock (p2m);if (rv ==0 ) {@@ -211,12 +217,10 @@ nestedhvm_hap_nested_page_fault(struct vbreak ; } -nestedp2m_lock (d);/* fix p2m_get_pagetable(nested_p2m) */ -nestedhap_fix_p2m (nested_p2m, L2_gpa, L0_gpa, +nestedhap_fix_p2m (v, nested_p2m, L2_gpa, L0_gpa, p2m_ram_rw, p2m_access_rwx/* FIXME: Should use same permission as l1 guest */ ); -nestedp2m_unlock (d);return NESTEDHVM_PAGEFAULT_DONE ; }diff -r
b265371addbb-ra168af9b6d2fxen/arch/x86/mm/mm-locks.hxen/arch/x86/mm/mm-locks.h +5
-2@@ -96,8 +96,11 @@ declare_mm_lock(shr)/* Nested P2M lock (per-domain) * -* A per-domain lock that protects some of the nested p2m datastructures. -* TODO: find out exactly what needs to be covered by this lock */ +* A per-domain lock that protects the mapping from nested-CR3 to +* nested-p2m. In particular it covers: +* - the array of nested-p2m tables, and all LRU activity therein; and +* - setting the "cr3" field of any p2m table to a non-CR3_EADDR value. +* (i.e. assigning a p2m table to be the shadow of that cr3 */ declare_mm_lock(nestedp2m)#define nestedp2m_lock (d) mm_lock(nestedp2m,&(d)->arch.nested_p2m_lock)diff -r
b265371addbb-ra168af9b6d2fxen/arch/x86/mm/p2m.cxen/arch/x86/mm/p2m.c +22
-19@@ -1052,7 +1052,7 @@ p2m_getlru_nestedp2m(struct domain *d, s/* Reset this p2m table to be empty */ static void -p2m_flush_locked (struct p2m_domain *p2m) +p2m_flush_table (struct p2m_domain *p2m) {struct page_info *top, *pg;struct domain *d = p2m->domain;@@ -1094,21 +1094,16 @@ p2m_flush(struct vcpu *v, struct p2m_domASSERT (v->domain == d);vcpu_nestedhvm (v).nv_p2m =NULL ; -nestedp2m_lock (d); -p2m_flush_locked (p2m); +p2m_flush_table (p2m);hvm_asid_flush_vcpu (v); -nestedp2m_unlock (d); }void p2m_flush_nestedp2m (struct domain *d) {int i; - -nestedp2m_lock (d);for ( i =0 ; i<MAX_NESTEDP2M ; i++ ) -p2m_flush_locked (d->arch.nested_p2m[i]); -nestedp2m_unlock (d); +p2m_flush_table (d->arch.nested_p2m[i]); } struct p2m_domain *@@ -1132,17 +1127,23 @@ p2m_get_nestedp2m(struct vcpu *v, uint64 d = v->domain;nestedp2m_lock (d); p2m = nv->nv_p2m; -if ( p2m&& (p2m->cr3 == cr3 || p2m->cr3 ==CR3_EADDR ) ) +if ( p2m ) { - nv->nv_flushp2m =0 ; -p2m_getlru_nestedp2m (d, p2m); - nv->nv_p2m = p2m; -if (p2m->cr3 ==CR3_EADDR ) -hvm_asid_flush_vcpu (v); - p2m->cr3 = cr3; -cpu_set (v->processor, p2m->p2m_dirty_cpumask); -nestedp2m_unlock (d); -return p2m; +p2m_lock (p2m); +if ( p2m->cr3 == cr3 || p2m->cr3 ==CR3_EADDR ) + { + nv->nv_flushp2m =0 ; +p2m_getlru_nestedp2m (d, p2m); + nv->nv_p2m = p2m; +if (p2m->cr3 ==CR3_EADDR ) +hvm_asid_flush_vcpu (v); + p2m->cr3 = cr3; +cpu_set (v->processor, p2m->p2m_dirty_cpumask); +p2m_unlock (p2m); +nestedp2m_unlock (d); +return p2m; + } + p2m_unlock(p2m) }/* All p2m's are or were in use. Take the least recent used one, @@ -1150,14 +1151,16 @@ p2m_get_nestedp2m(struct vcpu *v, uint64*/ for (i =0 ; i<MAX_NESTEDP2M ; i++) { p2m =p2m_getlru_nestedp2m (d,NULL ); -p2m_flush_locked (p2m); +p2m_flush_table (p2m); } +p2m_lock (p2m); nv->nv_p2m = p2m; p2m->cr3 = cr3; nv->nv_flushp2m =0 ;hvm_asid_flush_vcpu (v);nestedhvm_vmcx_flushtlb (nv->nv_p2m);cpu_set (v->processor, p2m->p2m_dirty_cpumask); +p2m_unlock (p2m);nestedp2m_unlock (d);return p2m;diff -r
b265371addbb-ra168af9b6d2fxen/include/asm-x86/p2m.hxen/include/asm-x86/p2m.h +6
-1@@ -201,8 +201,13 @@ struct p2m_domain {cpumask_t p2m_dirty_cpumask;struct domain *domain;/* back pointer to domain */ + +/* Nested p2ms only: nested-CR3 value that this p2m shadows. +* This can be cleared to CR3_EADDR under the per-p2m lock but +* needs both the per-p2m lock and the per-domain nestedp2m lock +* to set it to any other value. */ #define CR3_EADDR (~0ULL) -uint64_t cr3;/* to identify this p2m for re-use */ +uint64_t cr3;/* Pages used to construct the p2m */ struct page_list_head pages;
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Re: Re: [PATCH 4 of 4] Nested p2m: rework locking around nested-p2m flushes and updates
Quoted 10 lines · Christoph Egger
Review
Quoted 7 lines
(quoted diff) +7
-0+ /* If this p2m table has been flushed or recycled under our feet, + * leave it alone. We'll pick up the right one as we try to + * vmenter the guest. */ + if ( p2m->cr3 == nhvm_vcpu_hostcr3(v) ) + rv = set_p2m_entry(p2m, L2_gpa>> PAGE_SHIFT, + page_to_mfn(maddr_to_page(L0_gpa)), + 0 /*4K*/, p2mt, p2ma);The introduction of this check leads to this crash when the L2 guest initializes its third vcpu:
D'oh!
xen/arch/x86/mm/hap/nested_hap.c +1 -1
@@ -100,7 +100,7 @@ nestedhap_fix_p2m(struct vcpu *v, struct paddr_t L2_gpa, paddr_t L0_gpa, p2m_type_t p2mt, p2m_access_t p2ma) { - int rv = 0; + int rv = 1;ASSERT (p2m);ASSERT (p2m->set_entry);
This is what comes of not being able to test things properly. Can you describe your test setup for me? I'm having no luck getting xen-on-debian-on-xen-on-debian to work.
Cheers,
Tim
Signature · 3 lines
Tim Deegan <[email protected]> Principal Software Engineer, Xen Platform Team Citrix Systems UK Ltd. (Company #02937203, SL9 0BG)
Re: Re: [PATCH 4 of 4] Nested p2m: rework locking around nested-p2m flushes and updates
Quoted 18 lines · Tim Deegan
Quoted 10 lines · Christoph Egger
Review
Quoted 7 lines
(quoted diff) +7
-0+ /* If this p2m table has been flushed or recycled under our feet, + * leave it alone. We'll pick up the right one as we try to + * vmenter the guest. */ + if ( p2m->cr3 == nhvm_vcpu_hostcr3(v) ) + rv = set_p2m_entry(p2m, L2_gpa>> PAGE_SHIFT, + page_to_mfn(maddr_to_page(L0_gpa)), + 0 /*4K*/, p2mt, p2ma);The introduction of this check leads to this crash when the L2 guest initializes its third vcpu:
D'oh!
diff -r
b40d4bcca0d7xen/arch/x86/mm/hap/nested_hap.c
xen/arch/x86/mm/hap/nested_hap.c nestedhap_fix_p2m(struct vcpu *v, struct · line 106
Quoted 8 lines
xen/arch/x86/mm/hap/nested_hap.c +1
-1@@ -100,7 +100,7 @@ nestedhap_fix_p2m(struct vcpu *v, struct paddr_t L2_gpa, paddr_t L0_gpa, p2m_type_t p2mt, p2m_access_t p2ma) { - int rv = 0; + int rv = 1;ASSERT (p2m);ASSERT (p2m->set_entry);
Yes, that fixes the crash.
Quoted 3 lines
This is what comes of not being able to test things properly. Can you describe your test setup for me? I'm having no luck getting xen-on-debian-on-xen-on-debian to work.
That should do it. If your problem is that the L1 Dom0 hangs at boot then disable the TSC Deadline Timer in libxc/xc_cpuid_x86.c. This feature is broken since its introduction.
Christoph
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632