diff mbox

[v5,1/2] x86/mm: add a function to check if a pfn is UC/UC-

Message ID 20171108075630.16991-2-haozhong.zhang@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Haozhong Zhang Nov. 8, 2017, 7:56 a.m. UTC
It will be used by KVM to check whether a pfn should be
mapped to guest as UC.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/include/asm/pat.h |  2 ++
 arch/x86/mm/pat.c          | 16 ++++++++++++++++
 2 files changed, 18 insertions(+)

Comments

David Hildenbrand Nov. 15, 2017, 10:44 a.m. UTC | #1
On 08.11.2017 08:56, Haozhong Zhang wrote:
> It will be used by KVM to check whether a pfn should be
> mapped to guest as UC.
> 
> Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> ---
>  arch/x86/include/asm/pat.h |  2 ++
>  arch/x86/mm/pat.c          | 16 ++++++++++++++++
>  2 files changed, 18 insertions(+)
> 
> diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
> index fffb2794dd89..fabb0cf00e77 100644
> --- a/arch/x86/include/asm/pat.h
> +++ b/arch/x86/include/asm/pat.h
> @@ -21,4 +21,6 @@ int io_reserve_memtype(resource_size_t start, resource_size_t end,
>  
>  void io_free_memtype(resource_size_t start, resource_size_t end);
>  
> +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn);
> +
>  #endif /* _ASM_X86_PAT_H */
> diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
> index fe7d57a8fb60..e1282dd4eeb8 100644
> --- a/arch/x86/mm/pat.c
> +++ b/arch/x86/mm/pat.c
> @@ -677,6 +677,22 @@ static enum page_cache_mode lookup_memtype(u64 paddr)
>  	return rettype;
>  }
>  
> +/**
> + * Check with PAT whether the memory type of a pfn is UC or UC-.
> + *
> + * Only to be called when PAT is enabled.
> + *
> + * Returns true, if the memory type of @pfn is UC or UC-.
> + * Otherwise, returns false.
> + */
> +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn)
> +{
> +	enum page_cache_mode cm = lookup_memtype(PFN_PHYS(pfn));
> +
> +	return cm == _PAGE_CACHE_MODE_UC || cm == _PAGE_CACHE_MODE_UC_MINUS;
> +}
> +EXPORT_SYMBOL_GPL(pat_pfn_is_uc_or_uc_minus);
> +
>  /**
>   * io_reserve_memtype - Request a memory type mapping for a region of memory
>   * @start: start (physical address) of the region
> 

Wonder if we should check for pat internally. And if we should simply
return the memtype via lookup_memtype() instead of creating such a
strange named function (by providing e.g. a lookup_memtype() variant
that can be called with !pat_enabled()).

The caller can easily check against _PAGE_CACHE_MODE_UC ...
Dan Williams Nov. 15, 2017, 3:17 p.m. UTC | #2
On Tue, Nov 7, 2017 at 11:56 PM, Haozhong Zhang
<haozhong.zhang@intel.com> wrote:
> It will be used by KVM to check whether a pfn should be
> mapped to guest as UC.
>
> Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> ---
>  arch/x86/include/asm/pat.h |  2 ++
>  arch/x86/mm/pat.c          | 16 ++++++++++++++++
>  2 files changed, 18 insertions(+)
>
> diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
> index fffb2794dd89..fabb0cf00e77 100644
> --- a/arch/x86/include/asm/pat.h
> +++ b/arch/x86/include/asm/pat.h
> @@ -21,4 +21,6 @@ int io_reserve_memtype(resource_size_t start, resource_size_t end,
>
>  void io_free_memtype(resource_size_t start, resource_size_t end);
>
> +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn);
> +
>  #endif /* _ASM_X86_PAT_H */
> diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
> index fe7d57a8fb60..e1282dd4eeb8 100644
> --- a/arch/x86/mm/pat.c
> +++ b/arch/x86/mm/pat.c
> @@ -677,6 +677,22 @@ static enum page_cache_mode lookup_memtype(u64 paddr)
>         return rettype;
>  }
>
> +/**
> + * Check with PAT whether the memory type of a pfn is UC or UC-.
> + *
> + * Only to be called when PAT is enabled.
> + *
> + * Returns true, if the memory type of @pfn is UC or UC-.
> + * Otherwise, returns false.
> + */
> +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn)
> +{
> +       enum page_cache_mode cm = lookup_memtype(PFN_PHYS(pfn));
> +
> +       return cm == _PAGE_CACHE_MODE_UC || cm == _PAGE_CACHE_MODE_UC_MINUS;
> +}
> +EXPORT_SYMBOL_GPL(pat_pfn_is_uc_or_uc_minus);

