diff mbox series

[v2] KVM: x86/MMU: Do not check unsync status for root SP.

Message ID 20210207122254.23056-1-yu.c.zhang@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series [v2] KVM: x86/MMU: Do not check unsync status for root SP. | expand

Commit Message

Yu Zhang Feb. 7, 2021, 12:22 p.m. UTC
In shadow page table, only leaf SPs may be marked as unsync.
And for non-leaf SPs, we use unsync_children to keep the number
of the unsynced children. In kvm_mmu_sync_root(), sp->unsync
shall always be zero for the root SP, , hence no need to check
it. Instead, a warning inside mmu_sync_children() is added, in
case someone incorrectly used it.

Also, clarify the mmu_need_write_protect(), by moving the warning
into kvm_unsync_page().

Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
Changes in V2:
- warnings added based on Sean's suggestion.

 arch/x86/kvm/mmu/mmu.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

Comments

Paolo Bonzini Feb. 8, 2021, 11:36 a.m. UTC | #1
On 07/02/21 13:22, Yu Zhang wrote:
> In shadow page table, only leaf SPs may be marked as unsync.
> And for non-leaf SPs, we use unsync_children to keep the number
> of the unsynced children. In kvm_mmu_sync_root(), sp->unsync
> shall always be zero for the root SP, , hence no need to check
> it. Instead, a warning inside mmu_sync_children() is added, in
> case someone incorrectly used it.
> 
> Also, clarify the mmu_need_write_protect(), by moving the warning
> into kvm_unsync_page().
> 
> Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
> Signed-off-by: Sean Christopherson <seanjc@google.com>

This should really be more of a Co-developed-by, and there are a couple 
adjustments that could be made in the commit message.  I've queued the 
patch and I'll fix it up later.

Paolo

> ---
> Changes in V2:
> - warnings added based on Sean's suggestion.
> 
>   arch/x86/kvm/mmu/mmu.c | 12 +++++++++---
>   1 file changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> index 86af582..c4797a00cc 100644
> --- a/arch/x86/kvm/mmu/mmu.c
> +++ b/arch/x86/kvm/mmu/mmu.c
> @@ -1995,6 +1995,12 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
>   	LIST_HEAD(invalid_list);
>   	bool flush = false;
>   
> +	/*
> +	 * Only 4k SPTEs can directly be made unsync, the parent pages
> +	 * should never be unsyc'd.
> +	 */
> +	WARN_ON_ONCE(sp->unsync);
> +
>   	while (mmu_unsync_walk(parent, &pages)) {
>   		bool protected = false;
>   
> @@ -2502,6 +2508,8 @@ int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
>   
>   static void kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
>   {
> +	WARN_ON(sp->role.level != PG_LEVEL_4K);
> +
>   	trace_kvm_mmu_unsync_page(sp);
>   	++vcpu->kvm->stat.mmu_unsync;
>   	sp->unsync = 1;
> @@ -2524,7 +2532,6 @@ bool mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
>   		if (sp->unsync)
>   			continue;
>   
> -		WARN_ON(sp->role.level != PG_LEVEL_4K);
>   		kvm_unsync_page(vcpu, sp);
>   	}
>   
> @@ -3406,8 +3413,7 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu)
>   		 * mmu_need_write_protect() describe what could go wrong if this
>   		 * requirement isn't satisfied.
>   		 */
> -		if (!smp_load_acquire(&sp->unsync) &&
> -		    !smp_load_acquire(&sp->unsync_children))
> +		if (!smp_load_acquire(&sp->unsync_children))
>   			return;
>   
>   		write_lock(&vcpu->kvm->mmu_lock);
>
Yu Zhang Feb. 8, 2021, 1:49 p.m. UTC | #2
On Mon, Feb 08, 2021 at 12:36:57PM +0100, Paolo Bonzini wrote:
> On 07/02/21 13:22, Yu Zhang wrote:
> > In shadow page table, only leaf SPs may be marked as unsync.
> > And for non-leaf SPs, we use unsync_children to keep the number
> > of the unsynced children. In kvm_mmu_sync_root(), sp->unsync
> > shall always be zero for the root SP, , hence no need to check
> > it. Instead, a warning inside mmu_sync_children() is added, in
> > case someone incorrectly used it.
> > 
> > Also, clarify the mmu_need_write_protect(), by moving the warning
> > into kvm_unsync_page().
> > 
> > Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
> > Signed-off-by: Sean Christopherson <seanjc@google.com>
> 
> This should really be more of a Co-developed-by, and there are a couple
> adjustments that could be made in the commit message.  I've queued the patch
> and I'll fix it up later.

