diff mbox series

[v2,08/10] KVM: x86/mmu: Split out TDP MMU page fault handling

Message ID 20220826231227.4096391-9-dmatlack@google.com (mailing list archive)
State New, archived
Headers show
Series KVM: x86/mmu: Make tdp_mmu read-only and clean up TPD MMU fault handler | expand

Commit Message

David Matlack Aug. 26, 2022, 11:12 p.m. UTC
Split out the page fault handling for the TDP MMU to a separate
function.  This creates some duplicate code, but makes the TDP MMU fault
handler simpler to read by eliminating branches and will enable future
cleanups by allowing the TDP MMU and non-TDP MMU fault paths to diverge.

Only compile in the TDP MMU fault handler for 64-bit builds since
kvm_tdp_mmu_map() does not exist in 32-bit builds.

No functional change intended.

Signed-off-by: David Matlack <dmatlack@google.com>
---
 arch/x86/kvm/mmu/mmu.c | 62 ++++++++++++++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 14 deletions(-)

Comments

Isaku Yamahata Aug. 30, 2022, 11:57 p.m. UTC | #1
On Fri, Aug 26, 2022 at 04:12:25PM -0700,
David Matlack <dmatlack@google.com> wrote:

> Split out the page fault handling for the TDP MMU to a separate
> function.  This creates some duplicate code, but makes the TDP MMU fault
> handler simpler to read by eliminating branches and will enable future
> cleanups by allowing the TDP MMU and non-TDP MMU fault paths to diverge.
> 
> Only compile in the TDP MMU fault handler for 64-bit builds since
> kvm_tdp_mmu_map() does not exist in 32-bit builds.
> 
> No functional change intended.
> 
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
>  arch/x86/kvm/mmu/mmu.c | 62 ++++++++++++++++++++++++++++++++----------
>  1 file changed, 48 insertions(+), 14 deletions(-)
> 
> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> index a185599f4d1d..8f124a23ab4c 100644
> --- a/arch/x86/kvm/mmu/mmu.c
> +++ b/arch/x86/kvm/mmu/mmu.c
> @@ -4242,7 +4242,6 @@ static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
>  
>  static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
>  {
> -	bool is_tdp_mmu_fault = is_tdp_mmu(vcpu->arch.mmu);
>  	int r;
>  
>  	if (page_fault_handle_page_track(vcpu, fault))
> @@ -4261,11 +4260,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
>  		return r;
>  
>  	r = RET_PF_RETRY;
> -
> -	if (is_tdp_mmu_fault)
> -		read_lock(&vcpu->kvm->mmu_lock);
> -	else
> -		write_lock(&vcpu->kvm->mmu_lock);
> +	write_lock(&vcpu->kvm->mmu_lock);
>  
>  	if (is_page_fault_stale(vcpu, fault))
>  		goto out_unlock;
> @@ -4274,16 +4269,10 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
>  	if (r)
>  		goto out_unlock;
>  
> -	if (is_tdp_mmu_fault)
> -		r = kvm_tdp_mmu_map(vcpu, fault);
> -	else
> -		r = __direct_map(vcpu, fault);
> +	r = __direct_map(vcpu, fault);
>  
>  out_unlock:
> -	if (is_tdp_mmu_fault)
> -		read_unlock(&vcpu->kvm->mmu_lock);
> -	else
> -		write_unlock(&vcpu->kvm->mmu_lock);
> +	write_unlock(&vcpu->kvm->mmu_lock);
>  	kvm_release_pfn_clean(fault->pfn);
>  	return r;
>  }
> @@ -4331,6 +4320,46 @@ int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code,
>  }
>  EXPORT_SYMBOL_GPL(kvm_handle_page_fault);
>  
> +#ifdef CONFIG_X86_64
> +int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu,
> +			   struct kvm_page_fault *fault)

nitpick: static

