4.10-rc loadtest (even on x86, even without THPCache) fails with
"fork: Cannot allocate memory" or some such; and /proc/meminfo
shows PageTables growing.
rc1 removed the freeing of an unused preallocated pagetable after
do_fault_around() has called map_pages(): which is usually a good
optimization, so that the followup doesn't have to reallocate one;
but it's not sufficient to shift the freeing into alloc_set_pte(),
since there are failure cases (most commonly VM_FAULT_RETRY) which
never reach finish_fault().
Check and free it at the outer level in do_fault(), then we don't
need to worry in alloc_set_pte(), and can restore that to how it was
(I cannot find any reason to pte_free() under lock as it was doing).
And fix a separate pagetable leak, or crash, introduced by the same
change, that could only show up on some ppc64: why does do_set_pmd()'s
failure case attempt to withdraw a pagetable when it never deposited
one, at the same time overwriting (so leaking) the vmf->prealloc_pte?
Residue of an earlier implementation, perhaps? Delete it.
Fixes: 953c66c2b22a ("mm: THP page cache support for ppc64")
Signed-off-by: Hugh Dickins <hughd@google.com>
---
mm/memory.c | 47 ++++++++++++++++++++---------------------------
1 file changed, 20 insertions(+), 27 deletions(-)
@@ -3008,13 +3008,6 @@ static int do_set_pmd(struct vm_fault *vret=0;count_vm_event(THP_FILE_MAPPED);out:-/*-*Ifwearegoingtofallbacktoptemapping,doa-*withdrawwithpmdlockheld.-*/-if(arch_needs_pgtable_deposit()&&ret==VM_FAULT_FALLBACK)-vmf->prealloc_pte=pgtable_trans_huge_withdraw(vma->vm_mm,-vmf->pmd);spin_unlock(vmf->ptl);returnret;}
@@ -3055,20 +3048,18 @@ int alloc_set_pte(struct vm_fault *vmf,ret=do_set_pmd(vmf,page);if(ret!=VM_FAULT_FALLBACK)-gotofault_handled;+returnret;}if(!vmf->pte){ret=pte_alloc_one_map(vmf);if(ret)-gotofault_handled;+returnret;}/* Re-check under ptl */-if(unlikely(!pte_none(*vmf->pte))){-ret=VM_FAULT_NOPAGE;-gotofault_handled;-}+if(unlikely(!pte_none(*vmf->pte)))+returnVM_FAULT_NOPAGE;flush_icache_page(vma,page);entry=mk_pte(page,vma->vm_page_prot);
@@ -3088,15 +3079,8 @@ int alloc_set_pte(struct vm_fault *vmf,/* no need to invalidate: a not-present page won't be cached */update_mmu_cache(vma,vmf->address,vmf->pte);-ret=0;-fault_handled:-/* preallocated pagetable is unused: free it */-if(vmf->prealloc_pte){-pte_free(vmf->vma->vm_mm,vmf->prealloc_pte);-vmf->prealloc_pte=0;-}-returnret;+return0;}
@@ -3360,15 +3344,24 @@ static int do_shared_fault(struct vm_faustaticintdo_fault(structvm_fault*vmf){structvm_area_struct*vma=vmf->vma;+intret;/* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */if(!vma->vm_ops->fault)-returnVM_FAULT_SIGBUS;-if(!(vmf->flags&FAULT_FLAG_WRITE))-returndo_read_fault(vmf);-if(!(vma->vm_flags&VM_SHARED))-returndo_cow_fault(vmf);-returndo_shared_fault(vmf);+ret=VM_FAULT_SIGBUS;+elseif(!(vmf->flags&FAULT_FLAG_WRITE))+ret=do_read_fault(vmf);+elseif(!(vma->vm_flags&VM_SHARED))+ret=do_cow_fault(vmf);+else+ret=do_shared_fault(vmf);++/* preallocated pagetable is unused: free it */+if(vmf->prealloc_pte){+pte_free(vma->vm_mm,vmf->prealloc_pte);+vmf->prealloc_pte=0;+}+returnret;}staticintnuma_migrate_prep(structpage*page,structvm_area_struct*vma,
4.10-rc loadtest (even on x86, even without THPCache) fails with
"fork: Cannot allocate memory" or some such; and /proc/meminfo
shows PageTables growing.
rc1 removed the freeing of an unused preallocated pagetable after
do_fault_around() has called map_pages(): which is usually a good
optimization, so that the followup doesn't have to reallocate one;
but it's not sufficient to shift the freeing into alloc_set_pte(),
since there are failure cases (most commonly VM_FAULT_RETRY) which
never reach finish_fault().
Check and free it at the outer level in do_fault(), then we don't
need to worry in alloc_set_pte(), and can restore that to how it was
(I cannot find any reason to pte_free() under lock as it was doing).
And fix a separate pagetable leak, or crash, introduced by the same
change, that could only show up on some ppc64: why does do_set_pmd()'s
failure case attempt to withdraw a pagetable when it never deposited
one, at the same time overwriting (so leaking) the vmf->prealloc_pte?
Residue of an earlier implementation, perhaps? Delete it.
@@ -3008,13 +3008,6 @@ static int do_set_pmd(struct vm_fault *vret=0;count_vm_event(THP_FILE_MAPPED);out:-/*-*Ifwearegoingtofallbacktoptemapping,doa-*withdrawwithpmdlockheld.-*/-if(arch_needs_pgtable_deposit()&&ret==VM_FAULT_FALLBACK)-vmf->prealloc_pte=pgtable_trans_huge_withdraw(vma->vm_mm,-vmf->pmd);spin_unlock(vmf->ptl);returnret;}
@@ -3055,20 +3048,18 @@ int alloc_set_pte(struct vm_fault *vmf,ret=do_set_pmd(vmf,page);if(ret!=VM_FAULT_FALLBACK)-gotofault_handled;+returnret;}if(!vmf->pte){ret=pte_alloc_one_map(vmf);if(ret)-gotofault_handled;+returnret;}/* Re-check under ptl */-if(unlikely(!pte_none(*vmf->pte))){-ret=VM_FAULT_NOPAGE;-gotofault_handled;-}+if(unlikely(!pte_none(*vmf->pte)))+returnVM_FAULT_NOPAGE;flush_icache_page(vma,page);entry=mk_pte(page,vma->vm_page_prot);
@@ -3088,15 +3079,8 @@ int alloc_set_pte(struct vm_fault *vmf,/* no need to invalidate: a not-present page won't be cached */update_mmu_cache(vma,vmf->address,vmf->pte);-ret=0;-fault_handled:-/* preallocated pagetable is unused: free it */-if(vmf->prealloc_pte){-pte_free(vmf->vma->vm_mm,vmf->prealloc_pte);-vmf->prealloc_pte=0;-}-returnret;+return0;}
@@ -3360,15 +3344,24 @@ static int do_shared_fault(struct vm_faustaticintdo_fault(structvm_fault*vmf){structvm_area_struct*vma=vmf->vma;+intret;/* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */if(!vma->vm_ops->fault)-returnVM_FAULT_SIGBUS;-if(!(vmf->flags&FAULT_FLAG_WRITE))-returndo_read_fault(vmf);-if(!(vma->vm_flags&VM_SHARED))-returndo_cow_fault(vmf);-returndo_shared_fault(vmf);+ret=VM_FAULT_SIGBUS;+elseif(!(vmf->flags&FAULT_FLAG_WRITE))+ret=do_read_fault(vmf);+elseif(!(vma->vm_flags&VM_SHARED))+ret=do_cow_fault(vmf);+else+ret=do_shared_fault(vmf);++/* preallocated pagetable is unused: free it */+if(vmf->prealloc_pte){+pte_free(vma->vm_mm,vmf->prealloc_pte);+vmf->prealloc_pte=0;+}+returnret;}staticintnuma_migrate_prep(structpage*page,structvm_area_struct*vma,
And fix a separate pagetable leak, or crash, introduced by the same
change, that could only show up on some ppc64: why does do_set_pmd()'s
failure case attempt to withdraw a pagetable when it never deposited
one, at the same time overwriting (so leaking) the vmf->prealloc_pte?
Residue of an earlier implementation, perhaps? Delete it.
Ah, so it is, I hadn't looked there. That's reassuring,
I'm glad to know you reached the same conclusion on that piece of code.
It still worried me that the fix is languishing in mmotm, but it looks
not lost: akpm would have sent it in a couple of days anyway, and only
affected ppc64 (like the related khugepaged patch you have queued there).
quoted
Fixes: 953c66c2b22a ("mm: THP page cache support for ppc64")
Signed-off-by: Hugh Dickins <hughd@google.com>
Reviewed-by: Aneesh Kumar K.V <redacted>
Thanks, and to Linus, who already has this in for -rc3: so akpm can drop
mm-thp-pagecache-only-withdraw-page-table-after-a-successful-deposit.patch
and then later send in your
mm-thp-pagecache-collapse-free-the-pte-page-table-on-collapse-for-thp-page-cache.patch
Hugh
From: Kirill A. Shutemov <hidden> Date: 2017-01-08 23:29:10
On Sat, Jan 07, 2017 at 03:37:31PM -0800, Hugh Dickins wrote:
4.10-rc loadtest (even on x86, even without THPCache) fails with
"fork: Cannot allocate memory" or some such; and /proc/meminfo
shows PageTables growing.
rc1 removed the freeing of an unused preallocated pagetable after
do_fault_around() has called map_pages(): which is usually a good
optimization, so that the followup doesn't have to reallocate one;
but it's not sufficient to shift the freeing into alloc_set_pte(),
since there are failure cases (most commonly VM_FAULT_RETRY) which
never reach finish_fault().
Check and free it at the outer level in do_fault(), then we don't
need to worry in alloc_set_pte(), and can restore that to how it was
(I cannot find any reason to pte_free() under lock as it was doing).
And fix a separate pagetable leak, or crash, introduced by the same
change, that could only show up on some ppc64: why does do_set_pmd()'s
failure case attempt to withdraw a pagetable when it never deposited
one, at the same time overwriting (so leaking) the vmf->prealloc_pte?
Residue of an earlier implementation, perhaps? Delete it.
Fixes: 953c66c2b22a ("mm: THP page cache support for ppc64")
Signed-off-by: Hugh Dickins <hughd@google.com>
Sorry, that I missed this initially.
Acked-by: Kirill A. Shutemov <redacted>
--
Kirill A. Shutemov