Indeed. Thanks for the remind, and I'll pay attention in the future. :)

B.R.
Yu

> 
> Paolo
> 
> > ---
> > Changes in V2:
> > - warnings added based on Sean's suggestion.
> > 
> >   arch/x86/kvm/mmu/mmu.c | 12 +++++++++---
> >   1 file changed, 9 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> > index 86af582..c4797a00cc 100644
> > --- a/arch/x86/kvm/mmu/mmu.c
> > +++ b/arch/x86/kvm/mmu/mmu.c
> > @@ -1995,6 +1995,12 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
> >   	LIST_HEAD(invalid_list);
> >   	bool flush = false;
> > +	/*
> > +	 * Only 4k SPTEs can directly be made unsync, the parent pages
> > +	 * should never be unsyc'd.
> > +	 */
> > +	WARN_ON_ONCE(sp->unsync);
> > +
> >   	while (mmu_unsync_walk(parent, &pages)) {
> >   		bool protected = false;
> > @@ -2502,6 +2508,8 @@ int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
> >   static void kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
> >   {
> > +	WARN_ON(sp->role.level != PG_LEVEL_4K);
> > +
> >   	trace_kvm_mmu_unsync_page(sp);
> >   	++vcpu->kvm->stat.mmu_unsync;
> >   	sp->unsync = 1;
> > @@ -2524,7 +2532,6 @@ bool mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
> >   		if (sp->unsync)
> >   			continue;
> > -		WARN_ON(sp->role.level != PG_LEVEL_4K);
> >   		kvm_unsync_page(vcpu, sp);
> >   	}
> > @@ -3406,8 +3413,7 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu)
> >   		 * mmu_need_write_protect() describe what could go wrong if this
> >   		 * requirement isn't satisfied.
> >   		 */
> > -		if (!smp_load_acquire(&sp->unsync) &&
> > -		    !smp_load_acquire(&sp->unsync_children))
> > +		if (!smp_load_acquire(&sp->unsync_children))
> >   			return;
> >   		write_lock(&vcpu->kvm->mmu_lock);
> > 
>
Paolo Bonzini Feb. 8, 2021, 4:47 p.m. UTC | #3
On 08/02/21 14:49, Yu Zhang wrote:
> On Mon, Feb 08, 2021 at 12:36:57PM +0100, Paolo Bonzini wrote:
>> On 07/02/21 13:22, Yu Zhang wrote:
>>> In shadow page table, only leaf SPs may be marked as unsync.
>>> And for non-leaf SPs, we use unsync_children to keep the number
>>> of the unsynced children. In kvm_mmu_sync_root(), sp->unsync
>>> shall always be zero for the root SP, , hence no need to check
>>> it. Instead, a warning inside mmu_sync_children() is added, in
>>> case someone incorrectly used it.
>>>
>>> Also, clarify the mmu_need_write_protect(), by moving the warning
>>> into kvm_unsync_page().
>>>
>>> Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
>>> Signed-off-by: Sean Christopherson <seanjc@google.com>
>>
>> This should really be more of a Co-developed-by, and there are a couple
>> adjustments that could be made in the commit message.  I've queued the patch
>> and I'll fix it up later.
> 
> Indeed. Thanks for the remind, and I'll pay attention in the future. :)

Also:

arch/x86/kvm/mmu/mmu.c: In function ‘mmu_sync_children’:
arch/x86/kvm/mmu/mmu.c:2002:17: error: ‘sp’ is used uninitialized in 
this function [-Werror=uninitialized]
   WARN_ON_ONCE(sp->unsync);

so how was this tested?