> +{
> +	int r;
> +
> +	if (page_fault_handle_page_track(vcpu, fault))
> +		return RET_PF_EMULATE;
> +
> +	r = fast_page_fault(vcpu, fault);
> +	if (r != RET_PF_INVALID)
> +		return r;
> +
> +	r = mmu_topup_memory_caches(vcpu, false);
> +	if (r)
> +		return r;
> +
> +	r = kvm_faultin_pfn(vcpu, fault, ACC_ALL);
> +	if (r != RET_PF_CONTINUE)
> +		return r;
> +
> +	r = RET_PF_RETRY;
> +	read_lock(&vcpu->kvm->mmu_lock);
> +
> +	if (is_page_fault_stale(vcpu, fault))
> +		goto out_unlock;
> +
> +	r = make_mmu_pages_available(vcpu);
> +	if (r)
> +		goto out_unlock;
> +
> +	r = kvm_tdp_mmu_map(vcpu, fault);
> +
> +out_unlock:
> +	read_unlock(&vcpu->kvm->mmu_lock);
> +	kvm_release_pfn_clean(fault->pfn);
> +	return r;
> +}
> +#endif
> +
>  int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
>  {
>  	/*
> @@ -4355,6 +4384,11 @@ int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
>  		}
>  	}
>  
> +#ifdef CONFIG_X86_64
> +	if (tdp_mmu_enabled)
> +		return kvm_tdp_mmu_page_fault(vcpu, fault);
> +#endif
> +
>  	return direct_page_fault(vcpu, fault);
>  }

Now we mostly duplicated page_fault method.  We can go one step further.
kvm->arch.mmu.page_fault can be set for each case.  Maybe we can do it later
if necessary.
David Matlack Sept. 1, 2022, 4:50 p.m. UTC | #2
On Tue, Aug 30, 2022 at 4:57 PM Isaku Yamahata <isaku.yamahata@gmail.com> wrote:
>
> On Fri, Aug 26, 2022 at 04:12:25PM -0700,
> David Matlack <dmatlack@google.com> wrote:
>
> > Split out the page fault handling for the TDP MMU to a separate
> > function.  This creates some duplicate code, but makes the TDP MMU fault
> > handler simpler to read by eliminating branches and will enable future
> > cleanups by allowing the TDP MMU and non-TDP MMU fault paths to diverge.
> >
> > Only compile in the TDP MMU fault handler for 64-bit builds since
> > kvm_tdp_mmu_map() does not exist in 32-bit builds.
> >
> > No functional change intended.
> >
> > Signed-off-by: David Matlack <dmatlack@google.com>
> > ---
> >  arch/x86/kvm/mmu/mmu.c | 62 ++++++++++++++++++++++++++++++++----------
> >  1 file changed, 48 insertions(+), 14 deletions(-)
> >
> > diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> > index a185599f4d1d..8f124a23ab4c 100644
> > --- a/arch/x86/kvm/mmu/mmu.c
> > +++ b/arch/x86/kvm/mmu/mmu.c
> > @@ -4242,7 +4242,6 @@ static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
> >
> >  static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
> >  {
> > -     bool is_tdp_mmu_fault = is_tdp_mmu(vcpu->arch.mmu);
> >       int r;
> >
> >       if (page_fault_handle_page_track(vcpu, fault))
> > @@ -4261,11 +4260,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
> >               return r;
> >
> >       r = RET_PF_RETRY;
> > -
> > -     if (is_tdp_mmu_fault)
> > -             read_lock(&vcpu->kvm->mmu_lock);
> > -     else
> > -             write_lock(&vcpu->kvm->mmu_lock);
> > +     write_lock(&vcpu->kvm->mmu_lock);
> >
> >       if (is_page_fault_stale(vcpu, fault))
> >               goto out_unlock;
> > @@ -4274,16 +4269,10 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
> >       if (r)
> >               goto out_unlock;
> >
> > -     if (is_tdp_mmu_fault)
> > -             r = kvm_tdp_mmu_map(vcpu, fault);
> > -     else
> > -             r = __direct_map(vcpu, fault);
> > +     r = __direct_map(vcpu, fault);
> >
> >  out_unlock:
> > -     if (is_tdp_mmu_fault)
> > -             read_unlock(&vcpu->kvm->mmu_lock);
> > -     else
> > -             write_unlock(&vcpu->kvm->mmu_lock);
> > +     write_unlock(&vcpu->kvm->mmu_lock);
> >       kvm_release_pfn_clean(fault->pfn);
> >       return r;
> >  }
> > @@ -4331,6 +4320,46 @@ int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code,
> >  }
> >  EXPORT_SYMBOL_GPL(kvm_handle_page_fault);
> >
> > +#ifdef CONFIG_X86_64
> > +int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu,
> > +                        struct kvm_page_fault *fault)
>
> nitpick: static

Will do.

>
> > +{
> > +     int r;
> > +
> > +     if (page_fault_handle_page_track(vcpu, fault))
> > +             return RET_PF_EMULATE;
> > +
> > +     r = fast_page_fault(vcpu, fault);
> > +     if (r != RET_PF_INVALID)
> > +             return r;
> > +
> > +     r = mmu_topup_memory_caches(vcpu, false);
> > +     if (r)
> > +             return r;
> > +
> > +     r = kvm_faultin_pfn(vcpu, fault, ACC_ALL);
> > +     if (r != RET_PF_CONTINUE)
> > +             return r;
> > +
> > +     r = RET_PF_RETRY;
> > +     read_lock(&vcpu->kvm->mmu_lock);
> > +
> > +     if (is_page_fault_stale(vcpu, fault))
> > +             goto out_unlock;
> > +
> > +     r = make_mmu_pages_available(vcpu);
> > +     if (r)
> > +             goto out_unlock;
> > +
> > +     r = kvm_tdp_mmu_map(vcpu, fault);
> > +
> > +out_unlock:
> > +     read_unlock(&vcpu->kvm->mmu_lock);
> > +     kvm_release_pfn_clean(fault->pfn);
> > +     return r;
> > +}
> > +#endif
> > +
> >  int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
> >  {
> >       /*
> > @@ -4355,6 +4384,11 @@ int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
> >               }
> >       }
> >
> > +#ifdef CONFIG_X86_64
> > +     if (tdp_mmu_enabled)
> > +             return kvm_tdp_mmu_page_fault(vcpu, fault);
> > +#endif
> > +
> >       return direct_page_fault(vcpu, fault);
> >  }
>
> Now we mostly duplicated page_fault method.  We can go one step further.
> kvm->arch.mmu.page_fault can be set for each case.  Maybe we can do it later
> if necessary.

Hm, interesting idea. We would have to refactor the MTRR max_level
code in kvm_tdp_page_fault() into a helper function, but otherwise
that idea would work. I will give it a try in the next version.

> --
> Isaku Yamahata <isaku.yamahata@gmail.com>
David Matlack Sept. 20, 2022, 9:17 p.m. UTC | #3
On Thu, Sep 01, 2022 at 09:50:10AM -0700, David Matlack wrote:
> On Tue, Aug 30, 2022 at 4:57 PM Isaku Yamahata <isaku.yamahata@gmail.com> wrote:
> > On Fri, Aug 26, 2022 at 04:12:25PM -0700, David Matlack <dmatlack@google.com> wrote:
> > >  int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
> > >  {
> > >       /*
> > > @@ -4355,6 +4384,11 @@ int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
> > >               }
> > >       }
> > >
> > > +#ifdef CONFIG_X86_64
> > > +     if (tdp_mmu_enabled)
> > > +             return kvm_tdp_mmu_page_fault(vcpu, fault);
> > > +#endif
> > > +
> > >       return direct_page_fault(vcpu, fault);
> > >  }
> >
> > Now we mostly duplicated page_fault method.  We can go one step further.
> > kvm->arch.mmu.page_fault can be set for each case.  Maybe we can do it later
> > if necessary.
> 
> Hm, interesting idea. We would have to refactor the MTRR max_level
> code in kvm_tdp_page_fault() into a helper function, but otherwise
> that idea would work. I will give it a try in the next version.

So I took a stab at this. Refactoring the max_level adjustment for MTRRs
into a helper function is easy of course. But changing page_fault also
requires changes in kvm_mmu_do_page_fault() for CONFIG_RETPOLINE and
fault->is_tdp. I'm not saying it's not possible (it definitely is) but
it's not trivial to do it in a clean way, so I suggest we table this for
the time being.
Isaku Yamahata Sept. 21, 2022, 11:43 p.m. UTC | #4
On Tue, Sep 20, 2022 at 02:17:20PM -0700,
David Matlack <dmatlack@google.com> wrote:

> On Thu, Sep 01, 2022 at 09:50:10AM -0700, David Matlack wrote:
> > On Tue, Aug 30, 2022 at 4:57 PM Isaku Yamahata <isaku.yamahata@gmail.com> wrote:
> > > On Fri, Aug 26, 2022 at 04:12:25PM -0700, David Matlack <dmatlack@google.com> wrote:
> > > >  int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
> > > >  {
> > > >       /*
> > > > @@ -4355,6 +4384,11 @@ int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
> > > >               }
> > > >       }
> > > >
> > > > +#ifdef CONFIG_X86_64
> > > > +     if (tdp_mmu_enabled)
> > > > +             return kvm_tdp_mmu_page_fault(vcpu, fault);
> > > > +#endif
> > > > +
> > > >       return direct_page_fault(vcpu, fault);
> > > >  }
> > >
> > > Now we mostly duplicated page_fault method.  We can go one step further.
> > > kvm->arch.mmu.page_fault can be set for each case.  Maybe we can do it later
> > > if necessary.
> > 
> > Hm, interesting idea. We would have to refactor the MTRR max_level
> > code in kvm_tdp_page_fault() into a helper function, but otherwise
> > that idea would work. I will give it a try in the next version.
> 
> So I took a stab at this. Refactoring the max_level adjustment for MTRRs
> into a helper function is easy of course. But changing page_fault also
> requires changes in kvm_mmu_do_page_fault() for CONFIG_RETPOLINE and
> fault->is_tdp. I'm not saying it's not possible (it definitely is) but
> it's not trivial to do it in a clean way, so I suggest we table this for
> the time being.

Fair enough.
diff mbox series

Patch

diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index a185599f4d1d..8f124a23ab4c 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -4242,7 +4242,6 @@  static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
 
 static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 {
-	bool is_tdp_mmu_fault = is_tdp_mmu(vcpu->arch.mmu);
 	int r;
 
 	if (page_fault_handle_page_track(vcpu, fault))
@@ -4261,11 +4260,7 @@  static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
 		return r;
 
 	r = RET_PF_RETRY;
-
-	if (is_tdp_mmu_fault)
-		read_lock(&vcpu->kvm->mmu_lock);
-	else
-		write_lock(&vcpu->kvm->mmu_lock);
+	write_lock(&vcpu->kvm->mmu_lock);
 
 	if (is_page_fault_stale(vcpu, fault))
 		goto out_unlock;
@@ -4274,16 +4269,10 @@  static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
 	if (r)
 		goto out_unlock;
 
-	if (is_tdp_mmu_fault)
-		r = kvm_tdp_mmu_map(vcpu, fault);
-	else
-		r = __direct_map(vcpu, fault);
+	r = __direct_map(vcpu, fault);
 
 out_unlock:
-	if (is_tdp_mmu_fault)
-		read_unlock(&vcpu->kvm->mmu_lock);
-	else
-		write_unlock(&vcpu->kvm->mmu_lock);
+	write_unlock(&vcpu->kvm->mmu_lock);
 	kvm_release_pfn_clean(fault->pfn);
 	return r;
 }
@@ -4331,6 +4320,46 @@  int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code,
 }
 EXPORT_SYMBOL_GPL(kvm_handle_page_fault);
 
+#ifdef CONFIG_X86_64
+int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu,
+			   struct kvm_page_fault *fault)
+{
+	int r;
+
+	if (page_fault_handle_page_track(vcpu, fault))
+		return RET_PF_EMULATE;
+
+	r = fast_page_fault(vcpu, fault);
+	if (r != RET_PF_INVALID)
+		return r;
+
+	r = mmu_topup_memory_caches(vcpu, false);
+	if (r)
+		return r;
+
+	r = kvm_faultin_pfn(vcpu, fault, ACC_ALL);
+	if (r != RET_PF_CONTINUE)
+		return r;
+
+	r = RET_PF_RETRY;
+	read_lock(&vcpu->kvm->mmu_lock);
+
+	if (is_page_fault_stale(vcpu, fault))
+		goto out_unlock;
+
+	r = make_mmu_pages_available(vcpu);
+	if (r)
+		goto out_unlock;
+
+	r = kvm_tdp_mmu_map(vcpu, fault);
+
+out_unlock:
+	read_unlock(&vcpu->kvm->mmu_lock);
+	kvm_release_pfn_clean(fault->pfn);
+	return r;
+}
+#endif
+
 int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 {
 	/*
@@ -4355,6 +4384,11 @@  int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
 		}
 	}
 
+#ifdef CONFIG_X86_64
+	if (tdp_mmu_enabled)
+		return kvm_tdp_mmu_page_fault(vcpu, fault);
+#endif
+
 	return direct_page_fault(vcpu, fault);
 }