Why do we need this strangely named new accessor? It seems to be
open-coding a new / more limited version of track_pfn_insert().
Haozhong Zhang Nov. 16, 2017, 6:13 a.m. UTC | #3
On 11/15/17 07:17 -0800, Dan Williams wrote:
> On Tue, Nov 7, 2017 at 11:56 PM, Haozhong Zhang
> <haozhong.zhang@intel.com> wrote:
> > It will be used by KVM to check whether a pfn should be
> > mapped to guest as UC.
> >
> > Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> > ---
> >  arch/x86/include/asm/pat.h |  2 ++
> >  arch/x86/mm/pat.c          | 16 ++++++++++++++++
> >  2 files changed, 18 insertions(+)
> >
> > diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
> > index fffb2794dd89..fabb0cf00e77 100644
> > --- a/arch/x86/include/asm/pat.h
> > +++ b/arch/x86/include/asm/pat.h
> > @@ -21,4 +21,6 @@ int io_reserve_memtype(resource_size_t start, resource_size_t end,
> >
> >  void io_free_memtype(resource_size_t start, resource_size_t end);
> >
> > +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn);
> > +
> >  #endif /* _ASM_X86_PAT_H */
> > diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
> > index fe7d57a8fb60..e1282dd4eeb8 100644
> > --- a/arch/x86/mm/pat.c
> > +++ b/arch/x86/mm/pat.c
> > @@ -677,6 +677,22 @@ static enum page_cache_mode lookup_memtype(u64 paddr)
> >         return rettype;
> >  }
> >
> > +/**
> > + * Check with PAT whether the memory type of a pfn is UC or UC-.
> > + *
> > + * Only to be called when PAT is enabled.
> > + *
> > + * Returns true, if the memory type of @pfn is UC or UC-.
> > + * Otherwise, returns false.
> > + */
> > +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn)
> > +{
> > +       enum page_cache_mode cm = lookup_memtype(PFN_PHYS(pfn));
> > +
> > +       return cm == _PAGE_CACHE_MODE_UC || cm == _PAGE_CACHE_MODE_UC_MINUS;
> > +}
> > +EXPORT_SYMBOL_GPL(pat_pfn_is_uc_or_uc_minus);
> 
> Why do we need this strangely named new accessor? It seems to be
> open-coding a new / more limited version of track_pfn_insert().

In the first version patchset, KVM did extract and check the cache
mode got from track_pfn_insert(), but Ingo thought it was better to
keep all the low-level details out of KVM, so I encapsulated them in a
function in mm in subsequent versions.