Paolo
Yu Zhang Feb. 9, 2021, 3:33 a.m. UTC | #4
On Mon, Feb 08, 2021 at 05:47:22PM +0100, Paolo Bonzini wrote:
> On 08/02/21 14:49, Yu Zhang wrote:
> > On Mon, Feb 08, 2021 at 12:36:57PM +0100, Paolo Bonzini wrote:
> > > On 07/02/21 13:22, Yu Zhang wrote:
> > > > In shadow page table, only leaf SPs may be marked as unsync.
> > > > And for non-leaf SPs, we use unsync_children to keep the number
> > > > of the unsynced children. In kvm_mmu_sync_root(), sp->unsync
> > > > shall always be zero for the root SP, , hence no need to check
> > > > it. Instead, a warning inside mmu_sync_children() is added, in
> > > > case someone incorrectly used it.
> > > > 
> > > > Also, clarify the mmu_need_write_protect(), by moving the warning
> > > > into kvm_unsync_page().
> > > > 
> > > > Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
> > > > Signed-off-by: Sean Christopherson <seanjc@google.com>
> > > 
> > > This should really be more of a Co-developed-by, and there are a couple
> > > adjustments that could be made in the commit message.  I've queued the patch
> > > and I'll fix it up later.
> > 
> > Indeed. Thanks for the remind, and I'll pay attention in the future. :)
> 
> Also:
> 
> arch/x86/kvm/mmu/mmu.c: In function ‘mmu_sync_children’:
> arch/x86/kvm/mmu/mmu.c:2002:17: error: ‘sp’ is used uninitialized in this
> function [-Werror=uninitialized]
>   WARN_ON_ONCE(sp->unsync);

Oops. This is wrong. Should be WARN_ON_ONCE(parent->unsync);

> 
> so how was this tested?
> 

I ran access test in kvm-unit-test for previous version, which hasn't
this code(also in my local repo "enable_ept" was explicitly set to
0 in order to test the shadow mode). But I did not test this one. I'm
truely sorry for the negligence - even trying to compile should make
this happen!

Should we submit another version? Any suggestions on the test cases?

Thanks
Yu

> Paolo
>
Paolo Bonzini Feb. 9, 2021, 7:46 a.m. UTC | #5
On 09/02/21 04:33, Yu Zhang wrote:
> On Mon, Feb 08, 2021 at 05:47:22PM +0100, Paolo Bonzini wrote:
>> On 08/02/21 14:49, Yu Zhang wrote:
>>> On Mon, Feb 08, 2021 at 12:36:57PM +0100, Paolo Bonzini wrote:
>>>> On 07/02/21 13:22, Yu Zhang wrote:
>>>>> In shadow page table, only leaf SPs may be marked as unsync.
>>>>> And for non-leaf SPs, we use unsync_children to keep the number
>>>>> of the unsynced children. In kvm_mmu_sync_root(), sp->unsync
>>>>> shall always be zero for the root SP, , hence no need to check
>>>>> it. Instead, a warning inside mmu_sync_children() is added, in
>>>>> case someone incorrectly used it.
>>>>>
>>>>> Also, clarify the mmu_need_write_protect(), by moving the warning
>>>>> into kvm_unsync_page().
>>>>>
>>>>> Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
>>>>> Signed-off-by: Sean Christopherson <seanjc@google.com>
>>>>
>>>> This should really be more of a Co-developed-by, and there are a couple
>>>> adjustments that could be made in the commit message.  I've queued the patch
>>>> and I'll fix it up later.
>>>
>>> Indeed. Thanks for the remind, and I'll pay attention in the future. :)
>>
>> Also:
>>
>> arch/x86/kvm/mmu/mmu.c: In function ‘mmu_sync_children’:
>> arch/x86/kvm/mmu/mmu.c:2002:17: error: ‘sp’ is used uninitialized in this
>> function [-Werror=uninitialized]
>>    WARN_ON_ONCE(sp->unsync);
> 
> Oops. This is wrong. Should be WARN_ON_ONCE(parent->unsync);
> 
>>
>> so how was this tested?
>>
> 
> I ran access test in kvm-unit-test for previous version, which hasn't
> this code(also in my local repo "enable_ept" was explicitly set to
> 0 in order to test the shadow mode). But I did not test this one. I'm
> truely sorry for the negligence - even trying to compile should make
> this happen!
> 
> Should we submit another version? Any suggestions on the test cases?

Yes, please send v3.

The commit message can be:

In shadow page table, only leaf SPs may be marked as unsync; instead, 
for non-leaf SPs, we store the number of unsynced children in 
unsync_children.  Therefore, in kvm_mmu_sync_root(), sp->unsync
shall always be zero for the root SP and there is no need to check
it.  Remove the check, and add a warning inside mmu_sync_children() to 
assert that the flags are used properly.

While at it, move the warning from mmu_need_write_protect() to 
kvm_unsync_page().

