Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
On Wed, Apr 14, 2010 at 10:14:29AM +0800, Xiao Guangrong wrote: Marcelo Tosatti wrote: On Tue, Apr 13, 2010 at 09:34:14AM +0800, Xiao Guangrong wrote: Marcelo Tosatti wrote: @@ -1483,8 +1483,8 @@ static int mmu_zap_unsync_children(struct kvm *kvm, for_each_sp(pages, sp, parents, i) { kvm_mmu_zap_page(kvm, sp); mmu_pages_clear_parents(parents); +zapped++; } -zapped += pages.nr; kvm_mmu_pages_init(parent, parents, pages); } Don't see why this is needed? The for_each_sp loop uses pvec.nr. I think mmu_zap_unsync_children() should return the number of zapped pages then we can adjust the number of free pages in kvm_mmu_change_mmu_pages(), but pages.nr no only includes the unsync/zapped pages but also includes their parents. Oh i see. I think its safer to check for list_empty then to rely on proper accounting there, like __kvm_mmu_free_some_pages does. Do you mean that we'd better add WARN_ON(list_empty()) code in kvm_mmu_zap_page()? Just break out of the loop if list_empty(vcpu-kvm-arch.active_mmu_pages). -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
On Tue, Apr 13, 2010 at 09:34:14AM +0800, Xiao Guangrong wrote: Marcelo Tosatti wrote: @@ -1483,8 +1483,8 @@ static int mmu_zap_unsync_children(struct kvm *kvm, for_each_sp(pages, sp, parents, i) { kvm_mmu_zap_page(kvm, sp); mmu_pages_clear_parents(parents); + zapped++; } - zapped += pages.nr; kvm_mmu_pages_init(parent, parents, pages); } Don't see why this is needed? The for_each_sp loop uses pvec.nr. I think mmu_zap_unsync_children() should return the number of zapped pages then we can adjust the number of free pages in kvm_mmu_change_mmu_pages(), but pages.nr no only includes the unsync/zapped pages but also includes their parents. Oh i see. I think its safer to check for list_empty then to rely on proper accounting there, like __kvm_mmu_free_some_pages does. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
- calculate zapped page number properly in mmu_zap_unsync_children() - calculate freeed page number properly kvm_mmu_change_mmu_pages() - restart list walking if have children page zapped Signed-off-by: Xiao Guangrong xiaoguangr...@cn.fujitsu.com --- arch/x86/kvm/mmu.c |7 --- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index a23ca75..8f4f781 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1483,8 +1483,8 @@ static int mmu_zap_unsync_children(struct kvm *kvm, for_each_sp(pages, sp, parents, i) { kvm_mmu_zap_page(kvm, sp); mmu_pages_clear_parents(parents); + zapped++; } - zapped += pages.nr; kvm_mmu_pages_init(parent, parents, pages); } @@ -1540,7 +1540,7 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages) page = container_of(kvm-arch.active_mmu_pages.prev, struct kvm_mmu_page, link); - kvm_mmu_zap_page(kvm, page); + used_pages -= kvm_mmu_zap_page(kvm, page); used_pages--; } kvm-arch.n_free_mmu_pages = 0; @@ -1589,7 +1589,8 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) !sp-role.invalid) { pgprintk(%s: zap %lx %x\n, __func__, gfn, sp-role.word); - kvm_mmu_zap_page(kvm, sp); + if (kvm_mmu_zap_page(kvm, sp)) + nn = bucket-first; } } } -- 1.6.1.2 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
On 04/12/2010 11:01 AM, Xiao Guangrong wrote: - calculate zapped page number properly in mmu_zap_unsync_children() - calculate freeed page number properly kvm_mmu_change_mmu_pages() - restart list walking if have children page zapped Signed-off-by: Xiao Guangrongxiaoguangr...@cn.fujitsu.com --- arch/x86/kvm/mmu.c |7 --- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index a23ca75..8f4f781 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1483,8 +1483,8 @@ static int mmu_zap_unsync_children(struct kvm *kvm, for_each_sp(pages, sp, parents, i) { kvm_mmu_zap_page(kvm, sp); mmu_pages_clear_parents(parents); + zapped++; } - zapped += pages.nr; kvm_mmu_pages_init(parent,parents,pages); } This looks correct, I don't understand how we work in the first place. Marcelo? @@ -1540,7 +1540,7 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages) page = container_of(kvm-arch.active_mmu_pages.prev, struct kvm_mmu_page, link); - kvm_mmu_zap_page(kvm, page); + used_pages -= kvm_mmu_zap_page(kvm, page); used_pages--; } This too. Wow. kvm-arch.n_free_mmu_pages = 0; @@ -1589,7 +1589,8 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) !sp-role.invalid) { pgprintk(%s: zap %lx %x\n, __func__, gfn, sp-role.word); - kvm_mmu_zap_page(kvm, sp); + if (kvm_mmu_zap_page(kvm, sp)) + nn = bucket-first; } } I don't understand why this is needed. -- I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
Avi Kivity wrote: kvm-arch.n_free_mmu_pages = 0; @@ -1589,7 +1589,8 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) !sp-role.invalid) { pgprintk(%s: zap %lx %x\n, __func__, gfn, sp-role.word); -kvm_mmu_zap_page(kvm, sp); +if (kvm_mmu_zap_page(kvm, sp)) +nn = bucket-first; } } I don't understand why this is needed. There is the code segment in mmu_unshadow(): |hlist_for_each_entry_safe(sp, node, nn, bucket, hash_link) { | if (sp-gfn == gfn !sp-role.direct |!sp-role.invalid) { | pgprintk(%s: zap %lx %x\n, |__func__, gfn, sp-role.word); | kvm_mmu_zap_page(kvm, sp); | } | } in the loop, if nn is zapped, hlist_for_each_entry_safe() access nn will cause crash. and it's checked in other functions, such as kvm_mmu_zap_all(), kvm_mmu_unprotect_page()... Thanks, Xiao -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
On 04/12/2010 11:53 AM, Xiao Guangrong wrote: kvm-arch.n_free_mmu_pages = 0; @@ -1589,7 +1589,8 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) !sp-role.invalid) { pgprintk(%s: zap %lx %x\n, __func__, gfn, sp-role.word); -kvm_mmu_zap_page(kvm, sp); +if (kvm_mmu_zap_page(kvm, sp)) +nn = bucket-first; } } I don't understand why this is needed. There is the code segment in mmu_unshadow(): |hlist_for_each_entry_safe(sp, node, nn, bucket, hash_link) { | if (sp-gfn == gfn !sp-role.direct | !sp-role.invalid) { | pgprintk(%s: zap %lx %x\n, |__func__, gfn, sp-role.word); | kvm_mmu_zap_page(kvm, sp); | } | } in the loop, if nn is zapped, hlist_for_each_entry_safe() access nn will cause crash. and it's checked in other functions, such as kvm_mmu_zap_all(), kvm_mmu_unprotect_page()... hlist_for_each_entry_safe() is supposed to be be safe against removal of the element that is pointed to by the iteration cursor. -- I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
Hi Avi, Avi Kivity wrote: hlist_for_each_entry_safe() is supposed to be be safe against removal of the element that is pointed to by the iteration cursor. If we destroyed the next point, hlist_for_each_entry_safe() is unsafe. List hlist_for_each_entry_safe()'s code: |#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ | for (pos = (head)-first;\ |pos ({ n = pos-next; 1; })\ | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |pos = n) if n is destroyed: 'pos = n, n = pos-next' then it access n again, it's unsafe/illegal for us. Xiao -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
On 04/12/2010 12:22 PM, Xiao Guangrong wrote: Hi Avi, Avi Kivity wrote: hlist_for_each_entry_safe() is supposed to be be safe against removal of the element that is pointed to by the iteration cursor. If we destroyed the next point, hlist_for_each_entry_safe() is unsafe. List hlist_for_each_entry_safe()'s code: |#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ | for (pos = (head)-first; \ |pos ({ n = pos-next; 1; })\ | ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ |pos = n) if n is destroyed: 'pos = n, n = pos-next' then it access n again, it's unsafe/illegal for us. But kvm_mmu_zap_page() will only destroy sp == tpos == pos; n points at pos-next already, so it's safe. -- I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
Avi Kivity wrote: On 04/12/2010 12:22 PM, Xiao Guangrong wrote: Hi Avi, Avi Kivity wrote: But kvm_mmu_zap_page() will only destroy sp == tpos == pos; n points at pos-next already, so it's safe. kvm_mmu_zap_page(sp) not only zaps sp but also zaps all sp's unsync children pages, if n is just sp's unsyc child, just at the same hlist and just behind sp, it will crash. :-) -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
On 04/12/2010 03:22 PM, Xiao Guangrong wrote: But kvm_mmu_zap_page() will only destroy sp == tpos == pos; n points at pos-next already, so it's safe. kvm_mmu_zap_page(sp) not only zaps sp but also zaps all sp's unsync children pages, if n is just sp's unsyc child, just at the same hlist and just behind sp, it will crash. :-) Ouch. I see now, thanks for explaining. One way to fix it is to make kvm_mmu_zap_page() only zap the page it is given, and use sp-role.invalid on its children. But it's better to fix it now quickly and do the more involved fixes later. Just change the assignment to a 'goto restart;' please, I don't like playing with list_for_each internals. -- I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/6] KVM MMU: fix kvm_mmu_zap_page() and its calling path
On Mon, Apr 12, 2010 at 04:01:09PM +0800, Xiao Guangrong wrote: - calculate zapped page number properly in mmu_zap_unsync_children() - calculate freeed page number properly kvm_mmu_change_mmu_pages() - restart list walking if have children page zapped Signed-off-by: Xiao Guangrong xiaoguangr...@cn.fujitsu.com --- arch/x86/kvm/mmu.c |7 --- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index a23ca75..8f4f781 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1483,8 +1483,8 @@ static int mmu_zap_unsync_children(struct kvm *kvm, for_each_sp(pages, sp, parents, i) { kvm_mmu_zap_page(kvm, sp); mmu_pages_clear_parents(parents); + zapped++; } - zapped += pages.nr; kvm_mmu_pages_init(parent, parents, pages); } Don't see why this is needed? The for_each_sp loop uses pvec.nr. @@ -1540,7 +1540,7 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages) page = container_of(kvm-arch.active_mmu_pages.prev, struct kvm_mmu_page, link); - kvm_mmu_zap_page(kvm, page); + used_pages -= kvm_mmu_zap_page(kvm, page); used_pages--; } kvm-arch.n_free_mmu_pages = 0; Oops. @@ -1589,7 +1589,8 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) !sp-role.invalid) { pgprintk(%s: zap %lx %x\n, __func__, gfn, sp-role.word); - kvm_mmu_zap_page(kvm, sp); + if (kvm_mmu_zap_page(kvm, sp)) + nn = bucket-first; Oops 2. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html