Haozhong
Haozhong Zhang Nov. 16, 2017, 7:08 a.m. UTC | #4
On 11/15/17 11:44 +0100, David Hildenbrand wrote:
> On 08.11.2017 08:56, Haozhong Zhang wrote:
> > It will be used by KVM to check whether a pfn should be
> > mapped to guest as UC.
> > 
> > Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> > ---
> >  arch/x86/include/asm/pat.h |  2 ++
> >  arch/x86/mm/pat.c          | 16 ++++++++++++++++
> >  2 files changed, 18 insertions(+)
> > 
> > diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
> > index fffb2794dd89..fabb0cf00e77 100644
> > --- a/arch/x86/include/asm/pat.h
> > +++ b/arch/x86/include/asm/pat.h
> > @@ -21,4 +21,6 @@ int io_reserve_memtype(resource_size_t start, resource_size_t end,
> >  
> >  void io_free_memtype(resource_size_t start, resource_size_t end);
> >  
> > +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn);
> > +
> >  #endif /* _ASM_X86_PAT_H */
> > diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
> > index fe7d57a8fb60..e1282dd4eeb8 100644
> > --- a/arch/x86/mm/pat.c
> > +++ b/arch/x86/mm/pat.c
> > @@ -677,6 +677,22 @@ static enum page_cache_mode lookup_memtype(u64 paddr)
> >  	return rettype;
> >  }
> >  
> > +/**
> > + * Check with PAT whether the memory type of a pfn is UC or UC-.
> > + *
> > + * Only to be called when PAT is enabled.
> > + *
> > + * Returns true, if the memory type of @pfn is UC or UC-.
> > + * Otherwise, returns false.
> > + */
> > +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn)
> > +{
> > +	enum page_cache_mode cm = lookup_memtype(PFN_PHYS(pfn));
> > +
> > +	return cm == _PAGE_CACHE_MODE_UC || cm == _PAGE_CACHE_MODE_UC_MINUS;
> > +}
> > +EXPORT_SYMBOL_GPL(pat_pfn_is_uc_or_uc_minus);
> > +
> >  /**
> >   * io_reserve_memtype - Request a memory type mapping for a region of memory
> >   * @start: start (physical address) of the region
> > 
> 
> Wonder if we should check for pat internally. And if we should simply
> return the memtype via lookup_memtype() instead of creating such a
> strange named function (by providing e.g. a lookup_memtype() variant
> that can be called with !pat_enabled()).
>
> The caller can easily check against _PAGE_CACHE_MODE_UC ...
>

Yes, the better solution should work for both PAT enabled and disabled
cases, like what __vm_insert_mixed() does: use vma->vm_page_prot if
PAT is disabled, and refer to track_pfn_insert() in addition if PAT is
enabled.

The early RFC patch [1] got the cache mode in a similar way via a new
function kvm_vcpu_gfn_to_pgprot(). However, as explained in RFC, it
does not work, because the existing MMIO check (where kvm_vcpu_gfn_to_pgprot()
is called) in KVM is performed with a spinlock (vcpu->kvm->mmu_lock)
being taken, but kvm_vcpu_gfn_to_pgprot() has to touch a semaphore
(vcpu->kvm->mm->mmap_sem). Besides, KVM may prefetch and check MMIO of
other pfns within vcpu->kvm->mmu_lock, and the prefectched pfns cannot
be predicted in advance, which means we have to keep the MMIO check
within vcpu->kvm->mmu_lock.

Therefore, I only make a suboptimal fix in this patchset that only
fixes PAT enabled cases, which I suppose is the usual usage scenario
of NVDIMM.


[1] https://patchwork.kernel.org/patch/10016261/


Haozhong
Paolo Bonzini Dec. 18, 2017, 12:55 p.m. UTC | #5
On 08/11/2017 08:56, Haozhong Zhang wrote:
> +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn)
> +{
> +	enum page_cache_mode cm = lookup_memtype(PFN_PHYS(pfn));
> +
> +	return cm == _PAGE_CACHE_MODE_UC || cm == _PAGE_CACHE_MODE_UC_MINUS;
> +}
> +EXPORT_SYMBOL_GPL(pat_pfn_is_uc_or_uc_minus);
> +

As discussed in the reply to v2, this should include WC too.  The
function name could become something like pat_pfn_downgraded_by_uc_mtrr.

Thanks,

Paolo
Haozhong Zhang Dec. 19, 2017, 2:40 a.m. UTC | #6
On 12/18/17 13:55 +0100, Paolo Bonzini wrote:
> On 08/11/2017 08:56, Haozhong Zhang wrote:
> > +bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn)
> > +{
> > +	enum page_cache_mode cm = lookup_memtype(PFN_PHYS(pfn));
> > +
> > +	return cm == _PAGE_CACHE_MODE_UC || cm == _PAGE_CACHE_MODE_UC_MINUS;
> > +}
> > +EXPORT_SYMBOL_GPL(pat_pfn_is_uc_or_uc_minus);
> > +
> 
> As discussed in the reply to v2, this should include WC too.  The
> function name could become something like pat_pfn_downgraded_by_uc_mtrr.

Or shall we just expose lookup_memtype(), and keep all other logic in
KVM? The function name still looks strange somehow, and the check of
memory type makes more sense and would be easier to understand in the
context of KVM.

Haozhong
Paolo Bonzini Dec. 19, 2017, 10:42 a.m. UTC | #7
On 19/12/2017 03:40, Haozhong Zhang wrote:
>> As discussed in the reply to v2, this should include WC too.  The
>> function name could become something like pat_pfn_downgraded_by_uc_mtrr.
>
> Or shall we just expose lookup_memtype(), and keep all other logic in
> KVM? The function name still looks strange somehow, and the check of
> memory type makes more sense and would be easier to understand in the
> context of KVM.

I agree that it's a bit strange, but I don't want to go against the
suggestions of the x86 maintainer.

Paolo
diff mbox

Patch

diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
index fffb2794dd89..fabb0cf00e77 100644
--- a/arch/x86/include/asm/pat.h
+++ b/arch/x86/include/asm/pat.h
@@ -21,4 +21,6 @@  int io_reserve_memtype(resource_size_t start, resource_size_t end,
 
 void io_free_memtype(resource_size_t start, resource_size_t end);
 
+bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn);
+
 #endif /* _ASM_X86_PAT_H */
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index fe7d57a8fb60..e1282dd4eeb8 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -677,6 +677,22 @@  static enum page_cache_mode lookup_memtype(u64 paddr)
 	return rettype;
 }
 
+/**
+ * Check with PAT whether the memory type of a pfn is UC or UC-.
+ *
+ * Only to be called when PAT is enabled.
+ *
+ * Returns true, if the memory type of @pfn is UC or UC-.
+ * Otherwise, returns false.
+ */
+bool pat_pfn_is_uc_or_uc_minus(unsigned long pfn)
+{
+	enum page_cache_mode cm = lookup_memtype(PFN_PHYS(pfn));
+
+	return cm == _PAGE_CACHE_MODE_UC || cm == _PAGE_CACHE_MODE_UC_MINUS;
+}
+EXPORT_SYMBOL_GPL(pat_pfn_is_uc_or_uc_minus);
+
 /**
  * io_reserve_memtype - Request a memory type mapping for a region of memory
  * @start: start (physical address) of the region