Paolo
Yu Zhang Feb. 9, 2021, 8:53 a.m. UTC | #6
On Tue, Feb 09, 2021 at 08:46:42AM +0100, Paolo Bonzini wrote:
> On 09/02/21 04:33, Yu Zhang wrote:
> > On Mon, Feb 08, 2021 at 05:47:22PM +0100, Paolo Bonzini wrote:
> > > On 08/02/21 14:49, Yu Zhang wrote:
> > > > On Mon, Feb 08, 2021 at 12:36:57PM +0100, Paolo Bonzini wrote:
> > > > > On 07/02/21 13:22, Yu Zhang wrote:
> > > > > > In shadow page table, only leaf SPs may be marked as unsync.
> > > > > > And for non-leaf SPs, we use unsync_children to keep the number
> > > > > > of the unsynced children. In kvm_mmu_sync_root(), sp->unsync
> > > > > > shall always be zero for the root SP, , hence no need to check
> > > > > > it. Instead, a warning inside mmu_sync_children() is added, in
> > > > > > case someone incorrectly used it.
> > > > > > 
> > > > > > Also, clarify the mmu_need_write_protect(), by moving the warning
> > > > > > into kvm_unsync_page().
> > > > > > 
> > > > > > Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
> > > > > > Signed-off-by: Sean Christopherson <seanjc@google.com>
> > > > > 
> > > > > This should really be more of a Co-developed-by, and there are a couple
> > > > > adjustments that could be made in the commit message.  I've queued the patch
> > > > > and I'll fix it up later.
> > > > 
> > > > Indeed. Thanks for the remind, and I'll pay attention in the future. :)
> > > 
> > > Also:
> > > 
> > > arch/x86/kvm/mmu/mmu.c: In function ‘mmu_sync_children’:
> > > arch/x86/kvm/mmu/mmu.c:2002:17: error: ‘sp’ is used uninitialized in this
> > > function [-Werror=uninitialized]
> > >    WARN_ON_ONCE(sp->unsync);
> > 
> > Oops. This is wrong. Should be WARN_ON_ONCE(parent->unsync);
> > 
> > > 
> > > so how was this tested?
> > > 
> > 
> > I ran access test in kvm-unit-test for previous version, which hasn't
> > this code(also in my local repo "enable_ept" was explicitly set to
> > 0 in order to test the shadow mode). But I did not test this one. I'm
> > truely sorry for the negligence - even trying to compile should make
> > this happen!
> > 
> > Should we submit another version? Any suggestions on the test cases?
> 
> Yes, please send v3.
> 
> The commit message can be:
> 
> In shadow page table, only leaf SPs may be marked as unsync; instead, for
> non-leaf SPs, we store the number of unsynced children in unsync_children.
> Therefore, in kvm_mmu_sync_root(), sp->unsync
> shall always be zero for the root SP and there is no need to check
> it.  Remove the check, and add a warning inside mmu_sync_children() to
> assert that the flags are used properly.
> 
> While at it, move the warning from mmu_need_write_protect() to
> kvm_unsync_page().

Thanks Paolo. Will send out v3.

BTW, I just realized that mmu_sync_children() was not triggered by
kvm-unit-test(the access.flat case), so I ran another test by running
a regular VM using shadow, in which I witnessed the synchronization.

B.R.
Yu

> 
> Paolo
>
diff mbox series

Patch

diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 86af582..c4797a00cc 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -1995,6 +1995,12 @@  static void mmu_sync_children(struct kvm_vcpu *vcpu,
 	LIST_HEAD(invalid_list);
 	bool flush = false;
 
+	/*
+	 * Only 4k SPTEs can directly be made unsync, the parent pages
+	 * should never be unsyc'd.
+	 */
+	WARN_ON_ONCE(sp->unsync);
+
 	while (mmu_unsync_walk(parent, &pages)) {
 		bool protected = false;
 
@@ -2502,6 +2508,8 @@  int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
 
 static void kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 {
+	WARN_ON(sp->role.level != PG_LEVEL_4K);
+
 	trace_kvm_mmu_unsync_page(sp);
 	++vcpu->kvm->stat.mmu_unsync;
 	sp->unsync = 1;
@@ -2524,7 +2532,6 @@  bool mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
 		if (sp->unsync)
 			continue;
 
-		WARN_ON(sp->role.level != PG_LEVEL_4K);
 		kvm_unsync_page(vcpu, sp);
 	}
 
@@ -3406,8 +3413,7 @@  void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu)
 		 * mmu_need_write_protect() describe what could go wrong if this
 		 * requirement isn't satisfied.
 		 */
-		if (!smp_load_acquire(&sp->unsync) &&
-		    !smp_load_acquire(&sp->unsync_children))
+		if (!smp_load_acquire(&sp->unsync_children))
 			return;
 
 		write_lock(&vcpu->kvm->mmu_lock);