KVM MMU: fix for forgot mark parent->unsync_children bit
PATCH 1/2 KVM MMU: fix for forgot mark parent->unsync_children bit
When mapping a new parent to unsync shadow page, we should mark parent's unsync_children bit
--- arch/x86/kvm/mmu.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
arch/x86/kvm/mmu.c +3 -1
@@ -1374,7 +1374,9 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,if (sp->unsync_children) {set_bit (KVM_REQ_MMU_SYNC , &vcpu->requests);kvm_mmu_mark_parents_unsync (sp); - } + }else if (sp->unsync) +kvm_mmu_mark_parents_unsync (sp); +trace_kvm_mmu_get_page (sp, false);return sp; }
Signature · 1 line
1.6.1.2
PATCH 2/2 KVM MMU: fix race in invlpg code
It has race in invlpg code, like below sequences:
A: hold mmu_lock and get 'sp'
B: release mmu_lock and do other things
C: hold mmu_lock and continue use 'sp'
if other path freed 'sp' in stage B, then kernel will crash
This patch checks 'sp' whether lived before use 'sp' in stage C
--- arch/x86/kvm/paging_tmpl.h | 22 ++++++++++++++++++++-- 1 files changed, 20 insertions(+), 2 deletions(-)
arch/x86/kvm/paging_tmpl.h +20 -2
@@ -462,11 +462,16 @@ out_unlock:static void FNAME (invlpg )(struct kvm_vcpu *vcpu,gva_t gva) { -struct kvm_mmu_page *sp =NULL ; +struct kvm_mmu_page *sp =NULL , *s;struct kvm_shadow_walk_iterator iterator; +struct hlist_head *bucket; +struct hlist_node *node, *tmp;gfn_t gfn =-1 ;u64 *sptep =NULL , gentry;int invlpg_counter, level, offset =0 , need_flush =0 ; +unsigned index; +bool live = false; +union kvm_mmu_page_role role;spin_lock (&vcpu->kvm->mmu_lock);
@@ -480,7 +485,7 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)if (!sp->unsync)break ; - + role = sp->role;WARN_ON (level !=PT_PAGE_TABLE_LEVEL ); shift =PAGE_SHIFT - (PT_LEVEL_BITS -PT64_LEVEL_BITS ) * level;
@@ -519,10 +524,23 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)mmu_guess_page_from_pte_write (vcpu,gfn_to_gpa (gfn) + offset, gentry);spin_lock (&vcpu->kvm->mmu_lock); + index =kvm_page_table_hashfn (gfn); + bucket = &vcpu->kvm->arch.mmu_page_hash[index]; +hlist_for_each_entry_safe (s, node, tmp, bucket, hash_link) +if (s == sp) { +if (s->gfn == gfn && s->role.word == role.word) + live = true; +break ; + } + +if (!live) + goto unlock_exit; +if (atomic_read (&vcpu->kvm->arch.invlpg_counter) == invlpg_counter) { ++vcpu->kvm->stat.mmu_pte_updated;FNAME (update_pte)(vcpu, sp, sptep, &gentry); } +unlock_exit:spin_unlock (&vcpu->kvm->mmu_lock);mmu_release_page_from_pte_write (vcpu); }
Signature · 1 line
1.6.1.2
Re: [PATCH 2/2] KVM MMU: fix race in invlpg code
Quoted 53 lines · Xiao Guangrong
It has race in invlpg code, like below sequences:
A: hold
mmu_lockand get 'sp'
B: releasemmu_lockand do other things
C: holdmmu_lockand continue use 'sp'if other path freed 'sp' in stage B, then kernel will crash
This patch checks 'sp' whether lived before use 'sp' in stage C
Signed-off-by Xiao Guangrong<[email protected]>--- arch/x86/kvm/paging_tmpl.h | 22 ++++++++++++++++++++-- 1 files changed, 20 insertions(+), 2 deletions(-)arch/x86/kvm/paging_tmpl.h +10
-2@@ -462,11 +462,16 @@ out_unlock:static void FNAME (invlpg )(struct kvm_vcpu *vcpu,gva_t gva) { -struct kvm_mmu_page *sp =NULL ; +struct kvm_mmu_page *sp =NULL , *s;struct kvm_shadow_walk_iterator iterator; +struct hlist_head *bucket; +struct hlist_node *node, *tmp;gfn_t gfn =-1 ;u64 *sptep =NULL , gentry;int invlpg_counter, level, offset =0 , need_flush =0 ; +unsigned index; +bool live = false; +union kvm_mmu_page_role role;spin_lock (&vcpu->kvm->mmu_lock);@@ -480,7 +485,7 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)if (!sp->unsync)break ; - + role = sp->role;WARN_ON (level !=PT_PAGE_TABLE_LEVEL ); shift =PAGE_SHIFT - (PT_LEVEL_BITS -PT64_LEVEL_BITS ) * level;@@ -519,10 +524,23 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva)mmu_guess_page_from_pte_write (vcpu,gfn_to_gpa (gfn) + offset, gentry);spin_lock (&vcpu->kvm->mmu_lock); + index =kvm_page_table_hashfn (gfn); + bucket =&vcpu->kvm->arch.mmu_page_hash[index]; +hlist_for_each_entry_safe (s, node, tmp, bucket, hash_link)
arch/x86/kvm/paging_tmpl.h static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) · line 539
Quoted 10 lines
arch/x86/kvm/paging_tmpl.h +9
-0+if (s == sp) { +if (s->gfn == gfn&& s->role.word == role.word) + live = true; +break ; + } + +if (!live) + goto unlock_exit; +
Did you try the root_count method? I think it's cleaner.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [PATCH 2/2] KVM MMU: fix race in invlpg code
Quoted 8 lines · Avi Kivity
Quoted 8 lines
spin_lock(&vcpu->kvm->mmu_lock);arch/x86/kvm/paging_tmpl.h +7
-0+ index =kvm_page_table_hashfn (gfn); + bucket =&vcpu->kvm->arch.mmu_page_hash[index]; +hlist_for_each_entry_safe (s, node, tmp, bucket, hash_link) +if (s == sp) { +if (s->gfn == gfn&& s->role.word == role.word) + live = true; +break ;
Quoted 8 lines
arch/x86/kvm/paging_tmpl.h static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) · line 538
Quoted 6 lines
arch/x86/kvm/paging_tmpl.h +5
-0+ } + +if (!live) + goto unlock_exit; +Did you try the
root_countmethod? I think it's cleaner.
Avi, Thanks for your idea.
I have considered this method, but i'm not sure when it's the good time to real free this page, and i think we also need a way to synchronize the real free path and this path. Do you have any comment for it :-(
Xiao
Re: [PATCH 2/2] KVM MMU: fix race in invlpg code
Quoted 21 lines · Xiao Guangrong
Quoted 8 lines · Avi Kivity
Quoted 8 lines
spin_lock(&vcpu->kvm->mmu_lock);arch/x86/kvm/paging_tmpl.h +7
-0+ index =kvm_page_table_hashfn (gfn); + bucket =&vcpu->kvm->arch.mmu_page_hash[index]; +hlist_for_each_entry_safe (s, node, tmp, bucket, hash_link) +if (s == sp) { +if (s->gfn == gfn&& s->role.word == role.word) + live = true; +break ;Quoted 9 lines
arch/x86/kvm/paging_tmpl.h static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) · line 538
Quoted 7 lines
arch/x86/kvm/paging_tmpl.h +5
-0+ } + +if (!live) + goto unlock_exit; +Did you try the
root_countmethod? I think it's cleaner.
Quoted 6 lines
Avi, Thanks for your idea.
I have considered this method, but i'm not sure when it's the good time to real free this page, and i think we also need a way to synchronize the real free path and this path. Do you have any comment for it :-(
Same as mmu_free_roots():
--sp->root_count;
if (!sp->root_count && sp->role.invalid) {
kvm_mmu_zap_page(vcpu->kvm, sp);
goto unlock_exit;
}Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 15 lines · Xiao Guangrong
When mapping a new parent to unsync shadow page, we should mark parent's
unsync_childrenbitReported-by Marcelo Tosatti<[email protected]>Signed-off-by Xiao Guangrong<[email protected]>--- arch/x86/kvm/mmu.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)arch/x86/kvm/mmu.c +0
-0
arch/x86/kvm/mmu.c static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, · line 1382
Quoted 10 lines
arch/x86/kvm/mmu.c +3
-1@@ -1374,7 +1374,9 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,if (sp->unsync_children) {set_bit (KVM_REQ_MMU_SYNC ,&vcpu->requests);kvm_mmu_mark_parents_unsync (sp); - } + }else if (sp->unsync) +kvm_mmu_mark_parents_unsync (sp); +trace_kvm_mmu_get_page (sp, false);return sp; }
Which patch does this fix? If it wasn't merge yet, please repost with the fix included.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 23 lines · Avi Kivity
Quoted 22 lines · Xiao Guangrong
When mapping a new parent to unsync shadow page, we should mark parent's
unsync_childrenbitReported-by Marcelo Tosatti<[email protected]>Signed-off-by Xiao Guangrong<[email protected]>--- arch/x86/kvm/mmu.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)arch/x86/kvm/mmu.c +3
-1@@ -1374,7 +1374,9 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, if (sp->unsync_children) { set_bit(KVM_REQ_MMU_SYNC,&vcpu->requests); kvm_mmu_mark_parents_unsync(sp); - } + } else if (sp->unsync) +kvm_mmu_mark_parents_unsync (sp); +
Quoted 8 lines
Quoted 4 lines
arch/x86/kvm/mmu.c +0
-0trace_kvm_mmu_get_page (sp, false);return sp;}Which patch does this fix? If it wasn't merge yet, please repost with the fix included.
Oh, OK, i'll sent the previous pathset that are reverted by Marcelo.
Thanks,
Xiao