kvm: Use huge pages for DAX-backed files
Subsystems (7)
cover kvm: Use huge pages for DAX-backed files
This patch series depends on dax pages not being PageReserved. Once that is in place, these changes will let KVM use huge pages with dax-backed files. Without the PageReserved change, KVM and DAX still work with these patches, simply without huge pages - which is the current situation.
RFC/discussion thread:
https://lore.kernel.org/lkml/[email protected]/
Barret Rhoden (2):
mm: make dev_pagemap_mapping_shift() externally visible
kvm: Use huge pages for DAX-backed files
arch/x86/kvm/mmu.c | 34 ++++++++++++++++++++++++++++++++-- include/linux/mm.h | 3 +++ mm/memory-failure.c | 38 +++----------------------------------- mm/util.c | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 37 deletions(-)
Signature · 1 line
2.19.1.930.g4563a0d9d0-goog
PATCH 1/2 mm: make dev_pagemap_mapping_shift() externally visible
KVM has a use case for determining the size of a dax mapping. The KVM code has easy access to the address and the mm; hence the change in parameters.
--- include/linux/mm.h | 3 +++ mm/memory-failure.c | 38 +++----------------------------------- mm/util.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 35 deletions(-)
include/linux/mm.h +3 -0
@@ -935,6 +935,9 @@ static inline bool is_pci_p2pdma_page(const struct page *page) }#endif /* CONFIG_DEV_PAGEMAP_OPS */ +unsigned long dev_pagemap_mapping_shift (unsigned long address, +struct mm_struct *mm); +static inline void get_page (struct page *page) { page =compound_head (page);
mm/memory-failure.c +3 -35
@@ -265,40 +265,6 @@ void shake_page(struct page *p, int access) }EXPORT_SYMBOL_GPL (shake_page); -static unsigned long dev_pagemap_mapping_shift (struct page *page, -struct vm_area_struct *vma) -{ -unsigned long address =vma_address (page, vma); -pgd_t *pgd; -p4d_t *p4d; -pud_t *pud; -pmd_t *pmd; -pte_t *pte; - - pgd =pgd_offset (vma->vm_mm, address); -if (!pgd_present (*pgd)) -return 0 ; - p4d =p4d_offset (pgd, address); -if (!p4d_present (*p4d)) -return 0 ; - pud =pud_offset (p4d, address); -if (!pud_present (*pud)) -return 0 ; -if (pud_devmap (*pud)) -return PUD_SHIFT ; - pmd =pmd_offset (pud, address); -if (!pmd_present (*pmd)) -return 0 ; -if (pmd_devmap (*pmd)) -return PMD_SHIFT ; - pte =pte_offset_map (pmd, address); -if (!pte_present (*pte)) -return 0 ; -if (pte_devmap (*pte)) -return PAGE_SHIFT ; -return 0 ; -} -/* * Failure handling: if we can't find or can't kill a process there's * not much we can do. We just print a message and ignore otherwise.
@@ -329,7 +295,9 @@ static void add_to_kill(struct task_struct *tsk, struct page *p, tk->addr =page_address_in_vma (p, vma); tk->addr_valid =1 ;if (is_zone_device_page (p)) - tk->size_shift =dev_pagemap_mapping_shift (p, vma); + tk->size_shift = +dev_pagemap_mapping_shift (vma_address (page, vma), + vma->vm_mm);else tk->size_shift =compound_order (compound_head (p)) +PAGE_SHIFT ;
mm/util.c +34 -0
@@ -780,3 +780,37 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) out:return res; } + +unsigned long dev_pagemap_mapping_shift (unsigned long address, +struct mm_struct *mm) +{ +pgd_t *pgd; +p4d_t *p4d; +pud_t *pud; +pmd_t *pmd; +pte_t *pte; + + pgd =pgd_offset (mm, address); +if (!pgd_present (*pgd)) +return 0 ; + p4d =p4d_offset (pgd, address); +if (!p4d_present (*p4d)) +return 0 ; + pud =pud_offset (p4d, address); +if (!pud_present (*pud)) +return 0 ; +if (pud_devmap (*pud)) +return PUD_SHIFT ; + pmd =pmd_offset (pud, address); +if (!pmd_present (*pmd)) +return 0 ; +if (pmd_devmap (*pmd)) +return PMD_SHIFT ; + pte =pte_offset_map (pmd, address); +if (!pte_present (*pte)) +return 0 ; +if (pte_devmap (*pte)) +return PAGE_SHIFT ; +return 0 ; +} +EXPORT_SYMBOL_GPL (dev_pagemap_mapping_shift);
Signature · 1 line
2.19.1.930.g4563a0d9d0-goog
Re: [PATCH 1/2] mm: make dev_pagemap_mapping_shift() externally visible
Quoted 114 lines · Barret Rhoden
KVM has a use case for determining the size of a dax mapping. The KVM code has easy access to the address and the mm; hence the change in parameters.
Signed-off-by Barret Rhoden <[email protected]>--- include/linux/mm.h | 3 +++ mm/memory-failure.c | 38 +++----------------------------------- mm/util.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 35 deletions(-)include/linux/mm.h +3
-0@@ -935,6 +935,9 @@ static inline bool is_pci_p2pdma_page(const struct page *page) }#endif /* CONFIG_DEV_PAGEMAP_OPS */ +unsigned long dev_pagemap_mapping_shift (unsigned long address, +struct mm_struct *mm); +static inline void get_page (struct page *page) { page =compound_head (page);mm/memory-failure.c +3
-35@@ -265,40 +265,6 @@ void shake_page(struct page *p, int access) }EXPORT_SYMBOL_GPL (shake_page); -static unsigned long dev_pagemap_mapping_shift (struct page *page, -struct vm_area_struct *vma) -{ -unsigned long address =vma_address (page, vma); -pgd_t *pgd; -p4d_t *p4d; -pud_t *pud; -pmd_t *pmd; -pte_t *pte; - - pgd =pgd_offset (vma->vm_mm, address); -if (!pgd_present (*pgd)) -return 0 ; - p4d =p4d_offset (pgd, address); -if (!p4d_present (*p4d)) -return 0 ; - pud =pud_offset (p4d, address); -if (!pud_present (*pud)) -return 0 ; -if (pud_devmap (*pud)) -return PUD_SHIFT ; - pmd =pmd_offset (pud, address); -if (!pmd_present (*pmd)) -return 0 ; -if (pmd_devmap (*pmd)) -return PMD_SHIFT ; - pte =pte_offset_map (pmd, address); -if (!pte_present (*pte)) -return 0 ; -if (pte_devmap (*pte)) -return PAGE_SHIFT ; -return 0 ; -} -/* * Failure handling: if we can't find or can't kill a process there's * not much we can do. We just print a message and ignore otherwise. @@ -329,7 +295,9 @@ static void add_to_kill(struct task_struct *tsk, struct page *p, tk->addr =page_address_in_vma (p, vma); tk->addr_valid =1 ;if (is_zone_device_page (p)) - tk->size_shift =dev_pagemap_mapping_shift (p, vma); + tk->size_shift = +dev_pagemap_mapping_shift (vma_address (page, vma), + vma->vm_mm);else tk->size_shift =compound_order (compound_head (p)) +PAGE_SHIFT ;mm/util.c +24
-0@@ -780,3 +780,37 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) out:return res; } + +unsigned long dev_pagemap_mapping_shift (unsigned long address, +struct mm_struct *mm) +{ +pgd_t *pgd; +p4d_t *p4d; +pud_t *pud; +pmd_t *pmd; +pte_t *pte; + + pgd =pgd_offset (mm, address); +if (!pgd_present (*pgd)) +return 0 ; + p4d =p4d_offset (pgd, address); +if (!p4d_present (*p4d)) +return 0 ; + pud =pud_offset (p4d, address); +if (!pud_present (*pud)) +return 0 ; +if (pud_devmap (*pud)) +return PUD_SHIFT ; + pmd =pmd_offset (pud, address); +if (!pmd_present (*pmd)) +return 0 ;
mm/util.c int get_cmdline(struct task_struct *task, char *buffer, int buflen) · line 816
Quoted 10 lines
mm/util.c +10
-0+if (pmd_devmap (*pmd)) +return PMD_SHIFT ; + pte =pte_offset_map (pmd, address); +if (!pte_present (*pte)) +return 0 ; +if (pte_devmap (*pte)) +return PAGE_SHIFT ; +return 0 ; +} +EXPORT_SYMBOL_GPL (dev_pagemap_mapping_shift);
Looks good to me
Signature · 3 lines
Thanks, David / dhildenb
PATCH 2/2 kvm: Use huge pages for DAX-backed files
In reply to Barret RhodenThis change allows KVM to map DAX-backed files made of huge pages with huge mappings in the EPT/TDP.
DAX pages are not PageTransCompound. The existing check is trying to determine if the mapping for the pfn is a huge mapping or not. For non-DAX maps, e.g. hugetlbfs, that means checking PageTransCompound. For DAX, we can check the page table itself.
Note that KVM already faulted in the page (or huge page) in the host's page table, and we hold the KVM mmu spinlock (grabbed before checking the mmu seq).
--- arch/x86/kvm/mmu.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)
arch/x86/kvm/mmu.c +32 -2
@@ -3152,6 +3152,36 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)return -EFAULT ; } +static bool pfn_is_huge_mapped (struct kvm *kvm,gfn_t gfn,kvm_pfn_t pfn) +{ +struct page *page =pfn_to_page (pfn); +unsigned long hva, map_shift; + +if (!is_zone_device_page (page)) +return PageTransCompoundMap (page); + +/* +* DAX pages do not use compound pages. The page should have already +* been mapped into the host-side page table during try_async_pf(), so +* we can check the page tables directly. +*/ + hva =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (hva)) +return false; + +/* +* Our caller grabbed the KVM mmu_lock with a successful +* mmu_notifier_retry, so we're safe to walk the page table. +*/ + map_shift =dev_pagemap_mapping_shift (hva, current->mm); +switch (map_shift) { +case PMD_SHIFT : +case PUD_SIZE : +return true; + } +return false; +} +static void transparent_hugepage_adjust (struct kvm_vcpu *vcpu,gfn_t *gfnp,kvm_pfn_t *pfnp,int *levelp)
@@ -3168,7 +3198,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,*/ if (!is_error_noslot_pfn (pfn) && !kvm_is_reserved_pfn (pfn) && level ==PT_PAGE_TABLE_LEVEL && -PageTransCompoundMap (pfn_to_page (pfn)) && +pfn_is_huge_mapped (vcpu->kvm, gfn, pfn) && !mmu_gfn_lpage_is_disallowed (vcpu, gfn,PT_DIRECTORY_LEVEL )) {unsigned long mask;/*
@@ -5678,7 +5708,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,*/ if (sp->role.direct && !kvm_is_reserved_pfn (pfn) && -PageTransCompoundMap (pfn_to_page (pfn))) { +pfn_is_huge_mapped (kvm, sp->gfn, pfn)) {pte_list_remove (rmap_head, sptep); need_tlb_flush =1 ; goto restart;
Signature · 1 line
2.19.1.930.g4563a0d9d0-goog
Paolo Bonzini
maintainerQuoted 8 lines · Barret Rhoden
This change allows KVM to map DAX-backed files made of huge pages with huge mappings in the EPT/TDP.
DAX pages are not PageTransCompound. The existing check is trying to determine if the mapping for the pfn is a huge mapping or not. For non-DAX maps, e.g. hugetlbfs, that means checking PageTransCompound. For DAX, we can check the page table itself.
Quoted 8 lines
Note that KVM already faulted in the page (or huge page) in the host's page table, and we hold the KVM mmu spinlock (grabbed before checking the mmu seq).
Signed-off-by Barret Rhoden <[email protected]>--- arch/x86/kvm/mmu.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)
Looks good. What's the plan for removing PageReserved from DAX pages?
Thanks,
Paolo
Quoted 60 lines
arch/x86/kvm/mmu.c +32
-2@@ -3152,6 +3152,36 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)return -EFAULT ; } +static bool pfn_is_huge_mapped (struct kvm *kvm,gfn_t gfn,kvm_pfn_t pfn) +{ +struct page *page =pfn_to_page (pfn); +unsigned long hva, map_shift; + +if (!is_zone_device_page (page)) +return PageTransCompoundMap (page); + +/* +* DAX pages do not use compound pages. The page should have already +* been mapped into the host-side page table during try_async_pf(), so +* we can check the page tables directly. +*/ + hva =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (hva)) +return false; + +/* +* Our caller grabbed the KVM mmu_lock with a successful +* mmu_notifier_retry, so we're safe to walk the page table. +*/ + map_shift =dev_pagemap_mapping_shift (hva, current->mm); +switch (map_shift) { +case PMD_SHIFT : +case PUD_SIZE : +return true; + } +return false; +} +static void transparent_hugepage_adjust (struct kvm_vcpu *vcpu,gfn_t *gfnp,kvm_pfn_t *pfnp,int *levelp)@@ -3168,7 +3198,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,*/ if (!is_error_noslot_pfn (pfn) && !kvm_is_reserved_pfn (pfn) && level ==PT_PAGE_TABLE_LEVEL && -PageTransCompoundMap (pfn_to_page (pfn)) && +pfn_is_huge_mapped (vcpu->kvm, gfn, pfn) && !mmu_gfn_lpage_is_disallowed (vcpu, gfn,PT_DIRECTORY_LEVEL )) {unsigned long mask;/* @@ -5678,7 +5708,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,*/ if (sp->role.direct && !kvm_is_reserved_pfn (pfn) && -PageTransCompoundMap (pfn_to_page (pfn))) { +pfn_is_huge_mapped (kvm, sp->gfn, pfn)) {pte_list_remove (rmap_head, sptep); need_tlb_flush =1 ; goto restart;
Quoted 1 line · On 2018-11-12 at 20:31 Paolo Bonzini <[email protected]…
Looks good. What's the plan for removing PageReserved from DAX pages?
I hear that's going on in this thread:
Though it looks like it's speeding up page initialization, and not explicitly making the PageReserved change, yet.
Alternatively, I could change kvm_is_reserved_pfn() to single out zone_device pages if we don't want to wait or if there is a concern that it won't happen.
On a related note, there are two places in KVM where we check PageReserved outside of kvm_is_reserved_pfn().
For reference:
bool kvm_is_reserved_pfn(kvm_pfn_t pfn)
{
if (pfn_valid(pfn))
return PageReserved(pfn_to_page(pfn));
return true;
}One caller of PageReserved():
void kvm_set_pfn_dirty(kvm_pfn_t pfn)
{
if (!kvm_is_reserved_pfn(pfn)) {
struct page *page = pfn_to_page(pfn);
if (!PageReserved(page))
SetPageDirty(page);
}
}In that one, the PageReserved() check looks redundant, since if the page was PageReserved, then it would have been kvm_is_reserved.
The other is:
static bool kvm_is_mmio_pfn(kvm_pfn_t pfn)
{
if (pfn_valid(pfn))
return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn)) &&
/*
* Some reserved pages, such as those from NVDIMM
* DAX devices, are not for MMIO, and can be mapped
* with cached memory type for better performance.
* However, the above check misconceives those pages
* as MMIO, and results in KVM mapping them with UC
* memory type, which would hurt the performance.
* Therefore, we check the host memory type in addition
* and only treat UC/UC-/WC pages as MMIO. */
(!pat_enabled() || pat_pfn_immune_to_uc_mtrr(pfn));
return true;
}
Where the PAT stuff was motivated by DAX. The PageReserved check here looks like a broken-out version of kvm_is_reserved_pfn(), so that we can make some extra checks around it.
Anyway, I can get rid of those two PageReserved checks and/or have kvm_is_reserved_pfn() just check DAX pages, if everyone is OK with that.
Thanks,
Barret
Paolo Bonzini
maintainerQuoted 39 lines · Barret Rhoden
Quoted 1 line · On 2018-11-12 at 20:31 Paolo Bonzini <[email protected]> wrote:
Looks good. What's the plan for removing PageReserved from DAX pages?
I hear that's going on in this thread:
Though it looks like it's speeding up page initialization, and not explicitly making the PageReserved change, yet.
Alternatively, I could change
kvm_is_reserved_pfn()to single outzone_devicepages if we don't want to wait or if there is a concern that it won't happen.On a related note, there are two places in KVM where we check PageReserved outside of
kvm_is_reserved_pfn().For reference:
bool
kvm_is_reserved_pfn(kvm_pfn_t pfn){ if (pfn_valid(pfn)) return PageReserved(pfn_to_page(pfn)); return true; }One caller of
PageReserved():void
kvm_set_pfn_dirty(kvm_pfn_t pfn){ if (!kvm_is_reserved_pfn(pfn)) { struct page *page = pfn_to_page(pfn); if (!PageReserved(page)) SetPageDirty(page); } }
Quoted 2 lines
In that one, the
PageReserved()check looks redundant, since if the page was PageReserved, then it would have beenkvm_is_reserved.
Make sense, and a patch to fix this is welcome.
Quoted 19 lines
The other is:
static bool
kvm_is_mmio_pfn(kvm_pfn_t pfn)
{
if (pfn_valid(pfn))
return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn)) &&
/*
* Some reserved pages, such as those from NVDIMM
* DAX devices, are not for MMIO, and can be mapped
* with cached memory type for better performance.
* However, the above check misconceives those pages
* as MMIO, and results in KVM mapping them with UC
* memory type, which would hurt the performance.
* Therefore, we check the host memory type in addition
* and only treat UC/UC-/WC pages as MMIO. */
(!pat_enabled() ||pat_pfn_immune_to_uc_mtrr(pfn));
Quoted 6 lines
return true;
}Where the PAT stuff was motivated by DAX. The PageReserved check here looks like a broken-out version of
kvm_is_reserved_pfn(), so that we can make some extra checks around it.
Since this one is indeed motivated by DAX, it can be left in for now and it will DTRT. But when DAX is not PageReserved anymore, then this second part of the condition can be reverted.
Paolo
Quoted 11 lines · Barret Rhoden
This change allows KVM to map DAX-backed files made of huge pages with huge mappings in the EPT/TDP.
DAX pages are not PageTransCompound. The existing check is trying to determine if the mapping for the pfn is a huge mapping or not. For non-DAX maps, e.g. hugetlbfs, that means checking PageTransCompound. For DAX, we can check the page table itself.
Note that KVM already faulted in the page (or huge page) in the host's page table, and we hold the KVM mmu spinlock (grabbed before checking the mmu seq).
I wonder if the KVM mmu spinlock is enough for walking (not KVM exclusive) host page tables. Can you elaborate?
Quoted 26 lines
Signed-off-by Barret Rhoden <[email protected]>--- arch/x86/kvm/mmu.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)arch/x86/kvm/mmu.c +12
-0@@ -3152,6 +3152,36 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)return -EFAULT ; } +static bool pfn_is_huge_mapped (struct kvm *kvm,gfn_t gfn,kvm_pfn_t pfn) +{ +struct page *page =pfn_to_page (pfn); +unsigned long hva, map_shift; + +if (!is_zone_device_page (page)) +return PageTransCompoundMap (page); + +/* +* DAX pages do not use compound pages. The page should have already +* been mapped into the host-side page table during try_async_pf(), so +* we can check the page tables directly.
arch/x86/kvm/mmu.c static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn) · line 3176
Quoted 10 lines
arch/x86/kvm/mmu.c +10
-0+*/ + hva =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (hva)) +return false; + +/* +* Our caller grabbed the KVM mmu_lock with a successful +* mmu_notifier_retry, so we're safe to walk the page table. +*/ + map_shift =dev_pagemap_mapping_shift (hva, current->mm);
You could get rid of that local variable map_shift.
Quoted 22 lines
arch/x86/kvm/mmu.c +9
-1+switch (map_shift) { +case PMD_SHIFT : +case PUD_SIZE : +return true; + } +return false; +} +static void transparent_hugepage_adjust (struct kvm_vcpu *vcpu,gfn_t *gfnp,kvm_pfn_t *pfnp,int *levelp)@@ -3168,7 +3198,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,*/ if (!is_error_noslot_pfn (pfn) && !kvm_is_reserved_pfn (pfn) && level ==PT_PAGE_TABLE_LEVEL && -PageTransCompoundMap (pfn_to_page (pfn)) && +pfn_is_huge_mapped (vcpu->kvm, gfn, pfn) && !mmu_gfn_lpage_is_disallowed (vcpu, gfn,PT_DIRECTORY_LEVEL )) {unsigned long mask;/*
arch/x86/kvm/mmu.c static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm, · line 5714
Quoted 8 lines
arch/x86/kvm/mmu.c +1
-1@@ -5678,7 +5708,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,*/ if (sp->role.direct && !kvm_is_reserved_pfn (pfn) && -PageTransCompoundMap (pfn_to_page (pfn))) { +pfn_is_huge_mapped (kvm, sp->gfn, pfn)) {pte_list_remove (rmap_head, sptep); need_tlb_flush =1 ; goto restart;
This looks surprisingly simple to me :)
Signature · 3 lines
Thanks, David / dhildenb
Quoted 11 lines · Barret Rhoden
Quoted 8 lines
This change allows KVM to map DAX-backed files made of huge pages with huge mappings in the EPT/TDP.
DAX pages are not PageTransCompound. The existing check is trying to determine if the mapping for the pfn is a huge mapping or not. For non-DAX maps, e.g. hugetlbfs, that means checking PageTransCompound. For DAX, we can check the page table itself.
Quoted 6 lines
Quoted 3 lines
Note that KVM already faulted in the page (or huge page) in the host's page table, and we hold the KVM mmu spinlock (grabbed before checking the mmu seq).
I wonder if the KVM mmu spinlock is enough for walking (not KVM exclusive) host page tables. Can you elaborate?
As this patch is dependent on PageReserved patch(which is in progress), just wondering if we are able to test the code path for hugepage with DAX.
Thanks,
Pankaj
Quoted 82 lines
Quoted 28 lines
Signed-off-by Barret Rhoden <[email protected]>--- arch/x86/kvm/mmu.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)arch/x86/kvm/mmu.c +12
-0@@ -3152,6 +3152,36 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)return -EFAULT ; } +static bool pfn_is_huge_mapped (struct kvm *kvm,gfn_t gfn,kvm_pfn_t pfn) +{ +struct page *page =pfn_to_page (pfn); +unsigned long hva, map_shift; + +if (!is_zone_device_page (page)) +return PageTransCompoundMap (page); + +/* +* DAX pages do not use compound pages. The page should have already +* been mapped into the host-side page table during try_async_pf(), so +* we can check the page tables directly. arch/x86/kvm/mmu.c static int kvm_handle_bad_page(struct kvm_vcpu · line 3177
Quoted 10 lines
arch/x86/kvm/mmu.c +10
-0+*/ + hva =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (hva)) +return false; + +/* +* Our caller grabbed the KVM mmu_lock with a successful +* mmu_notifier_retry, so we're safe to walk the page table. +*/ + map_shift =dev_pagemap_mapping_shift (hva, current->mm);You could get rid of that local variable
map_shift.Quoted 30 lines
arch/x86/kvm/mmu.c +8
-0+switch (map_shift) { +case PMD_SHIFT : +case PUD_SIZE : +return true; + } +return false; +} + static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, gfn_t *gfnp, kvm_pfn_t *pfnp,arch/x86/kvm/mmu.c +1
-1int *levelp)@@ -3168,7 +3198,7 @@ static void transparent_hugepage_adjust(structkvm_vcpu *vcpu, */ if (!is_error_noslot_pfn (pfn) && !kvm_is_reserved_pfn (pfn) && level ==PT_PAGE_TABLE_LEVEL && -PageTransCompoundMap (pfn_to_page (pfn)) && +pfn_is_huge_mapped (vcpu->kvm, gfn, pfn) && !mmu_gfn_lpage_is_disallowed (vcpu, gfn,PT_DIRECTORY_LEVEL )) {unsigned long mask;arch/x86/kvm/mmu.c +1
-1/* @@ -5678,7 +5708,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm*kvm, */ if (sp->role.direct && !kvm_is_reserved_pfn (pfn) && -PageTransCompoundMap (pfn_to_page (pfn))) { +pfn_is_huge_mapped (kvm, sp->gfn, pfn)) {pte_list_remove (rmap_head, sptep); need_tlb_flush =1 ;Quoted 2 lines
goto restart;
This looks surprisingly simple to me :)
--
Thanks,
David / dhildenb
Paolo Bonzini
maintainerQuoted 15 lines · Pankaj Gupta
Quoted 15 lines · Barret Rhoden
Quoted 11 lines
This change allows KVM to map DAX-backed files made of huge pages with huge mappings in the EPT/TDP.
DAX pages are not PageTransCompound. The existing check is trying to determine if the mapping for the pfn is a huge mapping or not. For non-DAX maps, e.g. hugetlbfs, that means checking PageTransCompound. For DAX, we can check the page table itself.
Note that KVM already faulted in the page (or huge page) in the host's page table, and we hold the KVM mmu spinlock (grabbed before checking the mmu seq).
Quoted 5 lines
Quoted 2 lines
I wonder if the KVM mmu spinlock is enough for walking (not KVM exclusive) host page tables. Can you elaborate?
As this patch is dependent on PageReserved patch(which is in progress), just wondering if we are able to test the code path for hugepage with DAX.
The MMU spinlock is taken in kvm_mmu_notifier_invalidate_range_end, so it should be enough.
Paolo
Quoted 86 lines
Thanks,
PankajQuoted 82 lines
Quoted 28 lines
Signed-off-by Barret Rhoden <[email protected]>--- arch/x86/kvm/mmu.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-)arch/x86/kvm/mmu.c +12
-0@@ -3152,6 +3152,36 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)return -EFAULT ; } +static bool pfn_is_huge_mapped (struct kvm *kvm,gfn_t gfn,kvm_pfn_t pfn) +{ +struct page *page =pfn_to_page (pfn); +unsigned long hva, map_shift; + +if (!is_zone_device_page (page)) +return PageTransCompoundMap (page); + +/* +* DAX pages do not use compound pages. The page should have already +* been mapped into the host-side page table during try_async_pf(), so +* we can check the page tables directly. arch/x86/kvm/mmu.c static int kvm_handle_bad_page(struct kvm_vcpu · line 3177
Quoted 10 lines
arch/x86/kvm/mmu.c +10
-0+*/ + hva =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (hva)) +return false; + +/* +* Our caller grabbed the KVM mmu_lock with a successful +* mmu_notifier_retry, so we're safe to walk the page table. +*/ + map_shift =dev_pagemap_mapping_shift (hva, current->mm);You could get rid of that local variable
map_shift.Quoted 30 lines
arch/x86/kvm/mmu.c +8
-0+switch (map_shift) { +case PMD_SHIFT : +case PUD_SIZE : +return true; + } +return false; +} + static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, gfn_t *gfnp, kvm_pfn_t *pfnp,arch/x86/kvm/mmu.c +1
-1int *levelp)@@ -3168,7 +3198,7 @@ static void transparent_hugepage_adjust(structkvm_vcpu *vcpu, */ if (!is_error_noslot_pfn (pfn) && !kvm_is_reserved_pfn (pfn) && level ==PT_PAGE_TABLE_LEVEL && -PageTransCompoundMap (pfn_to_page (pfn)) && +pfn_is_huge_mapped (vcpu->kvm, gfn, pfn) && !mmu_gfn_lpage_is_disallowed (vcpu, gfn,PT_DIRECTORY_LEVEL )) {unsigned long mask;arch/x86/kvm/mmu.c +1
-1/* @@ -5678,7 +5708,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm*kvm, */ if (sp->role.direct && !kvm_is_reserved_pfn (pfn) && -PageTransCompoundMap (pfn_to_page (pfn))) { +pfn_is_huge_mapped (kvm, sp->gfn, pfn)) {pte_list_remove (rmap_head, sptep); need_tlb_flush =1 ;Quoted 2 lines
goto restart;
This looks surprisingly simple to me :)
--
Thanks,
David / dhildenb
Quoted 2 lines · On 2018-11-13 at 05:02 Pankaj Gupta <[email protected]…
As this patch is dependent on PageReserved patch(which is in progress), just wondering if we are able to test the code path for hugepage with DAX.
For testing, I used the following patch. It's not 100%, since it intercepts at kvm_is_reserved_pfn(), and not PageReserved() directly. The only difference is with kvm_set_pfn_dirty() I think.
I also have a nasty module that would dump the EPT's and the host page table's mappings so I could confirm that the huge pages are being mapped correctly.
-----------------------
virt/kvm/kvm_main.c +4 -0
@@ -148,6 +148,10 @@ __weak int kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,bool kvm_is_reserved_pfn (kvm_pfn_t pfn) { +// XXX hack +if (is_zone_device_page (pfn_to_page (pfn))) +return false; +if (pfn_valid (pfn))return PageReserved (pfn_to_page (pfn));
-----------------------
Thanks,
Barret
Quoted 9 lines
Quoted 4 lines
As this patch is dependent on PageReserved patch(which is in progress), just
wondering if we are able to test the code path for hugepage with DAX.For testing, I used the following patch. It's not 100%, since it intercepts at
kvm_is_reserved_pfn(), and notPageReserved()directly. The only difference is withkvm_set_pfn_dirty()I think.
Yes, this should be ok.
Thanks,
Pankaj
Quoted 28 lines
I also have a nasty module that would dump the EPT's and the host page table's mappings so I could confirm that the huge pages are being mapped correctly.
-----------------------
virt/kvm/kvm_main.c +4
-1@@ -148,6 +148,10 @@ __weak int kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm, bool kvm_is_reserved_pfn(kvm_pfn_t pfn) { + // XXX hack + if (is_zone_device_page(pfn_to_page(pfn))) + return false; + if (pfn_valid(pfn)) return PageReserved(pfn_to_page(pfn)); -----------------------Thanks,
Barret
Quoted 6 lines · On 2018-11-13 at 10:36 David Hildenbrand…
Quoted 3 lines
Note that KVM already faulted in the page (or huge page) in the host's page table, and we hold the KVM mmu spinlock (grabbed before checking the mmu seq).
I wonder if the KVM mmu spinlock is enough for walking (not KVM exclusive) host page tables. Can you elaborate?
I'll update the commit message with the info from Paolo's email (about kvm_mmu_notifier_invalidate_range_end()).
Thanks,
Barret
v2 cover kvm: Use huge pages for DAX-backed files
In reply to Barret RhodenThis patch series depends on dax pages not being PageReserved. Once that is in place, these changes will let KVM use huge pages with dax-backed files. Without the PageReserved change, KVM and DAX still work with these patches, simply without huge pages - which is the current situation.
RFC/discussion thread:
https://lore.kernel.org/lkml/20181029210716.212159-1-brho-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org/
v1 -> v2:
https://lore.kernel.org/lkml/20181109203921.178363-1-brho-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org/
- Updated Acks/Reviewed-by
- Minor touchups
- Added patch to remove redundant PageReserved() check
- Rebased onto linux-next
Barret Rhoden (3):
mm: make dev_pagemap_mapping_shift() externally visible
kvm: Use huge pages for DAX-backed files
kvm: remove redundant PageReserved() check
arch/x86/kvm/mmu.c | 33 +++++++++++++++++++++++++++++++-- include/linux/mm.h | 3 +++ mm/memory-failure.c | 38 +++----------------------------------- mm/util.c | 34 ++++++++++++++++++++++++++++++++++ virt/kvm/kvm_main.c | 8 ++------ 5 files changed, 73 insertions(+), 43 deletions(-)
Signature · 1 line
2.19.1.1215.g8438c0b245-goog
PATCH v2 1/3 mm: make dev_pagemap_mapping_shift() externally visible
KVM has a use case for determining the size of a dax mapping. The KVM code has easy access to the address and the mm; hence the change in parameters.
--- include/linux/mm.h | 3 +++ mm/memory-failure.c | 38 +++----------------------------------- mm/util.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 35 deletions(-)
include/linux/mm.h +3 -0
@@ -935,6 +935,9 @@ static inline bool is_pci_p2pdma_page(const struct page *page) }#endif /* CONFIG_DEV_PAGEMAP_OPS */ +unsigned long dev_pagemap_mapping_shift (unsigned long address, +struct mm_struct *mm); +static inline void get_page (struct page *page) { page =compound_head (page);
mm/memory-failure.c +3 -35
@@ -265,40 +265,6 @@ void shake_page(struct page *p, int access) }EXPORT_SYMBOL_GPL (shake_page); -static unsigned long dev_pagemap_mapping_shift (struct page *page, -struct vm_area_struct *vma) -{ -unsigned long address =vma_address (page, vma); -pgd_t *pgd; -p4d_t *p4d; -pud_t *pud; -pmd_t *pmd; -pte_t *pte; - - pgd =pgd_offset (vma->vm_mm, address); -if (!pgd_present (*pgd)) -return 0 ; - p4d =p4d_offset (pgd, address); -if (!p4d_present (*p4d)) -return 0 ; - pud =pud_offset (p4d, address); -if (!pud_present (*pud)) -return 0 ; -if (pud_devmap (*pud)) -return PUD_SHIFT ; - pmd =pmd_offset (pud, address); -if (!pmd_present (*pmd)) -return 0 ; -if (pmd_devmap (*pmd)) -return PMD_SHIFT ; - pte =pte_offset_map (pmd, address); -if (!pte_present (*pte)) -return 0 ; -if (pte_devmap (*pte)) -return PAGE_SHIFT ; -return 0 ; -} -/* * Failure handling: if we can't find or can't kill a process there's * not much we can do. We just print a message and ignore otherwise.
@@ -329,7 +295,9 @@ static void add_to_kill(struct task_struct *tsk, struct page *p, tk->addr =page_address_in_vma (p, vma); tk->addr_valid =1 ;if (is_zone_device_page (p)) - tk->size_shift =dev_pagemap_mapping_shift (p, vma); + tk->size_shift = +dev_pagemap_mapping_shift (vma_address (page, vma), + vma->vm_mm);else tk->size_shift =compound_order (compound_head (p)) +PAGE_SHIFT ;
mm/util.c +34 -0
@@ -780,3 +780,37 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) out:return res; } + +unsigned long dev_pagemap_mapping_shift (unsigned long address, +struct mm_struct *mm) +{ +pgd_t *pgd; +p4d_t *p4d; +pud_t *pud; +pmd_t *pmd; +pte_t *pte; + + pgd =pgd_offset (mm, address); +if (!pgd_present (*pgd)) +return 0 ; + p4d =p4d_offset (pgd, address); +if (!p4d_present (*p4d)) +return 0 ; + pud =pud_offset (p4d, address); +if (!pud_present (*pud)) +return 0 ; +if (pud_devmap (*pud)) +return PUD_SHIFT ; + pmd =pmd_offset (pud, address); +if (!pmd_present (*pmd)) +return 0 ; +if (pmd_devmap (*pmd)) +return PMD_SHIFT ; + pte =pte_offset_map (pmd, address); +if (!pte_present (*pte)) +return 0 ; +if (pte_devmap (*pte)) +return PAGE_SHIFT ; +return 0 ; +} +EXPORT_SYMBOL_GPL (dev_pagemap_mapping_shift);
Signature · 1 line
2.19.1.1215.g8438c0b245-goog
Paolo Bonzini
maintainerRe: [PATCH v2 1/3] mm: make dev_pagemap_mapping_shift() externally visible
Quoted 115 lines · Barret Rhoden
KVM has a use case for determining the size of a dax mapping. The KVM code has easy access to the address and the mm; hence the change in parameters.
Signed-off-by Barret Rhoden <[email protected]>Reviewed-by David Hildenbrand <[email protected]>--- include/linux/mm.h | 3 +++ mm/memory-failure.c | 38 +++----------------------------------- mm/util.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 35 deletions(-)include/linux/mm.h +3
-0@@ -935,6 +935,9 @@ static inline bool is_pci_p2pdma_page(const struct page *page) }#endif /* CONFIG_DEV_PAGEMAP_OPS */ +unsigned long dev_pagemap_mapping_shift (unsigned long address, +struct mm_struct *mm); +static inline void get_page (struct page *page) { page =compound_head (page);mm/memory-failure.c +3
-35@@ -265,40 +265,6 @@ void shake_page(struct page *p, int access) }EXPORT_SYMBOL_GPL (shake_page); -static unsigned long dev_pagemap_mapping_shift (struct page *page, -struct vm_area_struct *vma) -{ -unsigned long address =vma_address (page, vma); -pgd_t *pgd; -p4d_t *p4d; -pud_t *pud; -pmd_t *pmd; -pte_t *pte; - - pgd =pgd_offset (vma->vm_mm, address); -if (!pgd_present (*pgd)) -return 0 ; - p4d =p4d_offset (pgd, address); -if (!p4d_present (*p4d)) -return 0 ; - pud =pud_offset (p4d, address); -if (!pud_present (*pud)) -return 0 ; -if (pud_devmap (*pud)) -return PUD_SHIFT ; - pmd =pmd_offset (pud, address); -if (!pmd_present (*pmd)) -return 0 ; -if (pmd_devmap (*pmd)) -return PMD_SHIFT ; - pte =pte_offset_map (pmd, address); -if (!pte_present (*pte)) -return 0 ; -if (pte_devmap (*pte)) -return PAGE_SHIFT ; -return 0 ; -} -/* * Failure handling: if we can't find or can't kill a process there's * not much we can do. We just print a message and ignore otherwise. @@ -329,7 +295,9 @@ static void add_to_kill(struct task_struct *tsk, struct page *p, tk->addr =page_address_in_vma (p, vma); tk->addr_valid =1 ;if (is_zone_device_page (p)) - tk->size_shift =dev_pagemap_mapping_shift (p, vma); + tk->size_shift = +dev_pagemap_mapping_shift (vma_address (page, vma), + vma->vm_mm);else tk->size_shift =compound_order (compound_head (p)) +PAGE_SHIFT ;mm/util.c +24
-0@@ -780,3 +780,37 @@ int get_cmdline(struct task_struct *task, char *buffer, int buflen) out:return res; } + +unsigned long dev_pagemap_mapping_shift (unsigned long address, +struct mm_struct *mm) +{ +pgd_t *pgd; +p4d_t *p4d; +pud_t *pud; +pmd_t *pmd; +pte_t *pte; + + pgd =pgd_offset (mm, address); +if (!pgd_present (*pgd)) +return 0 ; + p4d =p4d_offset (pgd, address); +if (!p4d_present (*p4d)) +return 0 ; + pud =pud_offset (p4d, address); +if (!pud_present (*pud)) +return 0 ; +if (pud_devmap (*pud)) +return PUD_SHIFT ; + pmd =pmd_offset (pud, address); +if (!pmd_present (*pmd)) +return 0 ;
mm/util.c int get_cmdline(struct task_struct *task, char *buffer, int buflen) · line 816
Quoted 10 lines
mm/util.c +10
-0+if (pmd_devmap (*pmd)) +return PMD_SHIFT ; + pte =pte_offset_map (pmd, address); +if (!pte_present (*pte)) +return 0 ; +if (pte_devmap (*pte)) +return PAGE_SHIFT ; +return 0 ; +} +EXPORT_SYMBOL_GPL (dev_pagemap_mapping_shift);
Andrew,
can you ack this patch?
Thanks,
Paolo
Re: [PATCH v2 1/3] mm: make dev_pagemap_mapping_shift() externally visible
In reply to Barret RhodenQuoted 7 lines · Barret Rhoden
KVM has a use case for determining the size of a dax mapping. The KVM code has easy access to the address and the mm; hence the change in parameters.
Signed-off-by Barret Rhoden <[email protected]>Reviewed-by David Hildenbrand <[email protected]>
PATCH v2 2/3 kvm: Use huge pages for DAX-backed files
In reply to Barret RhodenThis change allows KVM to map DAX-backed files made of huge pages with huge mappings in the EPT/TDP.
DAX pages are not PageTransCompound. The existing check is trying to determine if the mapping for the pfn is a huge mapping or not. For non-DAX maps, e.g. hugetlbfs, that means checking PageTransCompound. For DAX, we can check the page table itself.
Note that KVM already faulted in the page (or huge page) in the host's page table, and we hold the KVM mmu spinlock. We grabbed that lock in kvm_mmu_notifier_invalidate_range_end, before checking the mmu seq.
---
- removed map_shift local variable
arch/x86/kvm/mmu.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-)
arch/x86/kvm/mmu.c +31 -2
@@ -3152,6 +3152,35 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)return -EFAULT ; } +static bool pfn_is_huge_mapped (struct kvm *kvm,gfn_t gfn,kvm_pfn_t pfn) +{ +struct page *page =pfn_to_page (pfn); +unsigned long hva; + +if (!is_zone_device_page (page)) +return PageTransCompoundMap (page); + +/* +* DAX pages do not use compound pages. The page should have already +* been mapped into the host-side page table during try_async_pf(), so +* we can check the page tables directly. +*/ + hva =gfn_to_hva (kvm, gfn); +if (kvm_is_error_hva (hva)) +return false; + +/* +* Our caller grabbed the KVM mmu_lock with a successful +* mmu_notifier_retry, so we're safe to walk the page table. +*/ +switch (dev_pagemap_mapping_shift (hva, current->mm)) { +case PMD_SHIFT : +case PUD_SIZE : +return true; + } +return false; +} +static void transparent_hugepage_adjust (struct kvm_vcpu *vcpu,gfn_t *gfnp,kvm_pfn_t *pfnp,int *levelp)
@@ -3168,7 +3197,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,*/ if (!is_error_noslot_pfn (pfn) && !kvm_is_reserved_pfn (pfn) && level ==PT_PAGE_TABLE_LEVEL && -PageTransCompoundMap (pfn_to_page (pfn)) && +pfn_is_huge_mapped (vcpu->kvm, gfn, pfn) && !mmu_gfn_lpage_is_disallowed (vcpu, gfn,PT_DIRECTORY_LEVEL )) {unsigned long mask;/*
@@ -5678,7 +5707,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,*/ if (sp->role.direct && !kvm_is_reserved_pfn (pfn) && -PageTransCompoundMap (pfn_to_page (pfn))) { +pfn_is_huge_mapped (kvm, sp->gfn, pfn)) {pte_list_remove (rmap_head, sptep); need_tlb_flush =1 ; goto restart;
Signature · 1 line
2.19.1.1215.g8438c0b245-goog
PATCH v2 3/3 kvm: remove redundant PageReserved() check
In reply to Barret Rhodenkvm_is_reserved_pfn() already checks PageReserved().
--- virt/kvm/kvm_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
virt/kvm/kvm_main.c +2 -6
@@ -1700,12 +1700,8 @@ EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty);void kvm_set_pfn_dirty (kvm_pfn_t pfn) { -if (!kvm_is_reserved_pfn (pfn)) { -struct page *page =pfn_to_page (pfn); - -if (!PageReserved (page)) -SetPageDirty (page); - } +if (!kvm_is_reserved_pfn (pfn)) +SetPageDirty (pfn_to_page (pfn)); }EXPORT_SYMBOL_GPL (kvm_set_pfn_dirty);
Signature · 1 line
2.19.1.1215.g8438c0b245-goog
Re: [PATCH v2 3/3] kvm: remove redundant PageReserved() check
Quoted 17 lines · Barret Rhoden
kvm_is_reserved_pfn()already checksPageReserved().Signed-off-by Barret Rhoden <[email protected]>--- virt/kvm/kvm_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)virt/kvm/kvm_main.c +0
-1@@ -1700,12 +1700,8 @@ EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty);void kvm_set_pfn_dirty (kvm_pfn_t pfn) { -if (!kvm_is_reserved_pfn (pfn)) {
virt/kvm/kvm_main.c EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); · line 1707
Quoted 10 lines
virt/kvm/kvm_main.c +2
-5-struct page *page =pfn_to_page (pfn); - -if (!PageReserved (page)) -SetPageDirty (page); - } +if (!kvm_is_reserved_pfn (pfn)) +SetPageDirty (pfn_to_page (pfn)); }EXPORT_SYMBOL_GPL (kvm_set_pfn_dirty);
Signature · 3 lines
Thanks, David / dhildenb
[ add Alex who is looking into removing PageReserved for DAX pages. ]
Quoted 34 lines · Barret Rhoden
This patch series depends on dax pages not being PageReserved. Once that is in place, these changes will let KVM use huge pages with dax-backed files. Without the PageReserved change, KVM and DAX still work with these patches, simply without huge pages - which is the current situation.
RFC/discussion thread:
https://lore.kernel.org/lkml/[email protected]/v1 -> v2:
https://lore.kernel.org/lkml/[email protected]/- Updated Acks/Reviewed-by
- Minor touchups
- Added patch to remove redundantPageReserved()check
- Rebased onto linux-nextBarret Rhoden (3):
mm: makedev_pagemap_mapping_shift()externally visible
kvm: Use huge pages for DAX-backed files
kvm: remove redundantPageReserved()checkarch/x86/kvm/mmu.c | 33 +++++++++++++++++++++++++++++++-- include/linux/mm.h | 3 +++ mm/memory-failure.c | 38 +++----------------------------------- mm/util.c | 34 ++++++++++++++++++++++++++++++++++ virt/kvm/kvm_main.c | 8 ++------ 5 files changed, 73 insertions(+), 43 deletions(-)--
2.19.1.1215.g8438c0b245-goog
Quoted 1 line · On 2018-11-14 at 16:55 Dan Williams <[email protected]> wrote:
[ add Alex who is looking into removing PageReserved for DAX pages. ]
Thanks. I can keep my eye out for his patches and repost once that's done.
Alternatively, if you all want to merge this before the PageReserved / DAX changes, then I can repost - just Ack/Review tags. It's harmless with the existing PageReserved behavior.
Thanks,
Barret
Quoted 35 lines · Barret Rhoden
Quoted 34 lines
This patch series depends on dax pages not being PageReserved. Once that is in place, these changes will let KVM use huge pages with dax-backed files. Without the PageReserved change, KVM and DAX still work with these patches, simply without huge pages - which is the current situation.
RFC/discussion thread:
https://lore.kernel.org/lkml/[email protected]/v1 -> v2:
https://lore.kernel.org/lkml/[email protected]/- Updated Acks/Reviewed-by
- Minor touchups
- Added patch to remove redundantPageReserved()check
- Rebased onto linux-nextBarret Rhoden (3):
mm: makedev_pagemap_mapping_shift()externally visible
kvm: Use huge pages for DAX-backed files
kvm: remove redundantPageReserved()checkarch/x86/kvm/mmu.c | 33 +++++++++++++++++++++++++++++++-- include/linux/mm.h | 3 +++ mm/memory-failure.c | 38 +++----------------------------------- mm/util.c | 34 ++++++++++++++++++++++++++++++++++ virt/kvm/kvm_main.c | 8 ++------ 5 files changed, 73 insertions(+), 43 deletions(-)--
2.19.1.1215.g8438c0b245-goog
Quoted 6 lines · Barret Rhoden
Quoted 1 line · On 2018-11-14 at 16:55 Dan Williams <dan.j.williams-ral2JQCrhuEAvxtiuMwx3w@publ…
[ add Alex who is looking into removing PageReserved for DAX pages. ]
Thanks. I can keep my eye out for his patches and repost once that's done.
Quoted 7 lines
Alternatively, if you all want to merge this before the PageReserved / DAX changes, then I can repost - just Ack/Review tags. It's harmless with the existing PageReserved behavior.
Thanks,
Barret
So the latest version of my generic memory init patches are up at:
To be honest I am not entirely convinced that dropping PageReserved is the right thing to do for DAX pages. I've been trying to work out a few different issues but not having much luck. It seems like the main issue is that the PageReserved bit is being used to indicate 2 different things in a few spots throughout the kernel.
The definition of the PG_reserved flag reads like it should apply to DAX pages:
PG_reserved is set for special pages, which can never be swapped out. Some of them might not even exist...
PageReserved essentially means you aren't supposed to be migrating or swapping the page. The problem here is that I believe this logic should apply to DAX pages and so in many cases it makes sense to leave the flag set for DAX pages. Otherwise you have to go through and start special casing all the spots where normal memory falls through and add a check to see if we have a DAX page.
The second use for the PG_reserved flag is to test for if you can pin the page or not. This I think is the reason why many are just assuming PageReserved == MMIO like KVM does. However this is a bad assumption to be making since the introduction of DAX, HMM, and P2PDMA allows MMIO memory to start doing different things like supporting pinning. I also believe it would be a bad reason to clear the flag for DAX pages.
Thanks.
- Alex