From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:32:48
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Subject: mm: introduce and use mapping_empty()
Patch series "Remove nrexceptional tracking", v2.
We actually use nrexceptional for very little these days. It's a minor
pain to keep in sync with nrpages, but the pain becomes much bigger with
the THP patches because we don't know how many indices a shadow entry
occupies. It's easier to just remove it than keep it accurate.
Also, we save 8 bytes per inode which is nothing to sneeze at; on my
laptop, it would improve shmem_inode_cache from 22 to 23 objects per
16kB, and inode_cache from 26 to 27 objects. Combined, that saves
a megabyte of memory from a combined usage of 25MB for both caches.
Unfortunately, ext4 doesn't cross a magic boundary, so it doesn't save
any memory for ext4.
This patch (of 4):
Instead of checking the two counters (nrpages and nrexceptional), we can
just check whether i_pages is empty.
Link: https://lkml.kernel.org/r/20201026151849.24232-1-willy@infradead.org
Link: https://lkml.kernel.org/r/20201026151849.24232-2-willy@infradead.org
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Tested-by: Vishal Verma <vishal.l.verma@intel.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/block_dev.c | 2 +-
fs/dax.c | 2 +-
fs/gfs2/glock.c | 3 +--
include/linux/pagemap.h | 5 +++++
mm/truncate.c | 18 +++---------------
5 files changed, 11 insertions(+), 19 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:32:51
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Subject: mm: stop accounting shadow entries
We no longer need to keep track of how many shadow entries are present in
a mapping. This saves a few writes to the inode and memory barriers.
Link: https://lkml.kernel.org/r/20201026151849.24232-3-willy@infradead.org
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Tested-by: Vishal Verma <vishal.l.verma@intel.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/filemap.c | 13 -------------
mm/swap_state.c | 4 ----
mm/truncate.c | 1 -
mm/workingset.c | 1 -
4 files changed, 19 deletions(-)
@@ -142,17 +142,6 @@ static void page_cache_delete(struct addpage->mapping=NULL;/* Leave page->index set: truncation lookup relies upon it */--if(shadow){-mapping->nrexceptional+=nr;-/*-*Makesurethenrexceptionalupdateiscommittedbefore-*thenrpagesupdatesothatfinaltruncateracing-*withreclaimdoesnotseebothcounters0atthe-*sametimeandmissashadowentry.-*/-smp_wmb();-}mapping->nrpages-=nr;}
@@ -925,8 +914,6 @@ noinline int __add_to_page_cache_locked(if(xas_error(&xas))gotounlock;-if(old)-mapping->nrexceptional--;mapping->nrpages++;/* hugetlb pages do not participate in page cache accounting */---a/mm/swap_state.c~mm-stop-accounting-shadow-entries+++a/mm/swap_state.c
@@ -132,7 +132,6 @@ int add_to_swap_cache(struct page *page,xas_store(&xas,page);xas_next(&xas);}-address_space->nrexceptional-=nr_shadows;address_space->nrpages+=nr;__mod_node_page_state(page_pgdat(page),NR_FILE_PAGES,nr);__mod_lruvec_page_state(page,NR_SWAPCACHE,nr);
@@ -275,7 +272,6 @@ void clear_shadow_from_swap_cache(int tyxas_store(&xas,NULL);nr_shadows++;}-address_space->nrexceptional-=nr_shadows;xa_unlock_irq(&address_space->i_pages);/* search the next swapcache until we meet end */---a/mm/truncate.c~mm-stop-accounting-shadow-entries+++a/mm/truncate.c
@@ -661,7 +661,7 @@ static int __dax_invalidate_entry(structgotoout;dax_disassociate_entry(entry,mapping,trunc);xas_store(&xas,NULL);-mapping->nrexceptional--;+mapping->nrpages-=1UL<<dax_entry_order(entry);ret=1;out:put_unlocked_entry(&xas,entry);---a/mm/filemap.c~dax-account-dax-entries-as-nrpages+++a/mm/filemap.c
@@ -618,9 +618,6 @@ EXPORT_SYMBOL(filemap_fdatawait_keep_err/* Returns true if writeback might be needed or already in progress. */staticboolmapping_needs_writeback(structaddress_space*mapping){-if(dax_mapping(mapping))-returnmapping->nrexceptional;-returnmapping->nrpages;}
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:00
From: Hugh Dickins <hughd@google.com>
Subject: mm: remove nrexceptional from inode: remove BUG_ON
clear_inode()'s BUG_ON(!mapping_empty(&inode->i_data)) is unsafe: we know
of two ways in which nodes can and do (on rare occasions) get left behind.
Until those are fixed, do not BUG_ON() nor even WARN_ON(). Yes, this
will then leak those nodes (or the next user of the struct inode may use
them); but this has been happening for years, and the new
BUG_ON(!mapping_empty) was only guilty of revealing that. A proper fix
will follow, but no hurry.
Link: https://lkml.kernel.org/r/alpine.LSU.2.11.2104292229380.16080@eggly.anvils
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/inode.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:04
From: Peter Xu <peterx@redhat.com>
Subject: hugetlb: pass vma into huge_pte_alloc() and huge_pmd_share()
Patch series "hugetlb: Disable huge pmd unshare for uffd-wp", v4.
This series tries to disable huge pmd unshare of hugetlbfs backed memory
for uffd-wp. Although uffd-wp of hugetlbfs is still during rfc stage, the
idea of this series may be needed for multiple tasks (Axel's uffd minor
fault series, and Mike's soft dirty series), so I picked it out from the
larger series.
This patch (of 4):
It is a preparation work to be able to behave differently in the per
architecture huge_pte_alloc() according to different VMA attributes.
Pass it deeper into huge_pmd_share() so that we can avoid the find_vma() call.
[peterx@redhat.com: build fix]
Link: https://lkml.kernel.org/r/20210304164653.GB397383@xz-x1Link: https://lkml.kernel.org/r/20210218230633.15028-1-peterx@redhat.com
Link: https://lkml.kernel.org/r/20210218230633.15028-2-peterx@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
Suggested-by: Mike Kravetz <redacted>
Cc: Adam Ruprecht <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Cannon Matthews <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Kirill A. Shutemov <redacted>
Cc: Lokesh Gidra <redacted>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mike Rapoport <redacted>
Cc: Mina Almasry <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oliver Upton <redacted>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
arch/arm64/mm/hugetlbpage.c | 4 ++--
arch/ia64/mm/hugetlbpage.c | 3 ++-
arch/mips/mm/hugetlbpage.c | 4 ++--
arch/parisc/mm/hugetlbpage.c | 2 +-
arch/powerpc/mm/hugetlbpage.c | 3 ++-
arch/s390/mm/hugetlbpage.c | 2 +-
arch/sh/mm/hugetlbpage.c | 2 +-
arch/sparc/mm/hugetlbpage.c | 2 +-
include/linux/hugetlb.h | 5 +++--
mm/hugetlb.c | 15 ++++++++-------
mm/userfaultfd.c | 2 +-
11 files changed, 24 insertions(+), 20 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:08
From: Peter Xu <peterx@redhat.com>
Subject: hugetlb/userfaultfd: forbid huge pmd sharing when uffd enabled
Huge pmd sharing could bring problem to userfaultfd. The thing is that
userfaultfd is running its logic based on the special bits on page table
entries, however the huge pmd sharing could potentially share page table
entries for different address ranges. That could cause issues on either:
- When sharing huge pmd page tables for an uffd write protected range, the
newly mapped huge pmd range will also be write protected unexpectedly, or,
- When we try to write protect a range of huge pmd shared range, we'll first
do huge_pmd_unshare() in hugetlb_change_protection(), however that also
means the UFFDIO_WRITEPROTECT could be silently skipped for the shared
region, which could lead to data loss.
Since at it, a few other things are done altogether:
- Move want_pmd_share() from mm/hugetlb.c into linux/hugetlb.h, because
that's definitely something that arch code would like to use too
- ARM64 currently directly check against CONFIG_ARCH_WANT_HUGE_PMD_SHARE when
trying to share huge pmd. Switch to the want_pmd_share() helper.
Since at it, move vma_shareable() from huge_pmd_share() into want_pmd_share().
[peterx@redhat.com: fix build with !ARCH_WANT_HUGE_PMD_SHARE]
Link: https://lkml.kernel.org/r/20210310185359.88297-1-peterx@redhat.com
Link: https://lkml.kernel.org/r/20210218231202.15426-1-peterx@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Mike Kravetz <redacted>
Reviewed-by: Axel Rasmussen <axelrasmussen@google.com>
Tested-by: Naresh Kamboju <redacted>
Cc: Adam Ruprecht <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Cannon Matthews <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Kirill A. Shutemov <redacted>
Cc: Lokesh Gidra <redacted>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mike Rapoport <redacted>
Cc: Mina Almasry <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oliver Upton <redacted>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
arch/arm64/mm/hugetlbpage.c | 3 +--
include/linux/hugetlb.h | 2 ++
include/linux/userfaultfd_k.h | 9 +++++++++
mm/hugetlb.c | 22 ++++++++++++++++------
4 files changed, 28 insertions(+), 8 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:17
From: Peter Xu <peterx@redhat.com>
Subject: hugetlb/userfaultfd: unshare all pmds for hugetlbfs when register wp
Huge pmd sharing for hugetlbfs is racy with userfaultfd-wp because
userfaultfd-wp is always based on pgtable entries, so they cannot be
shared.
Walk the hugetlb range and unshare all such mappings if there is, right
before UFFDIO_REGISTER will succeed and return to userspace.
This will pair with want_pmd_share() in hugetlb code so that huge pmd
sharing is completely disabled for userfaultfd-wp registered range.
Link: https://lkml.kernel.org/r/20210218231206.15524-1-peterx@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Mike Kravetz <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: Andrea Arcangeli <redacted>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Mike Rapoport <redacted>
Cc: Kirill A. Shutemov <redacted>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Adam Ruprecht <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Cannon Matthews <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Lokesh Gidra <redacted>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mina Almasry <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oliver Upton <redacted>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/userfaultfd.c | 4 ++
include/linux/hugetlb.h | 3 ++
mm/hugetlb.c | 51 ++++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:20
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugetlb: remove redundant reservation check condition in alloc_huge_page()
vma_resv_map(vma) checks if a reserve map is associated with the vma. The
routine vma_needs_reservation() will check vma_resv_map(vma) and return 1
if no reserv map is present. map_chg is set to the return value of
vma_needs_reservation(). Therefore, !vma_resv_map(vma) is redundant in
the expression:
map_chg || avoid_reserve || !vma_resv_map(vma);
Remove the redundant check.
[Thanks Mike Kravetz for reshaping this commit message!]
Link: https://lkml.kernel.org/r/20210301104726.45159-1-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -2316,7 +2316,7 @@ struct page *alloc_huge_page(struct vm_a/* If this allocation is not consuming a reservation, charge it now.*/-deferred_reserve=map_chg||avoid_reserve||!vma_resv_map(vma);+deferred_reserve=map_chg||avoid_reserve;if(deferred_reserve){ret=hugetlb_cgroup_charge_cgroup_rsvd(idx,pages_per_huge_page(h),&h_cg);
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:23
From: Anshuman Khandual <redacted>
Subject: mm: generalize HUGETLB_PAGE_SIZE_VARIABLE
HUGETLB_PAGE_SIZE_VARIABLE need not be defined for each individual
platform subscribing it. Instead just make it generic.
Link: https://lkml.kernel.org/r/1614914928-22039-1-git-send-email-anshuman.khandual@arm.com
Signed-off-by: Anshuman Khandual <redacted>
Suggested-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Michael Ellerman <mpe@ellerman.id.au> [powerpc]
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <redacted>
Cc: Christophe Leroy <redacted>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
arch/ia64/Kconfig | 6 +-----
arch/powerpc/Kconfig | 6 +-----
mm/Kconfig | 7 +++++++
3 files changed, 9 insertions(+), 10 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:25
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugetlb: use some helper functions to cleanup code
Patch series "Some cleanups for hugetlb".
This series contains cleanups to remove unnecessary VM_BUG_ON_PAGE, use
helper function and so on. I also collect some previous patches into this
series in case they are forgotten.
This patch (of 5):
We could use pages_per_huge_page to get the number of pages per hugepage,
use get_hstate_idx to calculate hstate index, and use hstate_is_gigantic
to check if a hstate is gigantic to make code more succinct.
Link: https://lkml.kernel.org/r/20210308112809.26107-1-linmiaohe@huawei.com
Link: https://lkml.kernel.org/r/20210308112809.26107-2-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/hugetlbfs/inode.c | 2 +-
mm/hugetlb.c | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:31
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugetlb_cgroup: remove unnecessary VM_BUG_ON_PAGE in hugetlb_cgroup_migrate()
!PageHuge(oldhpage) is implicitly checked in page_hstate() above, so we
remove this explicit one.
Link: https://lkml.kernel.org/r/20210308112809.26107-4-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb_cgroup.c | 1 -
1 file changed, 1 deletion(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:33
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugetlb: optimize the surplus state transfer code in move_hugetlb_state()
We should not transfer the per-node surplus state when we do not cross the
node in order to save some cpu cycles
Link: https://lkml.kernel.org/r/20210308112809.26107-3-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 6 ++++++
1 file changed, 6 insertions(+)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:35
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugetlb: simplify the code when alloc_huge_page() failed in hugetlb_no_page()
Rework the error handling code when alloc_huge_page() failed to remove
some duplicated code and simplify the code slightly.
Link: https://lkml.kernel.org/r/20210308112809.26107-5-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:37
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugetlb: avoid calculating fault_mutex_hash in truncate_op case
The fault_mutex hashing overhead can be avoided in truncate_op case
because page faults can not race with truncation in this routine. So
calculate hash for fault_mutex only in !truncate_op case to save some cpu
cycles.
Link: https://lkml.kernel.org/r/20210308112809.26107-6-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/hugetlbfs/inode.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:40
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: khugepaged: remove unneeded return value of khugepaged_collapse_pte_mapped_thps()
Patch series "Cleanup and fixup for khugepaged", v2.
This series contains cleanups to remove unneeded return value, use helper
function and so on. And there is one fix to correct the wrong result
value for trace_mm_collapse_huge_page_isolate().
This patch (of 4):
The return value of khugepaged_collapse_pte_mapped_thps() is never checked
since it's introduced. We should remove such unneeded return value.
Link: https://lkml.kernel.org/r/20210306032947.35921-1-linmiaohe@huawei.com
Link: https://lkml.kernel.org/r/20210306032947.35921-2-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Acked-by: Kirill A. Shutemov <redacted>
Cc: Rik van Riel <redacted>
Cc: Ebru Akagunduz <redacted>
Cc: Dan Carpenter <redacted>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/khugepaged.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:43
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: khugepaged: reuse the smp_wmb() inside __SetPageUptodate()
smp_wmb() is needed to avoid the copy_huge_page writes to become visible
after the set_pmd_at() write here. But we can reuse the smp_wmb() inside
__SetPageUptodate() to remove this redundant one.
Link: https://lkml.kernel.org/r/20210306032947.35921-3-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Acked-by: Kirill A. Shutemov <redacted>
Cc: Dan Carpenter <redacted>
Cc: Ebru Akagunduz <redacted>
Cc: Mike Kravetz <redacted>
Cc: Rik van Riel <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/khugepaged.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:46
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: khugepaged: use helper khugepaged_test_exit() in __khugepaged_enter()
Commit 4d45e75a9955 ("mm: remove the now-unnecessary mmget_still_valid()
hack") have made khugepaged_test_exit() suitable for check mm->mm_users
against 0. Use this helper here.
Link: https://lkml.kernel.org/r/20210306032947.35921-4-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Acked-by: Kirill A. Shutemov <redacted>
Cc: Dan Carpenter <redacted>
Cc: Ebru Akagunduz <redacted>
Cc: Mike Kravetz <redacted>
Cc: Rik van Riel <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/khugepaged.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -481,7 +481,7 @@ int __khugepaged_enter(struct mm_structreturn-ENOMEM;/* __khugepaged_exit() must not run from under us */-VM_BUG_ON_MM(atomic_read(&mm->mm_users)==0,mm);+VM_BUG_ON_MM(khugepaged_test_exit(mm),mm);if(unlikely(test_and_set_bit(MMF_VM_HUGEPAGE,&mm->flags))){free_mm_slot(mm_slot);return0;
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:49
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: khugepaged: fix wrong result value for trace_mm_collapse_huge_page_isolate()
In writable and !referenced case, the result value should be
SCAN_LACK_REFERENCED_PAGE for trace_mm_collapse_huge_page_isolate()
instead of default 0 (SCAN_FAIL) here.
Link: https://lkml.kernel.org/r/20210306032947.35921-5-linmiaohe@huawei.com
Fixes: 7d2eba0557c1 ("mm: add tracepoint for scanning pages")
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Acked-by: Kirill A. Shutemov <redacted>
Cc: Dan Carpenter <redacted>
Cc: Ebru Akagunduz <redacted>
Cc: Mike Kravetz <redacted>
Cc: Rik van Riel <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/khugepaged.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:52
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/huge_memory.c: remove unnecessary local variable ret2
There is no need to use a new local variable ret2 to get the return value
of handle_userfault(). Use ret directly to make code more succinct.
Link: https://lkml.kernel.org/r/20210210072409.60587-1-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/huge_memory.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:55
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/huge_memory.c: rework the function vma_adjust_trans_huge()
Patch series "Some cleanups for huge_memory", v3.
This series contains cleanups to rework some function logics to make it
more readable, use helper function and so on. More details can be found
in the respective changelogs.
This patch (of 6):
The current implementation of vma_adjust_trans_huge() contains some
duplicated codes. Add helper function to get rid of these codes to make
it more succinct.
Link: https://lkml.kernel.org/r/20210318122722.13135-1-linmiaohe@huawei.com
Link: https://lkml.kernel.org/r/20210318122722.13135-2-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: William Kucharski <redacted>
Cc: Vlastimil Babka <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: yuleixzhang <redacted>
Cc: Michel Lespinasse <redacted>
Cc: Aneesh Kumar K.V <redacted>
Cc: Ralph Campbell <redacted>
Cc: Thomas Hellstrm (Intel) <redacted>
Cc: Yang Shi <redacted>
Cc: Wei Yang <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/huge_memory.c | 44 +++++++++++++++++++-------------------------
1 file changed, 19 insertions(+), 25 deletions(-)
@@ -2301,44 +2301,38 @@ void split_huge_pmd_address(struct vm_ar__split_huge_pmd(vma,pmd,address,freeze,page);}+staticinlinevoidsplit_huge_pmd_if_needed(structvm_area_struct*vma,unsignedlongaddress)+{+/*+*Ifthenewaddressisn'thpagealignedanditcouldpreviously+*containanhugepage:checkifweneedtosplitanhugepmd.+*/+if(!IS_ALIGNED(address,HPAGE_PMD_SIZE)&&+range_in_vma(vma,ALIGN_DOWN(address,HPAGE_PMD_SIZE),+ALIGN(address,HPAGE_PMD_SIZE)))+split_huge_pmd_address(vma,address,false,NULL);+}+voidvma_adjust_trans_huge(structvm_area_struct*vma,unsignedlongstart,unsignedlongend,longadjust_next){-/*-*Ifthenewstartaddressisn'thpagealignedanditcould-*previouslycontainanhugepage:checkifweneedtosplit-*anhugepmd.-*/-if(start&~HPAGE_PMD_MASK&&-(start&HPAGE_PMD_MASK)>=vma->vm_start&&-(start&HPAGE_PMD_MASK)+HPAGE_PMD_SIZE<=vma->vm_end)-split_huge_pmd_address(vma,start,false,NULL);+/* Check if we need to split start first. */+split_huge_pmd_if_needed(vma,start);-/*-*Ifthenewendaddressisn'thpagealignedanditcould-*previouslycontainanhugepage:checkifweneedtosplit-*anhugepmd.-*/-if(end&~HPAGE_PMD_MASK&&-(end&HPAGE_PMD_MASK)>=vma->vm_start&&-(end&HPAGE_PMD_MASK)+HPAGE_PMD_SIZE<=vma->vm_end)-split_huge_pmd_address(vma,end,false,NULL);+/* Check if we need to split end next. */+split_huge_pmd_if_needed(vma,end);/*-*Ifwe'realsoupdatingthevma->vm_next->vm_start,ifthenew-*vm_next->vm_startisn'thpagealignedanditcouldpreviously-*containanhugepage:checkifweneedtosplitanhugepmd.+*Ifwe'realsoupdatingthevma->vm_next->vm_start,+*checkifweneedtosplitit.*/if(adjust_next>0){structvm_area_struct*next=vma->vm_next;unsignedlongnstart=next->vm_start;nstart+=adjust_next;-if(nstart&~HPAGE_PMD_MASK&&-(nstart&HPAGE_PMD_MASK)>=next->vm_start&&-(nstart&HPAGE_PMD_MASK)+HPAGE_PMD_SIZE<=next->vm_end)-split_huge_pmd_address(next,nstart,false,NULL);+split_huge_pmd_if_needed(next,nstart);}}
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:33:58
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/huge_memory.c: make get_huge_zero_page() return bool
It's guaranteed that huge_zero_page will not be NULL if huge_zero_refcount
is increased successfully. When READ_ONCE(huge_zero_page) is returned,
there must be a huge_zero_page and it can be replaced with returning
'true' when we do not care about the value of huge_zero_page. We can thus
make it return bool to save READ_ONCE cpu cycles as the return value is
just used to check if huge_zero_page exists.
Link: https://lkml.kernel.org/r/20210318122722.13135-3-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Aneesh Kumar K.V <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Michel Lespinasse <redacted>
Cc: Ralph Campbell <redacted>
Cc: Thomas Hellstrm (Intel) <redacted>
Cc: Vlastimil Babka <redacted>
Cc: Wei Yang <redacted>
Cc: William Kucharski <redacted>
Cc: Yang Shi <redacted>
Cc: yuleixzhang <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/huge_memory.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
@@ -101,7 +101,7 @@ retry:/* We take additional reference here. It will be put back by shrinker */atomic_set(&huge_zero_refcount,2);preempt_enable();-returnREAD_ONCE(huge_zero_page);+returntrue;}staticvoidput_huge_zero_page(void)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:02
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/huge_memory.c: rework the function do_huge_pmd_numa_page() slightly
The current code that checks if migrating misplaced transhuge page is
needed is pretty hard to follow. Rework it and add a comment to make its
logic more clear and improve readability.
Link: https://lkml.kernel.org/r/20210318122722.13135-4-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Aneesh Kumar K.V <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Michel Lespinasse <redacted>
Cc: Ralph Campbell <redacted>
Cc: Thomas Hellstrm (Intel) <redacted>
Cc: Vlastimil Babka <redacted>
Cc: Wei Yang <redacted>
Cc: William Kucharski <redacted>
Cc: Yang Shi <redacted>
Cc: yuleixzhang <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/huge_memory.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
@@ -1462,12 +1462,6 @@ vm_fault_t do_huge_pmd_numa_page(struct*/page_locked=trylock_page(page);target_nid=mpol_misplaced(page,vma,haddr);-if(target_nid==NUMA_NO_NODE){-/* If the page was locked, there are no parallel migrations */-if(page_locked)-gotoclear_pmdnuma;-}-/* Migration could have started since the pmd_trans_migrating check */if(!page_locked){page_nid=NUMA_NO_NODE;
@@ -1476,6 +1470,11 @@ vm_fault_t do_huge_pmd_numa_page(structspin_unlock(vmf->ptl);put_and_wait_on_page_locked(page,TASK_UNINTERRUPTIBLE);gotoout;+}elseif(target_nid==NUMA_NO_NODE){+/* There are no parallel migrations and page is in the right+*node.Clearthenumahintinginfointhispmd.+*/+gotoclear_pmdnuma;}/*
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:06
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/huge_memory.c: remove redundant PageCompound() check
The !PageCompound() check limits the page must be head or tail while
!PageHead() further limits it to page head only. So !PageHead() check is
equivalent here.
Link: https://lkml.kernel.org/r/20210318122722.13135-5-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Aneesh Kumar K.V <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Michel Lespinasse <redacted>
Cc: Ralph Campbell <redacted>
Cc: Thomas Hellstrm (Intel) <redacted>
Cc: Vlastimil Babka <redacted>
Cc: Wei Yang <redacted>
Cc: William Kucharski <redacted>
Cc: Yang Shi <redacted>
Cc: yuleixzhang <redacted>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/huge_memory.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:12
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/huge_memory.c: use helper function migration_entry_to_page()
It's more recommended to use helper function migration_entry_to_page() to
get the page via migration entry. We can also enjoy the PageLocked()
check there.
Link: https://lkml.kernel.org/r/20210318122722.13135-7-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Aneesh Kumar K.V <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Michel Lespinasse <redacted>
Cc: Ralph Campbell <redacted>
Cc: Thomas Hellstrm (Intel) <redacted>
Cc: Vlastimil Babka <redacted>
Cc: Wei Yang <redacted>
Cc: William Kucharski <redacted>
Cc: Yang Shi <redacted>
Cc: yuleixzhang <redacted>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/huge_memory.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:14
From: Yanfei Xu <redacted>
Subject: mm/khugepaged.c: replace barrier() with READ_ONCE() for a selective variable
READ_ONCE() is more selective and lightweight. It is more appropriate
that using a READ_ONCE() for the certain variable to prevent the compiler
from reordering.
Link: https://lkml.kernel.org/r/20210323092730.247583-1-yanfei.xu@windriver.com
Signed-off-by: Yanfei Xu <redacted>
Acked-by: Kirill A. Shutemov <redacted>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/khugepaged.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:18
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: khugepaged: use helper function range_in_vma() in collapse_pte_mapped_thp()
Patch series "Cleanup for khugepaged".
This series contains cleanups to remove unnecessary out label and
meaningless !pte_present() check. Also use helper function to simplify
the code. More details can be found in the respective changelogs.
This patch (of 3):
We could use helper function range_in_vma() to check whether the desired
range is inside the vma to simplify the code.
Link: https://lkml.kernel.org/r/20210325135647.64106-1-linmiaohe@huawei.com
Link: https://lkml.kernel.org/r/20210325135647.64106-2-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/khugepaged.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:20
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: khugepaged: remove unnecessary out label in collapse_huge_page()
The out label here is unneeded because it just goes to out_up_write label.
Remove it to make code more concise.
Link: https://lkml.kernel.org/r/20210325135647.64106-3-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/khugepaged.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
@@ -1128,10 +1128,10 @@ static void collapse_huge_page(struct mmmmap_write_lock(mm);result=hugepage_vma_revalidate(mm,address,&vma);if(result)-gotoout;+gotoout_up_write;/* check if the pmd is still valid */if(mm_find_pmd(mm,address)!=pmd)-gotoout;+gotoout_up_write;anon_vma_lock_write(vma->anon_vma);
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:23
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: khugepaged: remove meaningless !pte_present() check in khugepaged_scan_pmd()
We know it must meet the !is_swap_pte() and !pte_none() condition if we
reach here. Since !is_swap_pte() indicates pte_none() or pte_present()
is met, it's guaranteed that pte must be present here.
Link: https://lkml.kernel.org/r/20210325135647.64106-4-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/khugepaged.c | 4 ----
1 file changed, 4 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:30
From: Zi Yan <ziy@nvidia.com>
Subject: mm: huge_memory: debugfs for file-backed THP split
Further extend <debugfs>/split_huge_pages to accept
"<path>,<pgoff_start>,<pgoff_end>" for file-backed THP split tests since
tmpfs may have file backed by THP that mapped nowhere.
Update selftest program to test file-backed THP split too.
Link: https://lkml.kernel.org/r/20210331235309.332292-2-zi.yan@sent.com
Signed-off-by: Zi Yan <ziy@nvidia.com>
Suggested-by: Kirill A. Shutemov <redacted>
Reviewed-by: Yang Shi <redacted>
Cc: "Kirill A . Shutemov" <redacted>
Cc: Shuah Khan <shuah@kernel.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Sandipan Das <redacted>
Cc: David Hildenbrand <redacted>
Cc: Mika Penttila <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/huge_memory.c | 90 +++++++++++-
tools/testing/selftests/vm/split_huge_page_test.c | 82 ++++++++++
2 files changed, 166 insertions(+), 6 deletions(-)
@@ -87,13 +92,16 @@ static int write_file(const char *path,return(unsignedint)numwritten;}-staticvoidwrite_debugfs(intpid,uint64_tvaddr_start,uint64_tvaddr_end)+staticvoidwrite_debugfs(constchar*fmt,...){charinput[INPUT_MAX];intret;+va_listargp;++va_start(argp,fmt);+ret=vsnprintf(input,INPUT_MAX,fmt,argp);+va_end(argp);-ret=snprintf(input,INPUT_MAX,"%d,0x%lx,0x%lx",pid,vaddr_start,-vaddr_end);if(ret>=INPUT_MAX){printf("%s: Debugfs input is too long\n",__func__);exit(EXIT_FAILURE);
@@ -183,7 +191,8 @@ void split_pmd_thp(void)}/* split all THPs */-write_debugfs(getpid(),(uint64_t)one_page,(uint64_t)one_page+len);+write_debugfs(PID_FMT,getpid(),(uint64_t)one_page,+(uint64_t)one_page+len);for(i=0;i<len;i++)if(one_page[i]!=(char)i){
@@ -274,7 +283,7 @@ void split_pte_mapped_thp(void)}/* split all remapped THPs */-write_debugfs(getpid(),(uint64_t)pte_mapped,+write_debugfs(PID_FMT,getpid(),(uint64_t)pte_mapped,(uint64_t)pte_mapped+pagesize*4);/* smap does not show THPs after mremap, use kpageflags instead */
@@ -300,6 +309,68 @@ void split_pte_mapped_thp(void)close(kpageflags_fd);}+voidsplit_file_backed_thp(void)+{+intstatus;+intfd;+ssize_tnum_written;+chartmpfs_template[]="/tmp/thp_split_XXXXXX";+constchar*tmpfs_loc=mkdtemp(tmpfs_template);+chartestfile[INPUT_MAX];+uint64_tpgoff_start=0,pgoff_end=1024;++printf("Please enable pr_debug in split_huge_pages_in_file() if you need more info.\n");++status=mount("tmpfs",tmpfs_loc,"tmpfs",0,"huge=always,size=4m");++if(status){+printf("Unable to create a tmpfs for testing\n");+exit(EXIT_FAILURE);+}++status=snprintf(testfile,INPUT_MAX,"%s/thp_file",tmpfs_loc);+if(status>=INPUT_MAX){+printf("Fail to create file-backed THP split testing file\n");+gotocleanup;+}++fd=open(testfile,O_CREAT|O_WRONLY);+if(fd==-1){+perror("Cannot open testing file\n");+gotocleanup;+}++/* write something to the file, so a file-backed THP can be allocated */+num_written=write(fd,tmpfs_loc,sizeof(tmpfs_loc));+close(fd);++if(num_written<1){+printf("Fail to write data to testing file\n");+gotocleanup;+}++/* split the file-backed THP */+write_debugfs(PATH_FMT,testfile,pgoff_start,pgoff_end);++status=unlink(testfile);+if(status)+perror("Cannot remove testing file\n");++cleanup:+status=umount(tmpfs_loc);+if(status){+printf("Unable to umount %s\n",tmpfs_loc);+exit(EXIT_FAILURE);+}+status=rmdir(tmpfs_loc);+if(status){+perror("cannot remove tmp dir");+exit(EXIT_FAILURE);+}++printf("file-backed THP split test done, please check dmesg for more information\n");+}+intmain(intargc,char**argv){if(geteuid()!=0){
@@ -313,6 +384,7 @@ int main(int argc, char **argv)split_pmd_thp();split_pte_mapped_thp();+split_file_backed_thp();return0;}
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:32
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugeltb: remove redundant VM_BUG_ON() in region_add()
Patch series "Cleanup and fixup for hugetlb", v2.
This series contains cleanups to remove redundant VM_BUG_ON() and simplify
the return code. Also this handles the error case in
hugetlb_fix_reserve_counts() correctly. More details can be found in the
respective changelogs.
This patch (of 5):
The same VM_BUG_ON() check is already done in the callee. Remove this
extra one to simplify the code slightly.
Link: https://lkml.kernel.org/r/20210410072348.20437-1-linmiaohe@huawei.com
Link: https://lkml.kernel.org/r/20210410072348.20437-2-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Mike Kravetz <redacted>
Cc: Feilong Lin <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 1 -
1 file changed, 1 deletion(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:35
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugeltb: simplify the return code of __vma_reservation_common()
It's guaranteed that the vma is associated with a resv_map, i.e. either
VM_MAYSHARE or HPAGE_RESV_OWNER, when the code reaches here or we would
have returned via !resv check above. So it's unneeded to check whether
HPAGE_RESV_OWNER is set here. Simplify the return code to make it more
clear.
Link: https://lkml.kernel.org/r/20210410072348.20437-3-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Feilong Lin <redacted>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 41 ++++++++++++++++++++---------------------
1 file changed, 20 insertions(+), 21 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:38
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugeltb: clarify (chg - freed) won't go negative in hugetlb_unreserve_pages()
The resv_map could be NULL since this routine can be called in the evict
inode path for all hugetlbfs inodes and we will have chg = 0 in this case.
But (chg - freed) won't go negative as Mike pointed out:
"If resv_map is NULL, then no hugetlb pages can be allocated/associated
with the file. As a result, remove_inode_hugepages will never find any
huge pages associated with the inode and the passed value 'freed' will
always be zero."
Add a comment clarifying this to make it clear and also avoid confusion.
Link: https://lkml.kernel.org/r/20210410072348.20437-4-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Feilong Lin <redacted>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 3 +++
1 file changed, 3 insertions(+)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:41
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugeltb: handle the error case in hugetlb_fix_reserve_counts()
A rare out of memory error would prevent removal of the reserve map region
for a page. hugetlb_fix_reserve_counts() handles this rare case to avoid
dangling with incorrect counts. Unfortunately, hugepage_subpool_get_pages
and hugetlb_acct_memory could possibly fail too. We should correctly
handle these cases.
Link: https://lkml.kernel.org/r/20210410072348.20437-5-linmiaohe@huawei.com
Fixes: b5cec28d36f5 ("hugetlbfs: truncate_hugepages() takes a range of pages")
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Feilong Lin <redacted>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:44
From: Miaohe Lin <linmiaohe@huawei.com>
Subject: mm/hugetlb: remove unused variable pseudo_vma in remove_inode_hugepages()
The local variable pseudo_vma is not used anymore.
Link: https://lkml.kernel.org/r/20210410072348.20437-6-linmiaohe@huawei.com
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Feilong Lin <redacted>
Cc: Mike Kravetz <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/hugetlbfs/inode.c | 3 ---
1 file changed, 3 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:48
From: Mike Kravetz <redacted>
Subject: mm/cma: change cma mutex to irq safe spinlock
Patch series "make hugetlb put_page safe for all calling contexts", v5.
This effort is the result a recent bug report [1]. Syzbot found a
potential deadlock in the hugetlb put_page/free_huge_page_path. WARNING:
SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected Since the
free_huge_page_path already has code to 'hand off' page free requests to a
workqueue, a suggestion was proposed to make the in_irq() detection
accurate by always enabling PREEMPT_COUNT [2]. The outcome of that
discussion was that the hugetlb put_page path (free_huge_page) path should
be properly fixed and safe for all calling contexts.
This patch (of 8):
cma_release is currently a sleepable operatation because the bitmap
manipulation is protected by cma->lock mutex. Hugetlb code which relies
on cma_release for CMA backed (giga) hugetlb pages, however, needs to be
irq safe.
The lock doesn't protect any sleepable operation so it can be changed to a
(irq aware) spin lock. The bitmap processing should be quite fast in
typical case but if cma sizes grow to TB then we will likely need to
replace the lock by a more optimized bitmap implementation.
Link: https://lkml.kernel.org/r/20210409205254.242291-1-mike.kravetz@oracle.com
Link: https://lkml.kernel.org/r/20210409205254.242291-2-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: David Hildenbrand <redacted>
Acked-by: Roman Gushchin <redacted>
Cc: Shakeel Butt <redacted>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Muchun Song <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: HORIGUCHI NAOYA <redacted>
Cc: "Aneesh Kumar K . V" <redacted>
Cc: Waiman Long <longman@redhat.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Mina Almasry <redacted>
Cc: Hillf Danton <redacted>
Cc: Joonsoo Kim <redacted>
Cc: Barry Song <redacted>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/cma.c | 18 +++++++++---------
mm/cma.h | 2 +-
mm/cma_debug.c | 8 ++++----
3 files changed, 14 insertions(+), 14 deletions(-)
@@ -36,10 +36,10 @@ static int cma_used_get(void *data, u64structcma*cma=data;unsignedlongused;-mutex_lock(&cma->lock);+spin_lock_irq(&cma->lock);/* pages counter is smaller than sizeof(int) */used=bitmap_weight(cma->bitmap,(int)cma_bitmap_maxno(cma));-mutex_unlock(&cma->lock);+spin_unlock_irq(&cma->lock);*val=(u64)used<<cma->order_per_bit;return0;
@@ -53,7 +53,7 @@ static int cma_maxchunk_get(void *data,unsignedlongstart,end=0;unsignedlongbitmap_maxno=cma_bitmap_maxno(cma);-mutex_lock(&cma->lock);+spin_lock_irq(&cma->lock);for(;;){start=find_next_zero_bit(cma->bitmap,bitmap_maxno,end);if(start>=bitmap_maxno)
@@ -61,7 +61,7 @@ static int cma_maxchunk_get(void *data,end=find_next_bit(cma->bitmap,bitmap_maxno,start);maxchunk=max(end-start,maxchunk);}-mutex_unlock(&cma->lock);+spin_unlock_irq(&cma->lock);*val=(u64)maxchunk<<cma->order_per_bit;return0;---a/mm/cma.h~mm-cma-change-cma-mutex-to-irq-safe-spinlock+++a/mm/cma.h
@@ -9,7 +9,7 @@ struct cma {unsignedlongcount;unsignedlong*bitmap;unsignedintorder_per_bit;/* Order of pages represented by one bit */-structmutexlock;+spinlock_tlock;#ifdef CONFIG_CMA_DEBUGFSstructhlist_headmem_head;spinlock_tmem_head_lock;
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:51
From: Mike Kravetz <redacted>
Subject: hugetlb: no need to drop hugetlb_lock to call cma_release
Now that cma_release is non-blocking and irq safe, there is no need to
drop hugetlb_lock before calling.
Link: https://lkml.kernel.org/r/20210409205254.242291-3-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <redacted>
Acked-by: Roman Gushchin <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: David Hildenbrand <redacted>
Cc: "Aneesh Kumar K . V" <redacted>
Cc: Barry Song <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Hillf Danton <redacted>
Cc: HORIGUCHI NAOYA <redacted>
Cc: Joonsoo Kim <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Mina Almasry <redacted>
Cc: Muchun Song <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shakeel Butt <redacted>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 6 ------
1 file changed, 6 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:56
From: Mike Kravetz <redacted>
Subject: hugetlb: add per-hstate mutex to synchronize user adjustments
The helper routine hstate_next_node_to_alloc accesses and modifies the
hstate variable next_nid_to_alloc. The helper is used by the routines
alloc_pool_huge_page and adjust_pool_surplus. adjust_pool_surplus is
called with hugetlb_lock held. However, alloc_pool_huge_page can not be
called with the hugetlb lock held as it will call the page allocator. Two
instances of alloc_pool_huge_page could be run in parallel or
alloc_pool_huge_page could run in parallel with adjust_pool_surplus which
may result in the variable next_nid_to_alloc becoming invalid for the
caller and pages being allocated on the wrong node.
Both alloc_pool_huge_page and adjust_pool_surplus are only called from the
routine set_max_huge_pages after boot. set_max_huge_pages is only called
as the reusult of a user writing to the proc/sysfs nr_hugepages, or
nr_hugepages_mempolicy file to adjust the number of hugetlb pages.
It makes little sense to allow multiple adjustment to the number of
hugetlb pages in parallel. Add a mutex to the hstate and use it to only
allow one hugetlb page adjustment at a time. This will synchronize
modifications to the next_nid_to_alloc variable.
Link: https://lkml.kernel.org/r/20210409205254.242291-4-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Muchun Song <redacted>
Reviewed-by: David Hildenbrand <redacted>
Cc: "Aneesh Kumar K . V" <redacted>
Cc: Barry Song <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Hillf Danton <redacted>
Cc: HORIGUCHI NAOYA <redacted>
Cc: Joonsoo Kim <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mina Almasry <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <redacted>
Cc: Shakeel Butt <redacted>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/hugetlb.h | 1 +
mm/hugetlb.c | 8 ++++++++
2 files changed, 9 insertions(+)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:34:59
From: Mike Kravetz <redacted>
Subject: hugetlb: create remove_hugetlb_page() to separate functionality
The new remove_hugetlb_page() routine is designed to remove a hugetlb page
from hugetlbfs processing. It will remove the page from the active or
free list, update global counters and set the compound page destructor to
NULL so that PageHuge() will return false for the 'page'. After this
call, the 'page' can be treated as a normal compound page or a collection
of base size pages.
update_and_free_page no longer decrements h->nr_huge_pages{_node} as this
is performed in remove_hugetlb_page. The only functionality performed by
update_and_free_page is to free the base pages to the lower level
allocators.
update_and_free_page is typically called after remove_hugetlb_page.
remove_hugetlb_page is to be called with the hugetlb_lock held.
Creating this routine and separating functionality is in preparation for
restructuring code to reduce lock hold times. This commit should not
introduce any changes to functionality.
Link: https://lkml.kernel.org/r/20210409205254.242291-5-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Muchun Song <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Cc: "Aneesh Kumar K . V" <redacted>
Cc: Barry Song <redacted>
Cc: David Hildenbrand <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Hillf Danton <redacted>
Cc: HORIGUCHI NAOYA <redacted>
Cc: Joonsoo Kim <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mina Almasry <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <redacted>
Cc: Shakeel Butt <redacted>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 65 ++++++++++++++++++++++++++++++-------------------
1 file changed, 40 insertions(+), 25 deletions(-)
@@ -1421,15 +1450,12 @@ static void __free_huge_page(struct pageh->resv_huge_pages++;if(HPageTemporary(page)){-list_del(&page->lru);-ClearHPageTemporary(page);+remove_hugetlb_page(h,page,false);update_and_free_page(h,page);}elseif(h->surplus_huge_pages_node[nid]){/* remove the page from active list */-list_del(&page->lru);+remove_hugetlb_page(h,page,true);update_and_free_page(h,page);-h->surplus_huge_pages--;-h->surplus_huge_pages_node[nid]--;}else{arch_clear_hugepage_flags(page);enqueue_huge_page(h,page);
@@ -1714,13 +1740,7 @@ static int free_pool_huge_page(struct hsstructpage*page=list_entry(h->hugepage_freelists[node].next,structpage,lru);-list_del(&page->lru);-h->free_huge_pages--;-h->free_huge_pages_node[node]--;-if(acct_surplus){-h->surplus_huge_pages--;-h->surplus_huge_pages_node[node]--;-}+remove_hugetlb_page(h,page,acct_surplus);update_and_free_page(h,page);ret=1;break;
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:03
From: Mike Kravetz <redacted>
Subject: hugetlb: call update_and_free_page without hugetlb_lock
With the introduction of remove_hugetlb_page(), there is no need for
update_and_free_page to hold the hugetlb lock. Change all callers to drop
the lock before calling.
With additional code modifications, this will allow loops which decrease
the huge page pool to drop the hugetlb_lock with each page to reduce long
hold times.
The ugly unlock/lock cycle in free_pool_huge_page will be removed in a
subsequent patch which restructures free_pool_huge_page.
Link: https://lkml.kernel.org/r/20210409205254.242291-6-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Muchun Song <redacted>
Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Cc: "Aneesh Kumar K . V" <redacted>
Cc: Barry Song <redacted>
Cc: David Hildenbrand <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Hillf Danton <redacted>
Cc: HORIGUCHI NAOYA <redacted>
Cc: Joonsoo Kim <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mina Almasry <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <redacted>
Cc: Shakeel Butt <redacted>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
@@ -1451,16 +1451,18 @@ static void __free_huge_page(struct pageif(HPageTemporary(page)){remove_hugetlb_page(h,page,false);+spin_unlock(&hugetlb_lock);update_and_free_page(h,page);}elseif(h->surplus_huge_pages_node[nid]){/* remove the page from active list */remove_hugetlb_page(h,page,true);+spin_unlock(&hugetlb_lock);update_and_free_page(h,page);}else{arch_clear_hugepage_flags(page);enqueue_huge_page(h,page);+spin_unlock(&hugetlb_lock);}-spin_unlock(&hugetlb_lock);}/*
@@ -1741,7 +1743,13 @@ static int free_pool_huge_page(struct hslist_entry(h->hugepage_freelists[node].next,structpage,lru);remove_hugetlb_page(h,page,acct_surplus);+/*+*unlock/lockaroundupdate_and_free_pageistemporary+*andwillberemovedwithsubsequentpatch.+*/+spin_unlock(&hugetlb_lock);update_and_free_page(h,page);+spin_lock(&hugetlb_lock);ret=1;break;}
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:07
From: Mike Kravetz <redacted>
Subject: hugetlb: change free_pool_huge_page to remove_pool_huge_page
free_pool_huge_page was called with hugetlb_lock held. It would remove a
hugetlb page, and then free the corresponding pages to the lower level
allocators such as buddy. free_pool_huge_page was called in a loop to
remove hugetlb pages and these loops could hold the hugetlb_lock for a
considerable time.
Create new routine remove_pool_huge_page to replace free_pool_huge_page.
remove_pool_huge_page will remove the hugetlb page, and it must be called
with the hugetlb_lock held. It will return the removed page and it is the
responsibility of the caller to free the page to the lower level
allocators. The hugetlb_lock is dropped before freeing to these
allocators which results in shorter lock hold times.
Add new helper routine to call update_and_free_page for a list of pages.
Note: Some changes to the routine return_unused_surplus_pages are in need
of explanation. Commit e5bbc8a6c992 ("mm/hugetlb.c: fix reservation race
when freeing surplus pages") modified this routine to address a race which
could occur when dropping the hugetlb_lock in the loop that removes pool
pages. Accounting changes introduced in that commit were subtle and took
some thought to understand. This commit removes the cond_resched_lock()
and the potential race. Therefore, remove the subtle code and restore the
more straight forward accounting effectively reverting the commit.
Link: https://lkml.kernel.org/r/20210409205254.242291-7-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <redacted>
Reviewed-by: Muchun Song <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Cc: "Aneesh Kumar K . V" <redacted>
Cc: Barry Song <redacted>
Cc: David Hildenbrand <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Hillf Danton <redacted>
Cc: HORIGUCHI NAOYA <redacted>
Cc: Joonsoo Kim <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Mina Almasry <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <redacted>
Cc: Shakeel Butt <redacted>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 93 ++++++++++++++++++++++++++-----------------------
1 file changed, 51 insertions(+), 42 deletions(-)
@@ -2645,6 +2641,8 @@ static int set_max_huge_pages(struct hstnodemask_t*nodes_allowed){unsignedlongmin_count,ret;+structpage*page;+LIST_HEAD(page_list);NODEMASK_ALLOC(nodemask_t,node_alloc_noretry,GFP_KERNEL);/*
@@ -2757,11 +2755,22 @@ static int set_max_huge_pages(struct hstmin_count=h->resv_huge_pages+h->nr_huge_pages-h->free_huge_pages;min_count=max(count,min_count);try_to_free_low(h,min_count,nodes_allowed);++/*+*Collectpagestoberemovedonlistwithoutdroppinglock+*/while(min_count<persistent_huge_pages(h)){-if(!free_pool_huge_page(h,nodes_allowed,0))+page=remove_pool_huge_page(h,nodes_allowed,0);+if(!page)break;-cond_resched_lock(&hugetlb_lock);++list_add(&page->lru,&page_list);}+/* free the pages after dropping lock */+spin_unlock(&hugetlb_lock);+update_and_free_pages_bulk(h,&page_list);+spin_lock(&hugetlb_lock);+while(count<persistent_huge_pages(h)){if(!adjust_pool_surplus(h,nodes_allowed,1))break;
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:10
From: Mike Kravetz <redacted>
Subject: hugetlb: make free_huge_page irq safe
Commit c77c0a8ac4c5 ("mm/hugetlb: defer freeing of huge pages if in
non-task context") was added to address the issue of free_huge_page being
called from irq context. That commit hands off free_huge_page processing
to a workqueue if !in_task. However, this doesn't cover all the cases as
pointed out by 0day bot lockdep report [1].
: Possible interrupt unsafe locking scenario:
:
: CPU0 CPU1
: ---- ----
: lock(hugetlb_lock);
: local_irq_disable();
: lock(slock-AF_INET);
: lock(hugetlb_lock);
: <Interrupt>
: lock(slock-AF_INET);
Shakeel has later explained that this is very likely TCP TX zerocopy from
hugetlb pages scenario when the networking code drops a last reference to
hugetlb page while having IRQ disabled. Hugetlb freeing path doesn't
disable IRQ while holding hugetlb_lock so a lock dependency chain can lead
to a deadlock.
This commit addresses the issue by doing the following:
- Make hugetlb_lock irq safe. This is mostly a simple process of
changing spin_*lock calls to spin_*lock_irq* calls.
- Make subpool lock irq safe in a similar manner.
- Revert the !in_task check and workqueue handoff.
[1] https://lore.kernel.org/linux-mm/000000000000f1c03b05bc43aadc@google.com/
Link: https://lkml.kernel.org/r/20210409205254.242291-8-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Muchun Song <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Cc: "Aneesh Kumar K . V" <redacted>
Cc: Barry Song <redacted>
Cc: David Hildenbrand <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Hillf Danton <redacted>
Cc: HORIGUCHI NAOYA <redacted>
Cc: Joonsoo Kim <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Mina Almasry <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <redacted>
Cc: Shakeel Butt <redacted>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 169 +++++++++++++++---------------------------
mm/hugetlb_cgroup.c | 8 -
2 files changed, 67 insertions(+), 110 deletions(-)
@@ -94,9 +94,10 @@ static inline bool subpool_is_free(strucreturntrue;}-staticinlinevoidunlock_or_release_subpool(structhugepage_subpool*spool)+staticinlinevoidunlock_or_release_subpool(structhugepage_subpool*spool,+unsignedlongirq_flags){-spin_unlock(&spool->lock);+spin_unlock_irqrestore(&spool->lock,irq_flags);/* If no pages are used, and no other handles to the subpool*remain,giveupanyreservationsbasedonminimumsizeand
@@ -1461,66 +1466,18 @@ static void __free_huge_page(struct pageif(HPageTemporary(page)){remove_hugetlb_page(h,page,false);-spin_unlock(&hugetlb_lock);+spin_unlock_irqrestore(&hugetlb_lock,flags);update_and_free_page(h,page);}elseif(h->surplus_huge_pages_node[nid]){/* remove the page from active list */remove_hugetlb_page(h,page,true);-spin_unlock(&hugetlb_lock);+spin_unlock_irqrestore(&hugetlb_lock,flags);update_and_free_page(h,page);}else{arch_clear_hugepage_flags(page);enqueue_huge_page(h,page);-spin_unlock(&hugetlb_lock);-}-}--/*-*Asfree_huge_page()canbecalledfromanon-taskcontext,wehave-*todefertheactualfreeinginaworkqueuetopreventpotential-*hugetlb_lockdeadlock.-*-*free_hpage_workfn()locklesslyretrievesthelinkedlistofpagesto-*befreedandfreesthemone-by-one.Asthepage->mappingpointeris-*goingtobeclearedin__free_huge_page()anyway,itisreusedasthe-*llist_nodestructureofalocklesslinkedlistofhugepagestobefreed.-*/-staticLLIST_HEAD(hpage_freelist);--staticvoidfree_hpage_workfn(structwork_struct*work)-{-structllist_node*node;-structpage*page;--node=llist_del_all(&hpage_freelist);--while(node){-page=container_of((structaddress_space**)node,-structpage,mapping);-node=node->next;-__free_huge_page(page);-}-}-staticDECLARE_WORK(free_hpage_work,free_hpage_workfn);--voidfree_huge_page(structpage*page)-{-/*-*Deferfreeingifinnon-taskcontexttoavoidhugetlb_lockdeadlock.-*/-if(!in_task()){-/*-*Onlycallschedule_work()ifhpage_freelistispreviously-*empty.Otherwise,schedule_work()hadbeencalledbutthe-*workfnhasn'tretrievedthelistyet.-*/-if(llist_add((structllist_node*)&page->mapping,-&hpage_freelist))-schedule_work(&free_hpage_work);-return;+spin_unlock_irqrestore(&hugetlb_lock,flags);}--__free_huge_page(page);}staticvoidprep_new_huge_page(structhstate*h,structpage*page,intnid)
@@ -2660,7 +2617,7 @@ static int set_max_huge_pages(struct hst*pagesinhstateviatheproc/sysfsinterfaces.*/mutex_lock(&h->resize_lock);-spin_lock(&hugetlb_lock);+spin_lock_irq(&hugetlb_lock);/**Checkforanodespecificrequest.
@@ -2691,7 +2648,7 @@ static int set_max_huge_pages(struct hst*/if(hstate_is_gigantic(h)&&!IS_ENABLED(CONFIG_CONTIG_ALLOC)){if(count>persistent_huge_pages(h)){-spin_unlock(&hugetlb_lock);+spin_unlock_irq(&hugetlb_lock);mutex_unlock(&h->resize_lock);NODEMASK_FREE(node_alloc_noretry);return-EINVAL;
@@ -2721,14 +2678,14 @@ static int set_max_huge_pages(struct hst*page,free_huge_pagewillhandleitbyfreeingthepage*andreducingthesurplus.*/-spin_unlock(&hugetlb_lock);+spin_unlock_irq(&hugetlb_lock);/* yield cpu to avoid soft lockup */cond_resched();ret=alloc_pool_huge_page(h,nodes_allowed,node_alloc_noretry);-spin_lock(&hugetlb_lock);+spin_lock_irq(&hugetlb_lock);if(!ret)gotoout;
@@ -2767,9 +2724,9 @@ static int set_max_huge_pages(struct hstlist_add(&page->lru,&page_list);}/* free the pages after dropping lock */-spin_unlock(&hugetlb_lock);+spin_unlock_irq(&hugetlb_lock);update_and_free_pages_bulk(h,&page_list);-spin_lock(&hugetlb_lock);+spin_lock_irq(&hugetlb_lock);while(count<persistent_huge_pages(h)){if(!adjust_pool_surplus(h,nodes_allowed,1))
@@ -2777,7 +2734,7 @@ static int set_max_huge_pages(struct hst}out:h->max_huge_pages=persistent_huge_pages(h);-spin_unlock(&hugetlb_lock);+spin_unlock_irq(&hugetlb_lock);mutex_unlock(&h->resize_lock);NODEMASK_FREE(node_alloc_noretry);
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:14
From: Mike Kravetz <redacted>
Subject: hugetlb: add lockdep_assert_held() calls for hugetlb_lock
After making hugetlb lock irq safe and separating some functionality done
under the lock, add some lockdep_assert_held to help verify locking.
Link: https://lkml.kernel.org/r/20210409205254.242291-9-mike.kravetz@oracle.com
Signed-off-by: Mike Kravetz <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
Reviewed-by: Muchun Song <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Cc: "Aneesh Kumar K . V" <redacted>
Cc: Barry Song <redacted>
Cc: David Hildenbrand <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Hillf Danton <redacted>
Cc: HORIGUCHI NAOYA <redacted>
Cc: Joonsoo Kim <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mina Almasry <redacted>
Cc: Peter Xu <peterx@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <redacted>
Cc: Shakeel Butt <redacted>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 9 +++++++++
1 file changed, 9 insertions(+)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:17
From: Oscar Salvador <osalvador@suse.de>
Subject: mm,page_alloc: bail out earlier on -ENOMEM in alloc_contig_migrate_range
Patch series "Make alloc_contig_range handle Hugetlb pages", v10.
alloc_contig_range lacks the ability to handle HugeTLB pages. This can be
problematic for some users, e.g: CMA and virtio-mem, where those users
will fail the call if alloc_contig_range ever sees a HugeTLB page, even
when those pages lay in ZONE_MOVABLE and are free. That problem can be
easily solved by replacing the page in the free hugepage pool.
In-use HugeTLB are no exception though, as those can be isolated and
migrated as any other LRU or Movable page.
This patchset aims for improving
alloc_contig_range->isolate_migratepages_block, so HugeTLB pages can be
recognized and handled.
Since we also need to start reporting errors down the chain (e.g: -ENOMEM
due to not be able to allocate a new hugetlb page),
isolate_migratepages_{range,block} interfaces need to change to start
reporting error codes instead of the pfn == 0 vs pfn != 0 scheme it is
using right now. From now on, isolate_migratepages_block will not return
the next pfn to be scanned anymore, but -EINTR, -ENOMEM or 0, so we the
next pfn to be scanned will be recorded in cc->migrate_pfn field (as it is
already done in isolate_migratepages_range()).
Below is an insight from David (thanks), where the problem can clearly be
seen:
"Start a VM with 4G. Hotplug 1G via virtio-mem and online it to
ZONE_MOVABLE. Allocate 512 huge pages.
[root@localhost ~]# cat /proc/meminfo
MemTotal: 5061512 kB
MemFree: 3319396 kB
MemAvailable: 3457144 kB
...
HugePages_Total: 512
HugePages_Free: 512
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
The huge pages get partially allocate from ZONE_MOVABLE. Try unplugging
1G via virtio-mem (remember, all ZONE_MOVABLE). Inside the guest:
[ 180.058992] alloc_contig_range: [1b8000, 1c0000) PFNs busy
[ 180.060531] alloc_contig_range: [1b8000, 1c0000) PFNs busy
[ 180.061972] alloc_contig_range: [1b8000, 1c0000) PFNs busy
[ 180.063413] alloc_contig_range: [1b8000, 1c0000) PFNs busy
[ 180.064838] alloc_contig_range: [1b8000, 1c0000) PFNs busy
[ 180.065848] alloc_contig_range: [1bfc00, 1c0000) PFNs busy
[ 180.066794] alloc_contig_range: [1bfc00, 1c0000) PFNs busy
[ 180.067738] alloc_contig_range: [1bfc00, 1c0000) PFNs busy
[ 180.068669] alloc_contig_range: [1bfc00, 1c0000) PFNs busy
[ 180.069598] alloc_contig_range: [1bfc00, 1c0000) PFNs busy"
And then with this patchset running:
"Same experiment with ZONE_MOVABLE:
a) Free huge pages: all memory can get unplugged again.
b) Allocated/populated but idle huge pages: all memory can get unplugged
again.
c) Allocated/populated but all 512 huge pages are read/written in a
loop: all memory can get unplugged again, but I get a single
[ 121.192345] alloc_contig_range: [180000, 188000) PFNs busy
Most probably because it happened to try migrating a huge page
while it was busy. As virtio-mem retries on ZONE_MOVABLE a couple of
times, it can deal with this temporary failure.
Last but not least, I did something extreme:
# cat /proc/meminfo
MemTotal: 5061568 kB
MemFree: 186560 kB
MemAvailable: 354524 kB
...
HugePages_Total: 2048
HugePages_Free: 2048
HugePages_Rsvd: 0
HugePages_Surp: 0
Triggering unplug would require to dissolve+alloc - which now fails
when trying to allocate an additional ~512 huge pages (1G).
As expected, I can properly see memory unplug not fully succeeding. +
I get a fairly continuous stream of
[ 226.611584] alloc_contig_range: [19f400, 19f800) PFNs busy
...
But more importantly, the hugepage count remains stable, as configured
by the admin (me):
HugePages_Total: 2048
HugePages_Free: 2048
HugePages_Rsvd: 0
HugePages_Surp: 0"
This patch (of 7):
Currently, __alloc_contig_migrate_range can generate -EINTR, -ENOMEM or
-EBUSY, and report them down the chain. The problem is that when
migrate_pages() reports -ENOMEM, we keep going till we exhaust all the
try-attempts (5 at the moment) instead of bailing out.
migrate_pages() bails out right away on -ENOMEM because it is considered a
fatal error. Do the same here instead of keep going and retrying. Note
that this is not fixing a real issue, just a cosmetic change. Although we
can save some cycles by backing off ealier
Link: https://lkml.kernel.org/r/20210419075413.1064-1-osalvador@suse.de
Link: https://lkml.kernel.org/r/20210419075413.1064-2-osalvador@suse.de
Signed-off-by: Oscar Salvador <osalvador@suse.de>
Acked-by: Vlastimil Babka <redacted>
Reviewed-by: David Hildenbrand <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Acked-by: Mike Kravetz <redacted>
Cc: Muchun Song <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/page_alloc.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:20
From: Oscar Salvador <osalvador@suse.de>
Subject: mm,compaction: let isolate_migratepages_{range,block} return error codes
Currently, isolate_migratepages_{range,block} and their callers use a pfn
== 0 vs pfn != 0 scheme to let the caller know whether there was any error
during isolation.
This does not work as soon as we need to start reporting different error
codes and make sure we pass them down the chain, so they are properly
interpreted by functions like e.g: alloc_contig_range.
Let us rework isolate_migratepages_{range,block} so we can report error
codes. Since isolate_migratepages_block will stop returning the next pfn
to be scanned, we reuse the cc->migrate_pfn field to keep track of that.
Link: https://lkml.kernel.org/r/20210419075413.1064-3-osalvador@suse.de
Signed-off-by: Oscar Salvador <osalvador@suse.de>
Acked-by: Vlastimil Babka <redacted>
Acked-by: Mike Kravetz <redacted>
Reviewed-by: David Hildenbrand <redacted>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Muchun Song <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/compaction.c | 52 ++++++++++++++++++++++------------------------
mm/internal.h | 10 +++++++-
mm/page_alloc.c | 7 ++----
3 files changed, 36 insertions(+), 33 deletions(-)
@@ -818,16 +820,16 @@ isolate_migratepages_block(struct compacwhile(unlikely(too_many_isolated(pgdat))){/* stop isolation if there are still pages not migrated */if(cc->nr_migratepages)-return0;+return-EAGAIN;/* async migration should just abort */if(cc->mode==MIGRATE_ASYNC)-return0;+return-EAGAIN;congestion_wait(BLK_RW_ASYNC,HZ/10);if(fatal_signal_pending(current))-return0;+return-EINTR;}cond_resched();
@@ -1139,15 +1143,14 @@ fatal_pending:*@start_pfn:ThefirstPFNtostartisolating.*@end_pfn:Theone-past-lastPFN.*-*Returnszeroifisolationfailsfatallyduetoe.g.pendingsignal.-*Otherwise,functionreturnsone-past-the-lastPFNofisolatedpage-*(whichmaybegreaterthanend_pfnifendfellinamiddleofaTHPpage).+*Returns-EAGAINwhencontented,-EINTRincaseofasignalpendingor0.*/-unsignedlong+intisolate_migratepages_range(structcompact_control*cc,unsignedlongstart_pfn,unsignedlongend_pfn){unsignedlongpfn,block_start_pfn,block_end_pfn;+intret=0;/* Scan block by block. First and last block may be incomplete */pfn=start_pfn;
@@ -1903,9 +1904,6 @@ static isolate_migrate_t isolate_migratebreak;}-/* Record where migration scanner will be restarted. */-cc->migrate_pfn=low_pfn;-returncc->nr_migratepages?ISOLATE_SUCCESS:ISOLATE_NONE;}---a/mm/internal.h~mmcompaction-let-isolate_migratepages_rangeblock-return-error-codes+++a/mm/internal.h
@@ -244,7 +244,13 @@ struct compact_control {unsignedintnr_freepages;/* Number of isolated free pages */unsignedintnr_migratepages;/* Number of pages to migrate */unsignedlongfree_pfn;/* isolate_freepages search base */-unsignedlongmigrate_pfn;/* isolate_migratepages search base */+/*+*Actsasanin/outparametertopageisolationformigration.+*isolate_migratepagesusesitasasearchbase.+*isolate_migratepages_blockwillupdatethevaluetothenextpfn+*afterthelastisolatedone.+*/+unsignedlongmigrate_pfn;unsignedlongfast_start_pfn;/* a pfn to start linear scan from */structzone*zone;unsignedlongtotal_migrate_scanned;
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:23
From: Oscar Salvador <osalvador@suse.de>
Subject: mm,hugetlb: drop clearing of flag from prep_new_huge_page
Pages allocated via the page allocator or CMA get its private field
cleared by means of post_alloc_hook().
Pages allocated during boot, that is directly from the memblock allocator,
get cleared by
paging_init()->..->memmap_init_zone->..->__init_single_page() before any
memblock allocation.
Based on this ground, let us remove the clearing of the flag from
prep_new_huge_page() as it is not needed. This was a leftover from
6c0371490140 ("hugetlb: convert PageHugeFreed to HPageFreed flag").
Previously the explicit clearing was necessary because compound
allocations do not get this initialization (see prep_compound_page).
Link: https://lkml.kernel.org/r/20210419075413.1064-4-osalvador@suse.de
Signed-off-by: Oscar Salvador <osalvador@suse.de>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: David Hildenbrand <redacted>
Reviewed-by: Mike Kravetz <redacted>
Cc: Muchun Song <redacted>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 1 -
1 file changed, 1 deletion(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:27
From: Oscar Salvador <osalvador@suse.de>
Subject: mm,hugetlb: split prep_new_huge_page functionality
Currently, prep_new_huge_page() performs two functions. It sets the right
state for a new hugetlb, and increases the hstate's counters to account
for the new page.
Let us split its functionality into two separate functions, decoupling the
handling of the counters from initializing a hugepage. The outcome is
having __prep_new_huge_page(), which only initializes the page , and
__prep_account_new_huge_page(), which adds the new page to the hstate's
counters.
This allows us to be able to set a hugetlb without having to worry about
the counter/locking. It will prove useful in the next patch.
prep_new_huge_page() still calls both functions.
Link: https://lkml.kernel.org/r/20210419075413.1064-5-osalvador@suse.de
Signed-off-by: Oscar Salvador <osalvador@suse.de>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Mike Kravetz <redacted>
Reviewed-by: David Hildenbrand <redacted>
Cc: Muchun Song <redacted>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/hugetlb.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:29
From: Zi Yan <ziy@nvidia.com>
Subject: mm: huge_memory: a new debugfs interface for splitting THP tests
We did not have a direct user interface of splitting the compound page
backing a THP and there is no need unless we want to expose the THP
implementation details to users. Make <debugfs>/split_huge_pages accept a
new command to do that.
By writing "<pid>,<vaddr_start>,<vaddr_end>" to
<debugfs>/split_huge_pages, THPs within the given virtual address range
from the process with the given pid are split. It is used to test
split_huge_page function. In addition, a selftest program is added to
tools/testing/selftests/vm to utilize the interface by splitting
PMD THPs and PTE-mapped THPs.
This does not change the old behavior, i.e., writing 1 to the interface
to split all THPs in the system.
Link: https://lkml.kernel.org/r/20210331235309.332292-1-zi.yan@sent.com
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Yang Shi <redacted>
Cc: David Hildenbrand <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: "Kirill A . Shutemov" <redacted>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mika Penttila <redacted>
Cc: Sandipan Das <redacted>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/huge_memory.c | 155 +++++
tools/testing/selftests/vm/.gitignore | 1
tools/testing/selftests/vm/Makefile | 1
tools/testing/selftests/vm/split_huge_page_test.c | 318 ++++++++++++
4 files changed, 467 insertions(+), 8 deletions(-)
@@ -2948,15 +2947,155 @@ static int split_huge_pages_set(void *daunlock_page(page);next:put_page(page);+cond_resched();}}-pr_info("%lu of %lu THP split\n",split,total);+pr_debug("%lu of %lu THP split\n",split,total);+}-return0;+staticinlineboolvma_not_suitable_for_thp_split(structvm_area_struct*vma)+{+returnvma_is_special_huge(vma)||(vma->vm_flags&VM_IO)||+is_vm_hugetlb_page(vma);+}++staticintsplit_huge_pages_pid(intpid,unsignedlongvaddr_start,+unsignedlongvaddr_end)+{+intret=0;+structtask_struct*task;+structmm_struct*mm;+unsignedlongtotal=0,split=0;+unsignedlongaddr;++vaddr_start&=PAGE_MASK;+vaddr_end&=PAGE_MASK;++/* Find the task_struct from pid */+rcu_read_lock();+task=find_task_by_vpid(pid);+if(!task){+rcu_read_unlock();+ret=-ESRCH;+gotoout;+}+get_task_struct(task);+rcu_read_unlock();++/* Find the mm_struct */+mm=get_task_mm(task);+put_task_struct(task);++if(!mm){+ret=-EINVAL;+gotoout;+}++pr_debug("Split huge pages in pid: %d, vaddr: [0x%lx - 0x%lx]\n",+pid,vaddr_start,vaddr_end);++mmap_read_lock(mm);+/*+*alwaysincreaseaddrbyPAGE_SIZE,sincewecouldhaveaPTEpage+*tablefilledwithPTE-mappedTHPs,eachofwhichisdistinct.+*/+for(addr=vaddr_start;addr<vaddr_end;addr+=PAGE_SIZE){+structvm_area_struct*vma=find_vma(mm,addr);+unsignedintfollflags;+structpage*page;++if(!vma||addr<vma->vm_start)+break;++/* skip special VMA and hugetlb VMA */+if(vma_not_suitable_for_thp_split(vma)){+addr=vma->vm_end;+continue;+}++/* FOLL_DUMP to ignore special (like zero) pages */+follflags=FOLL_GET|FOLL_DUMP;+page=follow_page(vma,addr,follflags);++if(IS_ERR(page))+continue;+if(!page)+continue;++if(!is_transparent_hugepage(page))+gotonext;++total++;+if(!can_split_huge_page(compound_head(page),NULL))+gotonext;++if(!trylock_page(page))+gotonext;++if(!split_huge_page(page))+split++;++unlock_page(page);+next:+put_page(page);+cond_resched();+}+mmap_read_unlock(mm);+mmput(mm);++pr_debug("%lu of %lu THP split\n",split,total);++out:+returnret;}-DEFINE_DEBUGFS_ATTRIBUTE(split_huge_pages_fops,NULL,split_huge_pages_set,-"%llu\n");++#define MAX_INPUT_BUF_SZ 255++staticssize_tsplit_huge_pages_write(structfile*file,constchar__user*buf,+size_tcount,loff_t*ppops)+{+staticDEFINE_MUTEX(split_debug_mutex);+ssize_tret;+charinput_buf[MAX_INPUT_BUF_SZ];/* hold pid, start_vaddr, end_vaddr */+intpid;+unsignedlongvaddr_start,vaddr_end;++ret=mutex_lock_interruptible(&split_debug_mutex);+if(ret)+returnret;++ret=-EFAULT;++memset(input_buf,0,MAX_INPUT_BUF_SZ);+if(copy_from_user(input_buf,buf,min_t(size_t,count,MAX_INPUT_BUF_SZ)))+gotoout;++input_buf[MAX_INPUT_BUF_SZ-1]='\0';+ret=sscanf(input_buf,"%d,0x%lx,0x%lx",&pid,&vaddr_start,&vaddr_end);+if(ret==1&&pid==1){+split_huge_pages_all();+ret=strlen(input_buf);+gotoout;+}elseif(ret!=3){+ret=-EINVAL;+gotoout;+}++ret=split_huge_pages_pid(pid,vaddr_start,vaddr_end);+if(!ret)+ret=strlen(input_buf);+out:+mutex_unlock(&split_debug_mutex);+returnret;++}++staticconststructfile_operationssplit_huge_pages_fops={+.owner=THIS_MODULE,+.write=split_huge_pages_write,+.llseek=no_llseek,+};staticint__initsplit_huge_pages_debugfs(void){---a/tools/testing/selftests/vm/.gitignore~mm-huge_memory-a-new-debugfs-interface-for-splitting-thp-tests+++a/tools/testing/selftests/vm/.gitignore
@@ -0,0 +1,318 @@+// SPDX-License-Identifier: GPL-2.0+/*+*AtestofsplittingPMDTHPsandPTE-mappedTHPsfromaspecifiedvirtual+*addressrangeinaprocessvia<debugfs>/split_huge_pagesinterface.+*/++#define _GNU_SOURCE+#include<stdio.h>+#include<stdlib.h>+#include<unistd.h>+#include<inttypes.h>+#include<string.h>+#include<fcntl.h>+#include<sys/mman.h>+#include<malloc.h>+#include<stdbool.h>++uint64_tpagesize;+unsignedintpageshift;+uint64_tpmd_pagesize;++#define PMD_SIZE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"+#define SPLIT_DEBUGFS "/sys/kernel/debug/split_huge_pages"+#define SMAP_PATH "/proc/self/smaps"+#define INPUT_MAX 80++#define PFN_MASK ((1UL<<55)-1)+#define KPF_THP (1UL<<22)++intis_backed_by_thp(char*vaddr,intpagemap_file,intkpageflags_file)+{+uint64_tpaddr;+uint64_tpage_flags;++if(pagemap_file){+pread(pagemap_file,&paddr,sizeof(paddr),+((long)vaddr>>pageshift)*sizeof(paddr));++if(kpageflags_file){+pread(kpageflags_file,&page_flags,sizeof(page_flags),+(paddr&PFN_MASK)*sizeof(page_flags));++return!!(page_flags&KPF_THP);+}+}+return0;+}+++staticuint64_tread_pmd_pagesize(void)+{+intfd;+charbuf[20];+ssize_tnum_read;++fd=open(PMD_SIZE_PATH,O_RDONLY);+if(fd==-1){+perror("Open hpage_pmd_size failed");+exit(EXIT_FAILURE);+}+num_read=read(fd,buf,19);+if(num_read<1){+close(fd);+perror("Read hpage_pmd_size failed");+exit(EXIT_FAILURE);+}+buf[num_read]='\0';+close(fd);++returnstrtoul(buf,NULL,10);+}++staticintwrite_file(constchar*path,constchar*buf,size_tbuflen)+{+intfd;+ssize_tnumwritten;++fd=open(path,O_WRONLY);+if(fd==-1)+return0;++numwritten=write(fd,buf,buflen-1);+close(fd);+if(numwritten<1)+return0;++return(unsignedint)numwritten;+}++staticvoidwrite_debugfs(intpid,uint64_tvaddr_start,uint64_tvaddr_end)+{+charinput[INPUT_MAX];+intret;++ret=snprintf(input,INPUT_MAX,"%d,0x%lx,0x%lx",pid,vaddr_start,+vaddr_end);+if(ret>=INPUT_MAX){+printf("%s: Debugfs input is too long\n",__func__);+exit(EXIT_FAILURE);+}++if(!write_file(SPLIT_DEBUGFS,input,ret+1)){+perror(SPLIT_DEBUGFS);+exit(EXIT_FAILURE);+}+}++#define MAX_LINE_LENGTH 500++staticboolcheck_for_pattern(FILE*fp,constchar*pattern,char*buf)+{+while(fgets(buf,MAX_LINE_LENGTH,fp)!=NULL){+if(!strncmp(buf,pattern,strlen(pattern)))+returntrue;+}+returnfalse;+}++staticuint64_tcheck_huge(void*addr)+{+uint64_tthp=0;+intret;+FILE*fp;+charbuffer[MAX_LINE_LENGTH];+charaddr_pattern[MAX_LINE_LENGTH];++ret=snprintf(addr_pattern,MAX_LINE_LENGTH,"%08lx-",+(unsignedlong)addr);+if(ret>=MAX_LINE_LENGTH){+printf("%s: Pattern is too long\n",__func__);+exit(EXIT_FAILURE);+}+++fp=fopen(SMAP_PATH,"r");+if(!fp){+printf("%s: Failed to open file %s\n",__func__,SMAP_PATH);+exit(EXIT_FAILURE);+}+if(!check_for_pattern(fp,addr_pattern,buffer))+gotoerr_out;++/*+*FetchtheAnonHugePages:inthesameblockandcheckthenumberof+*hugepages.+*/+if(!check_for_pattern(fp,"AnonHugePages:",buffer))+gotoerr_out;++if(sscanf(buffer,"AnonHugePages:%10ld kB",&thp)!=1){+printf("Reading smap error\n");+exit(EXIT_FAILURE);+}++err_out:+fclose(fp);+returnthp;+}++voidsplit_pmd_thp(void)+{+char*one_page;+size_tlen=4*pmd_pagesize;+uint64_tthp_size;+size_ti;++one_page=memalign(pmd_pagesize,len);++if(!one_page){+printf("Fail to allocate memory\n");+exit(EXIT_FAILURE);+}++madvise(one_page,len,MADV_HUGEPAGE);++for(i=0;i<len;i++)+one_page[i]=(char)i;++thp_size=check_huge(one_page);+if(!thp_size){+printf("No THP is allocated\n");+exit(EXIT_FAILURE);+}++/* split all THPs */+write_debugfs(getpid(),(uint64_t)one_page,(uint64_t)one_page+len);++for(i=0;i<len;i++)+if(one_page[i]!=(char)i){+printf("%ld byte corrupted\n",i);+exit(EXIT_FAILURE);+}+++thp_size=check_huge(one_page);+if(thp_size){+printf("Still %ld kB AnonHugePages not split\n",thp_size);+exit(EXIT_FAILURE);+}++printf("Split huge pages successful\n");+free(one_page);+}++voidsplit_pte_mapped_thp(void)+{+char*one_page,*pte_mapped,*pte_mapped2;+size_tlen=4*pmd_pagesize;+uint64_tthp_size;+size_ti;+constchar*pagemap_template="/proc/%d/pagemap";+constchar*kpageflags_proc="/proc/kpageflags";+charpagemap_proc[255];+intpagemap_fd;+intkpageflags_fd;++if(snprintf(pagemap_proc,255,pagemap_template,getpid())<0){+perror("get pagemap proc error");+exit(EXIT_FAILURE);+}+pagemap_fd=open(pagemap_proc,O_RDONLY);++if(pagemap_fd==-1){+perror("read pagemap:");+exit(EXIT_FAILURE);+}++kpageflags_fd=open(kpageflags_proc,O_RDONLY);++if(kpageflags_fd==-1){+perror("read kpageflags:");+exit(EXIT_FAILURE);+}++one_page=mmap((void*)(1UL<<30),len,PROT_READ|PROT_WRITE,+MAP_ANONYMOUS|MAP_PRIVATE,-1,0);++madvise(one_page,len,MADV_HUGEPAGE);++for(i=0;i<len;i++)+one_page[i]=(char)i;++thp_size=check_huge(one_page);+if(!thp_size){+printf("No THP is allocated\n");+exit(EXIT_FAILURE);+}++/* remap the first pagesize of first THP */+pte_mapped=mremap(one_page,pagesize,pagesize,MREMAP_MAYMOVE);++/* remap the Nth pagesize of Nth THP */+for(i=1;i<4;i++){+pte_mapped2=mremap(one_page+pmd_pagesize*i+pagesize*i,+pagesize,pagesize,+MREMAP_MAYMOVE|MREMAP_FIXED,+pte_mapped+pagesize*i);+if(pte_mapped2==(char*)-1){+perror("mremap failed");+exit(EXIT_FAILURE);+}+}++/* smap does not show THPs after mremap, use kpageflags instead */+thp_size=0;+for(i=0;i<pagesize*4;i++)+if(i%pagesize==0&&+is_backed_by_thp(&pte_mapped[i],pagemap_fd,kpageflags_fd))+thp_size++;++if(thp_size!=4){+printf("Some THPs are missing during mremap\n");+exit(EXIT_FAILURE);+}++/* split all remapped THPs */+write_debugfs(getpid(),(uint64_t)pte_mapped,+(uint64_t)pte_mapped+pagesize*4);++/* smap does not show THPs after mremap, use kpageflags instead */+thp_size=0;+for(i=0;i<pagesize*4;i++){+if(pte_mapped[i]!=(char)i){+printf("%ld byte corrupted\n",i);+exit(EXIT_FAILURE);+}+if(i%pagesize==0&&+is_backed_by_thp(&pte_mapped[i],pagemap_fd,kpageflags_fd))+thp_size++;+}++if(thp_size){+printf("Still %ld THPs not split\n",thp_size);+exit(EXIT_FAILURE);+}++printf("Split PTE-mapped huge pages successful\n");+munmap(one_page,len);+close(pagemap_fd);+close(kpageflags_fd);+}++intmain(intargc,char**argv)+{+if(geteuid()!=0){+printf("Please run the benchmark as root\n");+exit(EXIT_FAILURE);+}++pagesize=getpagesize();+pageshift=ffs(pagesize)-1;+pmd_pagesize=read_pmd_pagesize();++split_pmd_thp();+split_pte_mapped_thp();++return0;+}
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:31
From: Oscar Salvador <osalvador@suse.de>
Subject: mm: make alloc_contig_range handle free hugetlb pages
alloc_contig_range will fail if it ever sees a HugeTLB page within the
range we are trying to allocate, even when that page is free and can be
easily reallocated.
This has proved to be problematic for some users of alloc_contic_range,
e.g: CMA and virtio-mem, where those would fail the call even when those
pages lay in ZONE_MOVABLE and are free.
We can do better by trying to replace such page.
Free hugepages are tricky to handle so as to no userspace application
notices disruption, we need to replace the current free hugepage with a
new one.
In order to do that, a new function called alloc_and_dissolve_huge_page is
introduced. This function will first try to get a new fresh hugepage, and
if it succeeds, it will replace the old one in the free hugepage pool.
The free page replacement is done under hugetlb_lock, so no external users
of hugetlb will notice the change. To allocate the new huge page, we use
alloc_buddy_huge_page(), so we do not have to deal with any counters, and
prep_new_huge_page() is not called. This is valulable because in case we
need to free the new page, we only need to call __free_pages().
Once we know that the page to be replaced is a genuine 0-refcounted huge
page, we remove the old page from the freelist by remove_hugetlb_page().
Then, we can call __prep_new_huge_page() and
__prep_account_new_huge_page() for the new huge page to properly
initialize it and increment the hstate->nr_huge_pages counter (previously
decremented by remove_hugetlb_page()). Once done, the page is enqueued by
enqueue_huge_page() and it is ready to be used.
There is one tricky case when page's refcount is 0 because it is in the
process of being released. A missing PageHugeFreed bit will tell us that
freeing is in flight so we retry after dropping the hugetlb_lock. The
race window should be small and the next retry should make a forward
progress.
E.g:
CPU0 CPU1
free_huge_page() isolate_or_dissolve_huge_page
PageHuge() == T
alloc_and_dissolve_huge_page
alloc_buddy_huge_page()
spin_lock_irq(hugetlb_lock)
// PageHuge() && !PageHugeFreed &&
// !PageCount()
spin_unlock_irq(hugetlb_lock)
spin_lock_irq(hugetlb_lock)
1) update_and_free_page
PageHuge() == F
__free_pages()
2) enqueue_huge_page
SetPageHugeFreed()
spin_unlock_irq(&hugetlb_lock)
spin_lock_irq(hugetlb_lock)
1) PageHuge() == F (freed by case#1 from CPU0)
2) PageHuge() == T
PageHugeFreed() == T
- proceed with replacing the page
In the case above we retry as the window race is quite small and we have
high chances to succeed next time.
With regard to the allocation, we restrict it to the node the page belongs
to with __GFP_THISNODE, meaning we do not fallback on other node's zones.
Note that gigantic hugetlb pages are fenced off since there is a cyclic
dependency between them and alloc_contig_range.
Link: https://lkml.kernel.org/r/20210419075413.1064-6-osalvador@suse.de
Signed-off-by: Oscar Salvador <osalvador@suse.de>
Acked-by: Michal Hocko <mhocko@suse.com>
Acked-by: David Hildenbrand <redacted>
Reviewed-by: Mike Kravetz <redacted>
Cc: Muchun Song <redacted>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/hugetlb.h | 6 +
mm/compaction.c | 33 +++++++++-
mm/hugetlb.c | 116 ++++++++++++++++++++++++++++++++++++++
3 files changed, 152 insertions(+), 3 deletions(-)
@@ -906,6 +906,29 @@ isolate_migratepages_block(struct compacvalid_page=page;}+if(PageHuge(page)&&cc->alloc_contig){+ret=isolate_or_dissolve_huge_page(page);++/*+*Failisolationincaseisolate_or_dissolve_huge_page()+*reportsanerror.Incaseof-ENOMEM,abortrightaway.+*/+if(ret<0){+/* Do not report -EBUSY down the chain */+if(ret==-EBUSY)+ret=0;+low_pfn+=(1UL<<compound_order(page))-1;+gotoisolate_fail;+}++/*+*Ok,thehugepagewasdissolved.Nowthesepagesare+*Buddyandcannotbere-allocatedbecausetheyare+*isolated.Fall-throughasthecheckbelowhandles+*Buddypages.+*/+}+/**Skipiffree.Wereadpageorderherewithoutzonelock*whichisgenerallyunsafe,buttheracewindowissmalland
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:33
From: Oscar Salvador <osalvador@suse.de>
Subject: mm: make alloc_contig_range handle in-use hugetlb pages
alloc_contig_range() will fail if it finds a HugeTLB page within the
range, without a chance to handle them. Since HugeTLB pages can be
migrated as any LRU or Movable page, it does not make sense to bail out
without trying. Enable the interface to recognize in-use HugeTLB pages so
we can migrate them, and have much better chances to succeed the call.
Link: https://lkml.kernel.org/r/20210419075413.1064-7-osalvador@suse.de
Signed-off-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Mike Kravetz <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Acked-by: David Hildenbrand <redacted>
Cc: Muchun Song <redacted>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/hugetlb.h | 5 +++--
mm/compaction.c | 12 +++++++++++-
mm/hugetlb.c | 22 +++++++++++++++++-----
mm/vmscan.c | 5 +++--
4 files changed, 34 insertions(+), 10 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:36
From: Oscar Salvador <osalvador@suse.de>
Subject: mm,page_alloc: drop unnecessary checks from pfn_range_valid_contig
pfn_range_valid_contig() bails out when it finds an in-use page or a
hugetlb page, among other things. We can drop the in-use page check since
__alloc_contig_pages can migrate away those pages, and the hugetlb page
check can go too since isolate_migratepages_range is now capable of
dealing with hugetlb pages. Either way, those checks are racy so let the
end function handle it when the time comes.
Link: https://lkml.kernel.org/r/20210419075413.1064-8-osalvador@suse.de
Signed-off-by: Oscar Salvador <osalvador@suse.de>
Suggested-by: David Hildenbrand <redacted>
Reviewed-by: David Hildenbrand <redacted>
Acked-by: Mike Kravetz <redacted>
Acked-by: Michal Hocko <mhocko@suse.com>
Cc: Muchun Song <redacted>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/page_alloc.c | 6 ------
1 file changed, 6 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:40
From: Axel Rasmussen <axelrasmussen@google.com>
Subject: userfaultfd: add minor fault registration mode
Patch series "userfaultfd: add minor fault handling", v9.
Overview
========
This series adds a new userfaultfd feature, UFFD_FEATURE_MINOR_HUGETLBFS.
When enabled (via the UFFDIO_API ioctl), this feature means that any
hugetlbfs VMAs registered with UFFDIO_REGISTER_MODE_MISSING will *also*
get events for "minor" faults. By "minor" fault, I mean the following
situation:
Let there exist two mappings (i.e., VMAs) to the same page(s) (shared
memory). One of the mappings is registered with userfaultfd (in minor
mode), and the other is not. Via the non-UFFD mapping, the underlying
pages have already been allocated & filled with some contents. The UFFD
mapping has not yet been faulted in; when it is touched for the first
time, this results in what I'm calling a "minor" fault. As a concrete
example, when working with hugetlbfs, we have huge_pte_none(), but
find_lock_page() finds an existing page.
We also add a new ioctl to resolve such faults: UFFDIO_CONTINUE. The idea
is, userspace resolves the fault by either a) doing nothing if the
contents are already correct, or b) updating the underlying contents using
the second, non-UFFD mapping (via memcpy/memset or similar, or something
fancier like RDMA, or etc...). In either case, userspace issues
UFFDIO_CONTINUE to tell the kernel "I have ensured the page contents are
correct, carry on setting up the mapping".
Use Case
========
Consider the use case of VM live migration (e.g. under QEMU/KVM):
1. While a VM is still running, we copy the contents of its memory to a
target machine. The pages are populated on the target by writing to the
non-UFFD mapping, using the setup described above. The VM is still running
(and therefore its memory is likely changing), so this may be repeated
several times, until we decide the target is "up to date enough".
2. We pause the VM on the source, and start executing on the target machine.
During this gap, the VM's user(s) will *see* a pause, so it is desirable to
minimize this window.
3. Between the last time any page was copied from the source to the target, and
when the VM was paused, the contents of that page may have changed - and
therefore the copy we have on the target machine is out of date. Although we
can keep track of which pages are out of date, for VMs with large amounts of
memory, it is "slow" to transfer this information to the target machine. We
want to resume execution before such a transfer would complete.
4. So, the guest begins executing on the target machine. The first time it
touches its memory (via the UFFD-registered mapping), userspace wants to
intercept this fault. Userspace checks whether or not the page is up to date,
and if not, copies the updated page from the source machine, via the non-UFFD
mapping. Finally, whether a copy was performed or not, userspace issues a
UFFDIO_CONTINUE ioctl to tell the kernel "I have ensured the page contents
are correct, carry on setting up the mapping".
We don't have to do all of the final updates on-demand. The userfaultfd manager
can, in the background, also copy over updated pages once it receives the map of
which pages are up-to-date or not.
Interaction with Existing APIs
==============================
Because this is a feature, a registered VMA could potentially receive both
missing and minor faults. I spent some time thinking through how the
existing API interacts with the new feature:
UFFDIO_CONTINUE cannot be used to resolve non-minor faults, as it does not
allocate a new page. If UFFDIO_CONTINUE is used on a non-minor fault:
- For non-shared memory or shmem, -EINVAL is returned.
- For hugetlb, -EFAULT is returned.
UFFDIO_COPY and UFFDIO_ZEROPAGE cannot be used to resolve minor faults.
Without modifications, the existing codepath assumes a new page needs to
be allocated. This is okay, since userspace must have a second
non-UFFD-registered mapping anyway, thus there isn't much reason to want
to use these in any case (just memcpy or memset or similar).
- If UFFDIO_COPY is used on a minor fault, -EEXIST is returned.
- If UFFDIO_ZEROPAGE is used on a minor fault, -EEXIST is returned (or -EINVAL
in the case of hugetlb, as UFFDIO_ZEROPAGE is unsupported in any case).
- UFFDIO_WRITEPROTECT simply doesn't work with shared memory, and returns
-ENOENT in that case (regardless of the kind of fault).
Future Work
===========
This series only supports hugetlbfs. I have a second series in flight to
support shmem as well, extending the functionality. This series is more
mature than the shmem support at this point, and the functionality works
fully on hugetlbfs, so this series can be merged first and then shmem
support will follow.
This patch (of 6):
This feature allows userspace to intercept "minor" faults. By "minor"
faults, I mean the following situation:
Let there exist two mappings (i.e., VMAs) to the same page(s). One of the
mappings is registered with userfaultfd (in minor mode), and the other is
not. Via the non-UFFD mapping, the underlying pages have already been
allocated & filled with some contents. The UFFD mapping has not yet been
faulted in; when it is touched for the first time, this results in what
I'm calling a "minor" fault. As a concrete example, when working with
hugetlbfs, we have huge_pte_none(), but find_lock_page() finds an existing
page.
This commit adds the new registration mode, and sets the relevant flag on
the VMAs being registered. In the hugetlb fault path, if we find that we
have huge_pte_none(), but find_lock_page() does indeed find an existing
page, then we have a "minor" fault, and if the VMA has the userfaultfd
registration flag, we call into userfaultfd to handle it.
This is implemented as a new registration mode, instead of an API feature.
This is because the alternative implementation has significant drawbacks
[1].
However, doing it this was requires we allocate a VM_* flag for the new
registration mode. On 32-bit systems, there are no unused bits, so this
feature is only supported on architectures with
CONFIG_ARCH_USES_HIGH_VMA_FLAGS. When attempting to register a VMA in
MINOR mode on 32-bit architectures, we return -EINVAL.
[1] https://lore.kernel.org/patchwork/patch/1380226/
[peterx@redhat.com: fix minor fault page leak]
Link: https://lkml.kernel.org/r/20210322175132.36659-1-peterx@redhat.com
Link: https://lkml.kernel.org/r/20210301222728.176417-1-axelrasmussen@google.com
Link: https://lkml.kernel.org/r/20210301222728.176417-2-axelrasmussen@google.com
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Mike Kravetz <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Lokesh Gidra <redacted>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mike Rapoport <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Steven Price <steven.price@arm.com>
Cc: Vlastimil Babka <redacted>
Cc: Adam Ruprecht <redacted>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Cannon Matthews <redacted>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: Mina Almasry <redacted>
Cc: Oliver Upton <redacted>
Cc: Kirill A. Shutemov <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
arch/arm64/Kconfig | 1
arch/x86/Kconfig | 1
fs/proc/task_mmu.c | 3 +
fs/userfaultfd.c | 78 +++++++++++++++++-----------
include/linux/mm.h | 7 ++
include/linux/userfaultfd_k.h | 15 +++++
include/trace/events/mmflags.h | 7 ++
include/uapi/linux/userfaultfd.h | 15 ++++-
init/Kconfig | 5 +
mm/hugetlb.c | 80 ++++++++++++++++++-----------
10 files changed, 150 insertions(+), 62 deletions(-)
@@ -127,6 +131,7 @@ struct uffd_msg { /*flagsforUFFD_EVENT_PAGEFAULT*/#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */+#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is VM_UFFD_MINOR */ structuffdio_api{/*userlandasksforanAPInumberandthefeaturestoenable*/
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:45
From: Axel Rasmussen <axelrasmussen@google.com>
Subject: userfaultfd: disable huge PMD sharing for MINOR registered VMAs
As the comment says: for the MINOR fault use case, although the page might
be present and populated in the other (non-UFFD-registered) half of the
mapping, it may be out of date, and we explicitly want userspace to get a
minor fault so it can check and potentially update the page's contents.
Huge PMD sharing would prevent these faults from occurring for suitably
aligned areas, so disable it upon UFFD registration.
Link: https://lkml.kernel.org/r/20210301222728.176417-3-axelrasmussen@google.com
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Mike Kravetz <redacted>
Cc: Adam Ruprecht <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Cannon Matthews <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Kirill A. Shutemov <redacted>
Cc: Lokesh Gidra <redacted>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mike Rapoport <redacted>
Cc: Mina Almasry <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oliver Upton <redacted>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/userfaultfd_k.h | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:48
From: Axel Rasmussen <axelrasmussen@google.com>
Subject: userfaultfd: hugetlbfs: only compile UFFD helpers if config enabled
For background, mm/userfaultfd.c provides a general mcopy_atomic
implementation. But some types of memory (i.e., hugetlb and shmem) need a
slightly different implementation, so they provide their own helpers for
this. In other words, userfaultfd is the only caller of these functions.
This patch achieves two things:
1. Don't spend time compiling code which will end up never being
referenced anyway (a small build time optimization).
2. In patches later in this series, we extend the signature of these
helpers with UFFD-specific state (a mode enumeration). Once this
happens, we *have to* either not compile the helpers, or
unconditionally define the UFFD-only state (which seems messier to me).
This includes the declarations in the headers, as otherwise they'd
yield warnings about implicitly defining the type of those arguments.
Link: https://lkml.kernel.org/r/20210301222728.176417-4-axelrasmussen@google.com
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Reviewed-by: Mike Kravetz <redacted>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Adam Ruprecht <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Cannon Matthews <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Kirill A. Shutemov <redacted>
Cc: Lokesh Gidra <redacted>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mike Rapoport <redacted>
Cc: Mina Almasry <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oliver Upton <redacted>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/hugetlb.h | 4 ++++
mm/hugetlb.c | 2 ++
2 files changed, 6 insertions(+)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:53
From: Axel Rasmussen <axelrasmussen@google.com>
Subject: userfaultfd: add UFFDIO_CONTINUE ioctl
This ioctl is how userspace ought to resolve "minor" userfaults. The
idea is, userspace is notified that a minor fault has occurred. It might
change the contents of the page using its second non-UFFD mapping, or
not. Then, it calls UFFDIO_CONTINUE to tell the kernel "I have ensured
the page contents are correct, carry on setting up the mapping".
Note that it doesn't make much sense to use UFFDIO_{COPY,ZEROPAGE} for
MINOR registered VMAs. ZEROPAGE maps the VMA to the zero page; but in
the minor fault case, we already have some pre-existing underlying page.
Likewise, UFFDIO_COPY isn't useful if we have a second non-UFFD mapping.
We'd just use memcpy() or similar instead.
It turns out hugetlb_mcopy_atomic_pte() already does very close to what
we want, if an existing page is provided via `struct page **pagep`. We
already special-case the behavior a bit for the UFFDIO_ZEROPAGE case, so
just extend that design: add an enum for the three modes of operation,
and make the small adjustments needed for the MCOPY_ATOMIC_CONTINUE
case. (Basically, look up the existing page, and avoid adding the
existing page to the page cache or calling set_page_huge_active() on
it.)
Link: https://lkml.kernel.org/r/20210301222728.176417-5-axelrasmussen@google.com
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Adam Ruprecht <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Cannon Matthews <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Kirill A. Shutemov <redacted>
Cc: Lokesh Gidra <redacted>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mike Kravetz <redacted>
Cc: Mike Rapoport <redacted>
Cc: Mina Almasry <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oliver Upton <redacted>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/userfaultfd.c | 67 +++++++++++++++++++++++++++++
include/linux/hugetlb.h | 3 +
include/linux/userfaultfd_k.h | 18 +++++++
include/uapi/linux/userfaultfd.h | 21 ++++++++-
mm/hugetlb.c | 40 +++++++++++------
mm/userfaultfd.c | 37 +++++++++-------
6 files changed, 156 insertions(+), 30 deletions(-)
@@ -1487,6 +1487,10 @@ out_unlock:if(!(uffdio_register.mode&UFFDIO_REGISTER_MODE_WP))ioctls_out&=~((__u64)1<<_UFFDIO_WRITEPROTECT);+/* CONTINUE ioctl is only supported for MINOR ranges. */+if(!(uffdio_register.mode&UFFDIO_REGISTER_MODE_MINOR))+ioctls_out&=~((__u64)1<<_UFFDIO_CONTINUE);+/**Nowthatwescannedallvmaswecanalreadytell*userlandwhichioctlsmethodsareguaranteedto
@@ -1840,6 +1844,66 @@ static int userfaultfd_writeprotect(strureturnret;}+staticintuserfaultfd_continue(structuserfaultfd_ctx*ctx,unsignedlongarg)+{+__s64ret;+structuffdio_continueuffdio_continue;+structuffdio_continue__user*user_uffdio_continue;+structuserfaultfd_wake_rangerange;++user_uffdio_continue=(structuffdio_continue__user*)arg;++ret=-EAGAIN;+if(READ_ONCE(ctx->mmap_changing))+gotoout;++ret=-EFAULT;+if(copy_from_user(&uffdio_continue,user_uffdio_continue,+/* don't copy the output fields */+sizeof(uffdio_continue)-(sizeof(__s64))))+gotoout;++ret=validate_range(ctx->mm,&uffdio_continue.range.start,+uffdio_continue.range.len);+if(ret)+gotoout;++ret=-EINVAL;+/* double check for wraparound just in case. */+if(uffdio_continue.range.start+uffdio_continue.range.len<=+uffdio_continue.range.start){+gotoout;+}+if(uffdio_continue.mode&~UFFDIO_CONTINUE_MODE_DONTWAKE)+gotoout;++if(mmget_not_zero(ctx->mm)){+ret=mcopy_continue(ctx->mm,uffdio_continue.range.start,+uffdio_continue.range.len,+&ctx->mmap_changing);+mmput(ctx->mm);+}else{+return-ESRCH;+}++if(unlikely(put_user(ret,&user_uffdio_continue->mapped)))+return-EFAULT;+if(ret<0)+gotoout;++/* len == 0 would wake all */+BUG_ON(!ret);+range.len=ret;+if(!(uffdio_continue.mode&UFFDIO_CONTINUE_MODE_DONTWAKE)){+range.start=uffdio_continue.range.start;+wake_userfault(ctx,&range);+}+ret=range.len==uffdio_continue.range.len?0:-EAGAIN;++out:+returnret;+}+staticinlineunsignedintuffd_ctx_features(__u64user_features){/*
@@ -1927,6 +1991,9 @@ static long userfaultfd_ioctl(struct filcaseUFFDIO_WRITEPROTECT:ret=userfaultfd_writeprotect(ctx,arg);break;+caseUFFDIO_CONTINUE:+ret=userfaultfd_continue(ctx,arg);+break;}returnret;}---a/include/linux/hugetlb.h~userfaultfd-add-uffdio_continue-ioctl+++a/include/linux/hugetlb.h
@@ -139,6 +140,7 @@ int hugetlb_mcopy_atomic_pte(struct mm_sstructvm_area_struct*dst_vma,unsignedlongdst_addr,unsignedlongsrc_addr,+enummcopy_atomic_modemode,structpage**pagep);#endif /* CONFIG_USERFAULTFD */boolhugetlb_reserve_pages(structinode*inode,longfrom,longto,
@@ -318,6 +320,7 @@ static inline int hugetlb_mcopy_atomic_pstructvm_area_struct*dst_vma,unsignedlongdst_addr,unsignedlongsrc_addr,+enummcopy_atomic_modemode,structpage**pagep){BUG();---a/include/linux/userfaultfd_k.h~userfaultfd-add-uffdio_continue-ioctl+++a/include/linux/userfaultfd_k.h
@@ -37,6 +37,22 @@ extern int sysctl_unprivileged_userfaultexternvm_fault_thandle_userfault(structvm_fault*vmf,unsignedlongreason);+/*+*Themodeofoperationfor__mcopy_atomicanditshelpers.+*+*Thisisalmostanimplementationdetail(mcopy_atomicbelowdoesn'ttakethis+*asaparameter),butit'sexposedherebecausememory-kind-specific+*implementations(e.g.hugetlbfs)needtoknowthemodeofoperation.+*/+enummcopy_atomic_mode{+/* A normal copy_from_user into the destination range. */+MCOPY_ATOMIC_NORMAL,+/* Don't copy; map the destination range to the zero page. */+MCOPY_ATOMIC_ZEROPAGE,+/* Just install pte(s) with the existing page(s) in the page cache. */+MCOPY_ATOMIC_CONTINUE,+};+externssize_tmcopy_atomic(structmm_struct*dst_mm,unsignedlongdst_start,unsignedlongsrc_start,unsignedlonglen,bool*mmap_changing,__u64mode);
@@ -4865,8 +4864,10 @@ int hugetlb_mcopy_atomic_pte(struct mm_sstructvm_area_struct*dst_vma,unsignedlongdst_addr,unsignedlongsrc_addr,+enummcopy_atomic_modemode,structpage**pagep){+boolis_continue=(mode==MCOPY_ATOMIC_CONTINUE);structaddress_space*mapping;pgoff_tidx;unsignedlongsize;
@@ -4876,8 +4877,17 @@ int hugetlb_mcopy_atomic_pte(struct mm_sspinlock_t*ptl;intret;structpage*page;+intwritable;-if(!*pagep){+mapping=dst_vma->vm_file->f_mapping;+idx=vma_hugecache_offset(h,dst_vma,dst_addr);++if(is_continue){+ret=-EFAULT;+page=find_lock_page(mapping,idx);+if(!page)+gotoout;+}elseif(!*pagep){ret=-ENOMEM;page=alloc_huge_page(dst_vma,dst_addr,0);if(IS_ERR(page))
@@ -4906,13 +4916,8 @@ int hugetlb_mcopy_atomic_pte(struct mm_s*/__SetPageUptodate(page);-mapping=dst_vma->vm_file->f_mapping;-idx=vma_hugecache_offset(h,dst_vma,dst_addr);--/*-*Ifshared,addtopagecache-*/-if(vm_shared){+/* Add shared, newly allocated pages to the page cache. */+if(vm_shared&&!is_continue){size=i_size_read(mapping->host)>>huge_page_shift(h);ret=-EFAULT;if(idx>=size)
@@ -4957,8 +4962,14 @@ int hugetlb_mcopy_atomic_pte(struct mm_shugepage_add_new_anon_rmap(page,dst_vma,dst_addr);}-_dst_pte=make_huge_pte(dst_vma,page,dst_vma->vm_flags&VM_WRITE);-if(dst_vma->vm_flags&VM_WRITE)+/* For CONTINUE on a non-shared VMA, don't set VM_WRITE for CoW. */+if(is_continue&&!vm_shared)+writable=0;+else+writable=dst_vma->vm_flags&VM_WRITE;++_dst_pte=make_huge_pte(dst_vma,page,writable);+if(writable)_dst_pte=huge_pte_mkdirty(_dst_pte);_dst_pte=pte_mkyoung(_dst_pte);
@@ -4972,15 +4983,16 @@ int hugetlb_mcopy_atomic_pte(struct mm_supdate_mmu_cache(dst_vma,dst_addr,dst_pte);spin_unlock(ptl);-SetHPageMigratable(page);-if(vm_shared)+if(!is_continue)+SetHPageMigratable(page);+if(vm_shared||is_continue)unlock_page(page);ret=0;out:returnret;out_release_unlock:spin_unlock(ptl);-if(vm_shared)+if(vm_shared||is_continue)unlock_page(page);out_release_nounlock:put_page(page);---a/mm/userfaultfd.c~userfaultfd-add-uffdio_continue-ioctl+++a/mm/userfaultfd.c
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:35:57
From: Axel Rasmussen <axelrasmussen@google.com>
Subject: userfaultfd: update documentation to describe minor fault handling
Reword / reorganize things a little bit into "lists", so new features /
modes / ioctls can sort of just be appended.
Describe how UFFDIO_REGISTER_MODE_MINOR and UFFDIO_CONTINUE can be used to
intercept and resolve minor faults. Make it clear that COPY and ZEROPAGE
are used for MISSING faults, whereas CONTINUE is used for MINOR faults.
Link: https://lkml.kernel.org/r/20210301222728.176417-6-axelrasmussen@google.com
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Adam Ruprecht <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Cannon Matthews <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Kirill A. Shutemov <redacted>
Cc: Lokesh Gidra <redacted>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mike Kravetz <redacted>
Cc: Mike Rapoport <redacted>
Cc: Mina Almasry <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oliver Upton <redacted>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
Documentation/admin-guide/mm/userfaultfd.rst | 105 ++++++++++-------
1 file changed, 65 insertions(+), 40 deletions(-)
@@ -63,36 +63,36 @@ the generic ioctl available. The ``uffdio_api.features`` bitmask returned by the ``UFFDIO_API`` ioctl defines what memory types are supported by the ``userfaultfd`` and what-events, except page fault notifications, may be generated.+events, except page fault notifications, may be generated:-If the kernel supports registering ``userfaultfd`` ranges on hugetlbfs-virtual memory areas, ``UFFD_FEATURE_MISSING_HUGETLBFS`` will be set in-``uffdio_api.features``. Similarly, ``UFFD_FEATURE_MISSING_SHMEM`` will be-set if the kernel supports registering ``userfaultfd`` ranges on shared-memory (covering all shmem APIs, i.e. tmpfs, ``IPCSHM``, ``/dev/zero``,-``MAP_SHARED``, ``memfd_create``, etc).--The userland application that wants to use ``userfaultfd`` with hugetlbfs-or shared memory need to set the corresponding flag in-``uffdio_api.features`` to enable those features.--If the userland desires to receive notifications for events other than-page faults, it has to verify that ``uffdio_api.features`` has appropriate-``UFFD_FEATURE_EVENT_*`` bits set. These events are described in more-detail below in `Non-cooperative userfaultfd`_ section.--Once the ``userfaultfd`` has been enabled the ``UFFDIO_REGISTER`` ioctl should-be invoked (if present in the returned ``uffdio_api.ioctls`` bitmask) to-register a memory range in the ``userfaultfd`` by setting the+- The ``UFFD_FEATURE_EVENT_*`` flags indicate that various other events+ other than page faults are supported. These events are described in more+ detail below in the `Non-cooperative userfaultfd`_ section.++-``UFFD_FEATURE_MISSING_HUGETLBFS`` and ``UFFD_FEATURE_MISSING_SHMEM``+ indicate that the kernel supports ``UFFDIO_REGISTER_MODE_MISSING``+ registrations for hugetlbfs and shared memory (covering all shmem APIs,+ i.e. tmpfs, ``IPCSHM``, ``/dev/zero``, ``MAP_SHARED``, ``memfd_create``,+ etc) virtual memory areas, respectively.++-``UFFD_FEATURE_MINOR_HUGETLBFS`` indicates that the kernel supports+``UFFDIO_REGISTER_MODE_MINOR`` registration for hugetlbfs virtual memory+ areas.++The userland application should set the feature flags it intends to use+when invoking the ``UFFDIO_API`` ioctl, to request that those features be+enabled if supported.++Once the ``userfaultfd`` API has been enabled the ``UFFDIO_REGISTER``+ioctl should be invoked (if present in the returned ``uffdio_api.ioctls``+bitmask) to register a memory range in the ``userfaultfd`` by setting the uffdio_register structure accordingly. The ``uffdio_register.mode`` bitmask will specify to the kernel which kind of faults to track for-the range (``UFFDIO_REGISTER_MODE_MISSING`` would track missing-pages). The ``UFFDIO_REGISTER`` ioctl will return the+the range. The ``UFFDIO_REGISTER`` ioctl will return the``uffdio_register.ioctls`` bitmask of ioctls that are suitable to resolve userfaults on the range registered. Not all ioctls will necessarily be-supported for all memory types depending on the underlying virtual-memory backend (anonymous memory vs tmpfs vs real filebacked-mappings).+supported for all memory types (e.g. anonymous memory vs. shmem vs.+hugetlbfs), or all types of intercepted faults. Userland can use the ``uffdio_register.ioctls`` to manage the virtual address space in the background (to add or potentially also remove
@@ -100,21 +100,46 @@ memory from the ``userfaultfd`` register could be triggering just before userland maps in the background the user-faulted page.-The primary ioctl to resolve userfaults is ``UFFDIO_COPY``. That-atomically copies a page into the userfault registered range and wakes-up the blocked userfaults-(unless ``uffdio_copy.mode & UFFDIO_COPY_MODE_DONTWAKE`` is set).-Other ioctl works similarly to ``UFFDIO_COPY``. They're atomic as in-guaranteeing that nothing can see an half copied page since it'll-keep userfaulting until the copy has finished.+Resolving Userfaults+--------------------++There are three basic ways to resolve userfaults:++-``UFFDIO_COPY`` atomically copies some existing page contents from+ userspace.++-``UFFDIO_ZEROPAGE`` atomically zeros the new page.++-``UFFDIO_CONTINUE`` maps an existing, previously-populated page.++These operations are atomic in the sense that they guarantee nothing can+see a half-populated page, since readers will keep userfaulting until the+operation has finished.++By default, these wake up userfaults blocked on the range in question.+They support a ``UFFDIO_*_MODE_DONTWAKE````mode`` flag, which indicates+that waking will be done separately at some later time.++Which ioctl to choose depends on the kind of page fault, and what we'd+like to do to resolve it:++- For ``UFFDIO_REGISTER_MODE_MISSING`` faults, the fault needs to be+ resolved by either providing a new page (``UFFDIO_COPY``), or mapping+ the zero page (``UFFDIO_ZEROPAGE``). By default, the kernel would map+ the zero page for a missing fault. With userfaultfd, userspace can+ decide what content to provide before the faulting thread continues.++- For ``UFFDIO_REGISTER_MODE_MINOR`` faults, there is an existing page (in+ the page cache). Userspace has the option of modifying the page's+ contents before resolving the fault. Once the contents are correct+ (modified or not), userspace asks the kernel to map the page and let the+ faulting thread continue with ``UFFDIO_CONTINUE``. Notes:-- If you requested ``UFFDIO_REGISTER_MODE_MISSING`` when registering then- you must provide some kind of page in your thread after reading from- the uffd. You must provide either ``UFFDIO_COPY`` or ``UFFDIO_ZEROPAGE``.- The normal behavior of the OS automatically providing a zero page on- an anonymous mmaping is not in place.+- You can tell which kind of fault occurred by examining+``pagefault.flags`` within the ``uffd_msg``, checking for the+``UFFD_PAGEFAULT_FLAG_*`` flags.- None of the page-delivering ioctls default to the range that you registered with. You must fill in all fields for the appropriate
@@ -122,9 +147,9 @@ Notes:- You get the address of the access that triggered the missing page event out of a struct uffd_msg that you read in the thread from the- uffd. You can supply as many pages as you want with ``UFFDIO_COPY`` or-``UFFDIO_ZEROPAGE``. Keep in mind that unless you used DONTWAKE then- the first of any of those IOCTLs wakes up the faulting thread.+ uffd. You can supply as many pages as you want with these IOCTLs.+ Keep in mind that unless you used DONTWAKE then the first of any of+ those IOCTLs wakes up the faulting thread.- Be sure to test for all errors including (``pollfd[0].revents & POLLERR``). This can happen, e.g. when ranges
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:01
From: Axel Rasmussen <axelrasmussen@google.com>
Subject: userfaultfd/selftests: add test exercising minor fault handling
Fix a dormant bug in userfaultfd_events_test(), where we did `return
faulting_process(0)` instead of `exit(faulting_process(0))`. This caused
the forked process to keep running, trying to execute any further test
cases after the events test in parallel with the "real" process.
Add a simple test case which exercises minor faults. In short, it does
the following:
1. "Sets up" an area (area_dst) and a second shared mapping to the same
underlying pages (area_dst_alias).
2. Register one of these areas with userfaultfd, in minor fault mode.
3. Start a second thread to handle any minor faults.
4. Populate the underlying pages with the non-UFFD-registered side of
the mapping. Basically, memset() each page with some arbitrary
contents.
5. Then, using the UFFD-registered mapping, read all of the page
contents, asserting that the contents match expectations (we expect
the minor fault handling thread can modify the page contents before
resolving the fault).
The minor fault handling thread, upon receiving an event, flips all the
bits (~) in that page, just to prove that it can modify it in some
arbitrary way. Then it issues a UFFDIO_CONTINUE ioctl, to setup the
mapping and resolve the fault. The reading thread should wake up and see
this modification.
Currently the minor fault test is only enabled in hugetlb_shared mode, as
this is the only configuration the kernel feature supports.
Link: https://lkml.kernel.org/r/20210301222728.176417-7-axelrasmussen@google.com
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Adam Ruprecht <redacted>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alexey Dobriyan <redacted>
Cc: Andrea Arcangeli <redacted>
Cc: Anshuman Khandual <redacted>
Cc: Cannon Matthews <redacted>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chinwen Chang <redacted>
Cc: David Rientjes <rientjes@google.com>
Cc: "Dr . David Alan Gilbert" <redacted>
Cc: Huang Ying <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jerome Glisse <redacted>
Cc: Kirill A. Shutemov <redacted>
Cc: Lokesh Gidra <redacted>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: "Michal Koutn" <mkoutny@suse.com>
Cc: Michel Lespinasse <redacted>
Cc: Mike Kravetz <redacted>
Cc: Mike Rapoport <redacted>
Cc: Mina Almasry <redacted>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oliver Upton <redacted>
Cc: Shaohua Li <redacted>
Cc: Shawn Anastasio <redacted>
Cc: Steven Price <steven.price@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
tools/testing/selftests/vm/userfaultfd.c | 164 ++++++++++++++++++++-
1 file changed, 158 insertions(+), 6 deletions(-)
@@ -81,6 +81,8 @@ static volatile bool test_uffdio_copy_eestaticvolatilebooltest_uffdio_zeropage_eexist=true;/* Whether to test uffd write-protection */staticbooltest_uffdio_wp=false;+/* Whether to test uffd minor faults */+staticbooltest_uffdio_minor=false;staticboolmap_shared;staticinthuge_fd;
@@ -779,7 +827,7 @@ static int stress(struct uffd_stats *uffreturn0;}-staticintuserfaultfd_open(intfeatures)+staticintuserfaultfd_open_ext(uint64_t*features){structuffdio_apiuffdio_api;
@@ -792,7 +840,7 @@ static int userfaultfd_open(int featuresuffd_flags=fcntl(uffd,F_GETFD,NULL);uffdio_api.api=UFFD_API;-uffdio_api.features=features;+uffdio_api.features=*features;if(ioctl(uffd,UFFDIO_API,&uffdio_api)){fprintf(stderr,"UFFDIO_API failed.\nPlease make sure to ""run with either root or ptrace capability.\n");
@@ -804,9 +852,15 @@ static int userfaultfd_open(int featuresreturn1;}+*features=uffdio_api.features;return0;}+staticintuserfaultfd_open(uint64_tfeatures)+{+returnuserfaultfd_open_ext(&features);+}+sigjmp_bufjbuf,*sigbuf;staticvoidsighndl(intsig,siginfo_t*siginfo,void*ptr)
@@ -1112,7 +1166,7 @@ static int userfaultfd_events_test(void)}if(!pid)-returnfaulting_process(0);+exit(faulting_process(0));waitpid(pid,&err,0);if(err){
@@ -1215,6 +1269,102 @@ static int userfaultfd_sig_test(void)returnuserfaults!=0;}+staticintuserfaultfd_minor_test(void)+{+structuffdio_registeruffdio_register;+unsignedlongexpected_ioctls;+unsignedlongp;+pthread_tuffd_mon;+uint8_texpected_byte;+void*expected_page;+charc;+structuffd_statsstats={0};+uint64_tfeatures=UFFD_FEATURE_MINOR_HUGETLBFS;++if(!test_uffdio_minor)+return0;++printf("testing minor faults: ");+fflush(stdout);++if(uffd_test_ops->release_pages(area_dst))+return1;++if(userfaultfd_open_ext(&features))+return1;+/* If kernel reports the feature isn't supported, skip the test. */+if(!(features&UFFD_FEATURE_MINOR_HUGETLBFS)){+printf("skipping test due to lack of feature support\n");+fflush(stdout);+return0;+}++uffdio_register.range.start=(unsignedlong)area_dst_alias;+uffdio_register.range.len=nr_pages*page_size;+uffdio_register.mode=UFFDIO_REGISTER_MODE_MINOR;+if(ioctl(uffd,UFFDIO_REGISTER,&uffdio_register)){+fprintf(stderr,"register failure\n");+exit(1);+}++expected_ioctls=uffd_test_ops->expected_ioctls;+expected_ioctls|=1<<_UFFDIO_CONTINUE;+if((uffdio_register.ioctls&expected_ioctls)!=expected_ioctls){+fprintf(stderr,"unexpected missing ioctl(s)\n");+exit(1);+}++/*+*AfterregisteringwithUFFD,populatethenon-UFFD-registeredsideof+*thesharedmapping.Thisshould*not*triggeranyUFFDminorfaults.+*/+for(p=0;p<nr_pages;++p){+memset(area_dst+(p*page_size),p%((uint8_t)-1),+page_size);+}++if(pthread_create(&uffd_mon,&attr,uffd_poll_thread,&stats)){+perror("uffd_poll_thread create");+exit(1);+}++/*+*ReadeachofthepagesbackusingtheUFFD-registeredmapping.We+*expectthatthefirsttimewetouchapage,itwillresultinaminor+*fault.uffd_poll_threadwillresolvethefaultbybit-flippingthe+*page'scontents,andthenissuingaCONTINUEioctl.+*/++if(posix_memalign(&expected_page,page_size,page_size)){+fprintf(stderr,"out of memory\n");+return1;+}++for(p=0;p<nr_pages;++p){+expected_byte=~((uint8_t)(p%((uint8_t)-1)));+memset(expected_page,expected_byte,page_size);+if(my_bcmp(expected_page,area_dst_alias+(p*page_size),+page_size)){+fprintf(stderr,+"unexpected page contents after minor fault\n");+exit(1);+}+}++if(write(pipefd[1],&c,sizeof(c))!=sizeof(c)){+perror("pipe write");+exit(1);+}+if(pthread_join(uffd_mon,NULL))+return1;++close(uffd);++uffd_stats_report(&stats,1);++returnstats.missing_faults!=0||stats.minor_faults!=nr_pages;+}+staticintuserfaultfd_stress(void){void*area;
@@ -1413,7 +1563,7 @@ static int userfaultfd_stress(void)close(uffd);returnuserfaultfd_zeropage_test()||userfaultfd_sig_test()-||userfaultfd_events_test();+||userfaultfd_events_test()||userfaultfd_minor_test();}/*
@@ -1454,6 +1604,8 @@ static void set_test_type(const char *tymap_shared=true;test_type=TEST_HUGETLB;uffd_test_ops=&hugetlb_uffd_test_ops;+/* Minor faults require shared hugetlb; only enable here. */+test_uffdio_minor=true;}elseif(!strcmp(type,"shmem")){map_shared=true;test_type=TEST_SHMEM;
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:04
From: Dave Hansen <dave.hansen@linux.intel.com>
Subject: mm/vmscan: move RECLAIM* bits to uapi header
It is currently not obvious that the RECLAIM_* bits are part of the uapi
since they are defined in vmscan.c. Move them to a uapi header to make it
obvious.
This should have no functional impact.
Link: https://lkml.kernel.org/r/20210219172557.08074910@viggo.jf.intel.com
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Ben Widawsky <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Acked-by: David Rientjes <rientjes@google.com>
Acked-by: Christoph Lameter <redacted>
Cc: Alex Shi <redacted>
Cc: Daniel Wagner <redacted>
Cc: "Tobin C. Harding" <tobin@kernel.org>
Cc: Christoph Lameter <redacted>
Cc: Huang Ying <redacted>
Cc: Dan Williams <redacted>
Cc: Qian Cai <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/uapi/linux/mempolicy.h | 7 +++++++
mm/vmscan.c | 8 --------
2 files changed, 7 insertions(+), 8 deletions(-)
@@ -64,5 +64,12 @@ enum {#define MPOL_F_MOF (1 << 3) /* this policy wants migrate on fault */#define MPOL_F_MORON (1 << 4) /* Migrate On protnone Reference On Node */+/*+*Thesebitlocationsareexposedinthevm.zone_reclaim_modesysctl+*ABI.NewbitsareOK,butexistingbitscanneverchange.+*/+#define RECLAIM_ZONE (1<<0) /* Run shrink_inactive_list on the zone */+#define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */+#define RECLAIM_UNMAP (1<<2) /* Unmap pages during reclaim */#endif /* _UAPI_LINUX_MEMPOLICY_H */---a/mm/vmscan.c~mm-vmscan-move-reclaim-bits-to-uapi-header+++a/mm/vmscan.c
@@ -4087,14 +4087,6 @@ module_init(kswapd_init)intnode_reclaim_mode__read_mostly;/*-*Thesebitlocationsareexposedinthevm.zone_reclaim_modesysctl-*ABI.NewbitsareOK,butexistingbitscanneverchange.-*/-#define RECLAIM_ZONE (1<<0) /* Run shrink_inactive_list on the zone */-#define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */-#define RECLAIM_UNMAP (1<<2) /* Unmap pages during reclaim */--/**PriorityforNODE_RECLAIM.Thisdeterminesthefractionofpages*ofanodeconsideredforeachzone_reclaim.4scans1/16thof*azone.
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:07
From: Dave Hansen <dave.hansen@linux.intel.com>
Subject: mm/vmscan: replace implicit RECLAIM_ZONE checks with explicit checks
RECLAIM_ZONE was assumed to be unused because it was never explicitly used
in the kernel. However, there were a number of places where it was
checked implicitly by checking 'node_reclaim_mode' for a zero value.
These zero checks are not great because it is not obvious what a zero mode
*means* in the code. Replace them with a helper which makes it more
obvious: node_reclaim_enabled().
This helper also provides a handy place to explicitly check the
RECLAIM_ZONE bit itself. Check it explicitly there to make it more
obvious where the bit can affect behavior.
This should have no functional impact.
Link: https://lkml.kernel.org/r/20210219172559.BF589C44@viggo.jf.intel.com
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Ben Widawsky <redacted>
Reviewed-by: Oscar Salvador <osalvador@suse.de>
Acked-by: Christoph Lameter <redacted>
Acked-by: David Rientjes <rientjes@google.com>
Cc: Alex Shi <redacted>
Cc: "Tobin C. Harding" <tobin@kernel.org>
Cc: Huang Ying <redacted>
Cc: Dan Williams <redacted>
Cc: Qian Cai <redacted>
Cc: Daniel Wagner <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/swap.h | 7 +++++++
mm/khugepaged.c | 2 +-
mm/page_alloc.c | 2 +-
3 files changed, 9 insertions(+), 2 deletions(-)
@@ -378,6 +379,12 @@ extern int sysctl_min_slab_ratio;#define node_reclaim_mode 0#endif+staticinlineboolnode_reclaim_enabled(void)+{+/* Is any node_reclaim_mode bit set? */+returnnode_reclaim_mode&(RECLAIM_ZONE|RECLAIM_WRITE|RECLAIM_UNMAP);+}+externvoidcheck_move_unevictable_pages(structpagevec*pvec);externintkswapd_run(intnid);---a/mm/khugepaged.c~mm-vmscan-replace-implicit-reclaim_zone-checks-with-explicit-checks+++a/mm/khugepaged.c
@@ -809,7 +809,7 @@ static bool khugepaged_scan_abort(int ni*Ifnode_reclaim_modeisdisabled,thennoextraeffortismadeto*allocatememorylocally.*/-if(!node_reclaim_mode)+if(!node_reclaim_enabled())returnfalse;/* If there is a count for this node already, it must be acceptable */---a/mm/page_alloc.c~mm-vmscan-replace-implicit-reclaim_zone-checks-with-explicit-checks+++a/mm/page_alloc.c
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:11
From: Yang Shi <redacted>
Subject: mm: vmscan: use nid from shrink_control for tracepoint
Patch series "Make shrinker's nr_deferred memcg aware", v10.
Recently huge amount one-off slab drop was seen on some vfs metadata heavy
workloads, it turned out there were huge amount accumulated nr_deferred
objects seen by the shrinker.
On our production machine, I saw absurd number of nr_deferred shown as the
below tracing result:
<...>-48776 [032] .... 27970562.458916: mm_shrink_slab_start:
super_cache_scan+0x0/0x1a0 ffff9a83046f3458: nid: 0 objects to shrink
2531805877005 gfp_flags GFP_HIGHUSER_MOVABLE pgs_scanned 32 lru_pgs
9300 cache items 1667 delta 11 total_scan 833
There are 2.5 trillion deferred objects on one node, assuming all of them
are dentry (192 bytes per object), so the total size of deferred on one
node is ~480TB. It is definitely ridiculous.
I managed to reproduce this problem with kernel build workload plus
negative dentry generator.
First step, run the below kernel build test script:
NR_CPUS=`cat /proc/cpuinfo | grep -e processor | wc -l`
cd /root/Buildarea/linux-stable
for i in `seq 1500`; do
cgcreate -g memory:kern_build
echo 4G > /sys/fs/cgroup/memory/kern_build/memory.limit_in_bytes
echo 3 > /proc/sys/vm/drop_caches
cgexec -g memory:kern_build make clean > /dev/null 2>&1
cgexec -g memory:kern_build make -j$NR_CPUS > /dev/null 2>&1
cgdelete -g memory:kern_build
done
Then run the below negative dentry generator script:
NR_CPUS=`cat /proc/cpuinfo | grep -e processor | wc -l`
mkdir /sys/fs/cgroup/memory/test
echo $$ > /sys/fs/cgroup/memory/test/tasks
for i in `seq $NR_CPUS`; do
while true; do
FILE=`head /dev/urandom | tr -dc A-Za-z0-9 | head -c 64`
cat $FILE 2>/dev/null
done &
done
Then kswapd will shrink half of dentry cache in just one loop as the below
tracing result showed:
kswapd0-475 [028] .... 305968.252561: mm_shrink_slab_start: super_cache_scan+0x0/0x190 0000000024acf00c: nid: 0
objects to shrink 4994376020 gfp_flags GFP_KERNEL cache items 93689873 delta 45746 total_scan 46844936 priority 12
kswapd0-475 [021] .... 306013.099399: mm_shrink_slab_end: super_cache_scan+0x0/0x190 0000000024acf00c: nid: 0 unused
scan count 4994376020 new scan count 4947576838 total_scan 8 last shrinker return val 46844928
There were huge number of deferred objects before the shrinker was called,
the behavior does match the code but it might be not desirable from the
user's stand of point.
The excessive amount of nr_deferred might be accumulated due to various
reasons, for example:
* GFP_NOFS allocation
* Significant times of small amount scan (< scan_batch, 1024 for vfs
metadata)
However the LRUs of slabs are per memcg (memcg-aware shrinkers) but the
deferred objects is per shrinker, this may have some bad effects:
* Poor isolation among memcgs. Some memcgs which happen to have
frequent limit reclaim may get nr_deferred accumulated to a huge number,
then other innocent memcgs may take the fall. In our case the main
workload was hit.
* Unbounded deferred objects. There is no cap for deferred objects, it
can outgrow ridiculously as the tracing result showed.
* Easy to get out of control. Although shrinkers take into account
deferred objects, but it can go out of control easily. One
misconfigured memcg could incur absurd amount of deferred objects in a
period of time.
* Sort of reclaim problems, i.e. over reclaim, long reclaim latency,
etc. There may be hundred GB slab caches for vfe metadata heavy
workload, shrink half of them may take minutes. We observed latency
spike due to the prolonged reclaim.
These issues also have been discussed in
https://lore.kernel.org/linux-mm/20200916185823.5347-1-shy828301@gmail.com/.
The patchset is the outcome of that discussion.
So this patchset makes nr_deferred per-memcg to tackle the problem. It
does:
* Have memcg_shrinker_deferred per memcg per node, just like what
shrinker_map does. Instead it is an atomic_long_t array, each element
represent one shrinker even though the shrinker is not memcg aware, this
simplifies the implementation. For memcg aware shrinkers, the deferred
objects are just accumulated to its own memcg. The shrinkers just see
nr_deferred from its own memcg. Non memcg aware shrinkers still use
global nr_deferred from struct shrinker.
* Once the memcg is offlined, its nr_deferred will be reparented to its
parent along with LRUs.
* The root memcg has memcg_shrinker_deferred array too. It simplifies
the handling of reparenting to root memcg.
* Cap nr_deferred to 2x of the length of lru. The idea is borrowed from
Dave Chinner's series
(https://lore.kernel.org/linux-xfs/20191031234618.15403-1-david@fromorbit.com/)
The downside is each memcg has to allocate extra memory to store the
nr_deferred array. On our production environment, there are typically
around 40 shrinkers, so each memcg needs ~320 bytes. 10K memcgs would
need ~3.2MB memory. It seems fine.
We have been running the patched kernel on some hosts of our fleet (test
and production) for months, it works very well. The monitor data shows
the working set is sustained as expected.
This patch (of 13):
The tracepoint's nid should show what node the shrink happens on, the
start tracepoint uses nid from shrinkctl, but the nid might be set to 0
before end tracepoint if the shrinker is not NUMA aware, so the tracing
log may show the shrink happens on one node but end up on the other node.
It seems confusing. And the following patch will remove using nid
directly in do_shrink_slab(), this patch also helps cleanup the code.
Link: https://lkml.kernel.org/r/20210311190845.9708-1-shy828301@gmail.com
Link: https://lkml.kernel.org/r/20210311190845.9708-2-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Vlastimil Babka <redacted>
Acked-by: Kirill Tkhai <redacted>
Reviewed-by: Shakeel Butt <redacted>
Acked-by: Roman Gushchin <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/vmscan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:14
From: Yang Shi <redacted>
Subject: mm: vmscan: consolidate shrinker_maps handling code
The shrinker map management is not purely memcg specific, it is at the
intersection between memory cgroup and shrinkers. It's allocation and
assignment of a structure, and the only memcg bit is the map is being
stored in a memcg structure. So move the shrinker_maps handling code into
vmscan.c for tighter integration with shrinker code, and remove the
"memcg_" prefix. There is no functional change.
Link: https://lkml.kernel.org/r/20210311190845.9708-3-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Vlastimil Babka <redacted>
Acked-by: Kirill Tkhai <redacted>
Acked-by: Roman Gushchin <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/memcontrol.h | 11 +-
mm/huge_memory.c | 4 -
mm/list_lru.c | 6 -
mm/memcontrol.c | 130 ----------------------------------
mm/vmscan.c | 132 ++++++++++++++++++++++++++++++++++-
5 files changed, 142 insertions(+), 141 deletions(-)
@@ -125,8 +125,8 @@ bool list_lru_add(struct list_lru *lru,list_add_tail(item,&l->list);/* Set shrinker bit if the first element was added */if(!l->nr_items++)-memcg_set_shrinker_bit(memcg,nid,-lru_shrinker_id(lru));+set_shrinker_bit(memcg,nid,+lru_shrinker_id(lru));nlru->nr_items++;spin_unlock(&nlru->lock);returntrue;
@@ -400,130 +400,6 @@ DEFINE_STATIC_KEY_FALSE(memcg_kmem_enablEXPORT_SYMBOL(memcg_kmem_enabled_key);#endif-staticintmemcg_shrinker_map_size;-staticDEFINE_MUTEX(memcg_shrinker_map_mutex);--staticvoidmemcg_free_shrinker_map_rcu(structrcu_head*head)-{-kvfree(container_of(head,structmemcg_shrinker_map,rcu));-}--staticintmemcg_expand_one_shrinker_map(structmem_cgroup*memcg,-intsize,intold_size)-{-structmemcg_shrinker_map*new,*old;-structmem_cgroup_per_node*pn;-intnid;--lockdep_assert_held(&memcg_shrinker_map_mutex);--for_each_node(nid){-pn=memcg->nodeinfo[nid];-old=rcu_dereference_protected(pn->shrinker_map,true);-/* Not yet online memcg */-if(!old)-return0;--new=kvmalloc_node(sizeof(*new)+size,GFP_KERNEL,nid);-if(!new)-return-ENOMEM;--/* Set all old bits, clear all new bits */-memset(new->map,(int)0xff,old_size);-memset((void*)new->map+old_size,0,size-old_size);--rcu_assign_pointer(pn->shrinker_map,new);-call_rcu(&old->rcu,memcg_free_shrinker_map_rcu);-}--return0;-}--staticvoidmemcg_free_shrinker_maps(structmem_cgroup*memcg)-{-structmem_cgroup_per_node*pn;-structmemcg_shrinker_map*map;-intnid;--if(mem_cgroup_is_root(memcg))-return;--for_each_node(nid){-pn=memcg->nodeinfo[nid];-map=rcu_dereference_protected(pn->shrinker_map,true);-kvfree(map);-rcu_assign_pointer(pn->shrinker_map,NULL);-}-}--staticintmemcg_alloc_shrinker_maps(structmem_cgroup*memcg)-{-structmemcg_shrinker_map*map;-intnid,size,ret=0;--if(mem_cgroup_is_root(memcg))-return0;--mutex_lock(&memcg_shrinker_map_mutex);-size=memcg_shrinker_map_size;-for_each_node(nid){-map=kvzalloc_node(sizeof(*map)+size,GFP_KERNEL,nid);-if(!map){-memcg_free_shrinker_maps(memcg);-ret=-ENOMEM;-break;-}-rcu_assign_pointer(memcg->nodeinfo[nid]->shrinker_map,map);-}-mutex_unlock(&memcg_shrinker_map_mutex);--returnret;-}--intmemcg_expand_shrinker_maps(intnew_id)-{-intsize,old_size,ret=0;-structmem_cgroup*memcg;--size=DIV_ROUND_UP(new_id+1,BITS_PER_LONG)*sizeof(unsignedlong);-old_size=memcg_shrinker_map_size;-if(size<=old_size)-return0;--mutex_lock(&memcg_shrinker_map_mutex);-if(!root_mem_cgroup)-gotounlock;--for_each_mem_cgroup(memcg){-if(mem_cgroup_is_root(memcg))-continue;-ret=memcg_expand_one_shrinker_map(memcg,size,old_size);-if(ret){-mem_cgroup_iter_break(NULL,memcg);-gotounlock;-}-}-unlock:-if(!ret)-memcg_shrinker_map_size=size;-mutex_unlock(&memcg_shrinker_map_mutex);-returnret;-}--voidmemcg_set_shrinker_bit(structmem_cgroup*memcg,intnid,intshrinker_id)-{-if(shrinker_id>=0&&memcg&&!mem_cgroup_is_root(memcg)){-structmemcg_shrinker_map*map;--rcu_read_lock();-map=rcu_dereference(memcg->nodeinfo[nid]->shrinker_map);-/* Pairs with smp mb in shrink_slab() */-smp_mb__before_atomic();-set_bit(shrinker_id,map->map);-rcu_read_unlock();-}-}-/***mem_cgroup_css_from_page-cssofthememcgassociatedwithapage*@page:pageofinterest
@@ -5242,11 +5118,11 @@ static int mem_cgroup_css_online(structstructmem_cgroup*memcg=mem_cgroup_from_css(css);/*-*Amemcgmustbevisibleformemcg_expand_shrinker_maps()+*Amemcgmustbevisibleforexpand_shrinker_maps()*bythetimethemapsareallocated.So,weallocatemaps*here,whenfor_each_mem_cgroup()can'tskipit.*/-if(memcg_alloc_shrinker_maps(memcg)){+if(alloc_shrinker_maps(memcg)){mem_cgroup_id_remove(memcg);return-ENOMEM;}
@@ -185,6 +185,132 @@ static LIST_HEAD(shrinker_list);staticDECLARE_RWSEM(shrinker_rwsem);#ifdef CONFIG_MEMCG++staticintmemcg_shrinker_map_size;+staticDEFINE_MUTEX(memcg_shrinker_map_mutex);++staticvoidfree_shrinker_map_rcu(structrcu_head*head)+{+kvfree(container_of(head,structmemcg_shrinker_map,rcu));+}++staticintexpand_one_shrinker_map(structmem_cgroup*memcg,+intsize,intold_size)+{+structmemcg_shrinker_map*new,*old;+structmem_cgroup_per_node*pn;+intnid;++lockdep_assert_held(&memcg_shrinker_map_mutex);++for_each_node(nid){+pn=memcg->nodeinfo[nid];+old=rcu_dereference_protected(pn->shrinker_map,true);+/* Not yet online memcg */+if(!old)+return0;++new=kvmalloc_node(sizeof(*new)+size,GFP_KERNEL,nid);+if(!new)+return-ENOMEM;++/* Set all old bits, clear all new bits */+memset(new->map,(int)0xff,old_size);+memset((void*)new->map+old_size,0,size-old_size);++rcu_assign_pointer(pn->shrinker_map,new);+call_rcu(&old->rcu,free_shrinker_map_rcu);+}++return0;+}++voidfree_shrinker_maps(structmem_cgroup*memcg)+{+structmem_cgroup_per_node*pn;+structmemcg_shrinker_map*map;+intnid;++if(mem_cgroup_is_root(memcg))+return;++for_each_node(nid){+pn=memcg->nodeinfo[nid];+map=rcu_dereference_protected(pn->shrinker_map,true);+kvfree(map);+rcu_assign_pointer(pn->shrinker_map,NULL);+}+}++intalloc_shrinker_maps(structmem_cgroup*memcg)+{+structmemcg_shrinker_map*map;+intnid,size,ret=0;++if(mem_cgroup_is_root(memcg))+return0;++mutex_lock(&memcg_shrinker_map_mutex);+size=memcg_shrinker_map_size;+for_each_node(nid){+map=kvzalloc_node(sizeof(*map)+size,GFP_KERNEL,nid);+if(!map){+free_shrinker_maps(memcg);+ret=-ENOMEM;+break;+}+rcu_assign_pointer(memcg->nodeinfo[nid]->shrinker_map,map);+}+mutex_unlock(&memcg_shrinker_map_mutex);++returnret;+}++staticintexpand_shrinker_maps(intnew_id)+{+intsize,old_size,ret=0;+structmem_cgroup*memcg;++size=DIV_ROUND_UP(new_id+1,BITS_PER_LONG)*sizeof(unsignedlong);+old_size=memcg_shrinker_map_size;+if(size<=old_size)+return0;++mutex_lock(&memcg_shrinker_map_mutex);+if(!root_mem_cgroup)+gotounlock;++memcg=mem_cgroup_iter(NULL,NULL,NULL);+do{+if(mem_cgroup_is_root(memcg))+continue;+ret=expand_one_shrinker_map(memcg,size,old_size);+if(ret){+mem_cgroup_iter_break(NULL,memcg);+gotounlock;+}+}while((memcg=mem_cgroup_iter(NULL,memcg,NULL))!=NULL);+unlock:+if(!ret)+memcg_shrinker_map_size=size;+mutex_unlock(&memcg_shrinker_map_mutex);+returnret;+}++voidset_shrinker_bit(structmem_cgroup*memcg,intnid,intshrinker_id)+{+if(shrinker_id>=0&&memcg&&!mem_cgroup_is_root(memcg)){+structmemcg_shrinker_map*map;++rcu_read_lock();+map=rcu_dereference(memcg->nodeinfo[nid]->shrinker_map);+/* Pairs with smp mb in shrink_slab() */+smp_mb__before_atomic();+set_bit(shrinker_id,map->map);+rcu_read_unlock();+}+}+/**Weallowsubsystemstopopulatetheirshrinker-related*LRUlistsbeforeregister_shrinker_prepared()iscalled
@@ -212,7 +338,7 @@ static int prealloc_memcg_shrinker(strucgotounlock;if(id>=shrinker_nr_max){-if(memcg_expand_shrinker_maps(id)){+if(expand_shrinker_maps(id)){idr_remove(&shrinker_idr,id);gotounlock;}
@@ -590,7 +716,7 @@ static unsigned long shrink_slab_memcg(g*case,weinvoketheshrinkeronemoretimeandreset*thebitifitreportsthatitisnotemptyanymore.*Thememorybarrierherepairswiththebarrierin-*memcg_set_shrinker_bit():+*set_shrinker_bit():**list_lru_add()shrink_slab_memcg()*list_add_tail()clear_bit()
@@ -602,7 +728,7 @@ static unsigned long shrink_slab_memcg(gif(ret==SHRINK_EMPTY)ret=0;else-memcg_set_shrinker_bit(memcg,nid,i);+set_shrinker_bit(memcg,nid,i);}freed+=ret;
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:17
From: Yang Shi <redacted>
Subject: mm: vmscan: use shrinker_rwsem to protect shrinker_maps allocation
Since memcg_shrinker_map_size just can be changed under holding
shrinker_rwsem exclusively, the read side can be protected by holding read
lock, so it sounds superfluous to have a dedicated mutex.
Kirill Tkhai suggested use write lock since:
* We want the assignment to shrinker_maps is visible for shrink_slab_memcg().
* The rcu_dereference_protected() dereferrencing in shrink_slab_memcg(), but
in case of we use READ lock in alloc_shrinker_maps(), the dereferrencing
is not actually protected.
* READ lock makes alloc_shrinker_info() racy against memory allocation fail.
alloc_shrinker_info()->free_shrinker_info() may free memory right after
shrink_slab_memcg() dereferenced it. You may say
shrink_slab_memcg()->mem_cgroup_online() protects us from it? Yes, sure,
but this is not the thing we want to remember in the future, since this
spreads modularity.
And a test with heavy paging workload didn't show write lock makes things worse.
Link: https://lkml.kernel.org/r/20210311190845.9708-4-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Vlastimil Babka <redacted>
Acked-by: Kirill Tkhai <redacted>
Acked-by: Roman Gushchin <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/vmscan.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:20
From: Yang Shi <redacted>
Subject: mm: vmscan: remove memcg_shrinker_map_size
Both memcg_shrinker_map_size and shrinker_nr_max is maintained, but
actually the map size can be calculated via shrinker_nr_max, so it seems
unnecessary to keep both. Remove memcg_shrinker_map_size since
shrinker_nr_max is also used by iterating the bit map.
Link: https://lkml.kernel.org/r/20210311190845.9708-5-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Kirill Tkhai <redacted>
Acked-by: Roman Gushchin <redacted>
Acked-by: Vlastimil Babka <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/vmscan.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:23
From: Yang Shi <redacted>
Subject: mm: vmscan: use kvfree_rcu instead of call_rcu
Using kvfree_rcu() to free the old shrinker_maps instead of call_rcu().
We don't have to define a dedicated callback for call_rcu() anymore.
Link: https://lkml.kernel.org/r/20210311190845.9708-6-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Roman Gushchin <redacted>
Acked-by: Kirill Tkhai <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/vmscan.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:26
From: Yang Shi <redacted>
Subject: mm: memcontrol: rename shrinker_map to shrinker_info
The following patch is going to add nr_deferred into shrinker_map, the
change will make shrinker_map not only include map anymore, so rename it
to "memcg_shrinker_info". And this should make the patch adding
nr_deferred cleaner and readable and make review easier. Also remove the
"memcg_" prefix.
Link: https://lkml.kernel.org/r/20210311190845.9708-7-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Vlastimil Babka <redacted>
Acked-by: Kirill Tkhai <redacted>
Acked-by: Roman Gushchin <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/memcontrol.h | 8 ++--
mm/memcontrol.c | 6 +--
mm/vmscan.c | 58 +++++++++++++++++------------------
3 files changed, 36 insertions(+), 36 deletions(-)
@@ -145,7 +145,7 @@ struct mem_cgroup_per_node {structmem_cgroup_reclaim_iteriter;-structmemcg_shrinker_map__rcu*shrinker_map;+structshrinker_info__rcu*shrinker_info;structrb_nodetree_node;/* RB tree node */unsignedlongusage_in_excess;/* Set to the value by which */
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:29
From: Yang Shi <redacted>
Subject: mm: vmscan: add shrinker_info_protected() helper
The shrinker_info is dereferenced in a couple of places via
rcu_dereference_protected with different calling conventions, for example,
using mem_cgroup_nodeinfo helper or dereferencing
memcg->nodeinfo[nid]->shrinker_info. And the later patch will add more
dereference places.
So extract the dereference into a helper to make the code more readable.
No functional change.
[akpm@linux-foundation.org: retain rcu_dereference_protected() in free_shrinker_info(), per Hugh]
Link: https://lkml.kernel.org/r/20210311190845.9708-8-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Roman Gushchin <redacted>
Acked-by: Kirill Tkhai <redacted>
Acked-by: Vlastimil Babka <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/vmscan.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:32
From: Yang Shi <redacted>
Subject: mm: vmscan: use a new flag to indicate shrinker is registered
Currently registered shrinker is indicated by non-NULL
shrinker->nr_deferred. This approach is fine with nr_deferred at the
shrinker level, but the following patches will move MEMCG_AWARE shrinkers'
nr_deferred to memcg level, so their shrinker->nr_deferred would always be
NULL. This would prevent the shrinkers from unregistering correctly.
Remove SHRINKER_REGISTERING since we could check if shrinker is registered
successfully by the new flag.
Link: https://lkml.kernel.org/r/20210311190845.9708-9-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Kirill Tkhai <redacted>
Acked-by: Vlastimil Babka <redacted>
Acked-by: Roman Gushchin <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/shrinker.h | 7 +++---
mm/vmscan.c | 40 +++++++++++++------------------------
2 files changed, 19 insertions(+), 28 deletions(-)
@@ -337,7 +324,7 @@ static int prealloc_memcg_shrinker(strucdown_write(&shrinker_rwsem);/* This may call shrinker, so it must use down_read_trylock() */-id=idr_alloc(&shrinker_idr,SHRINKER_REGISTERING,0,0,GFP_KERNEL);+id=idr_alloc(&shrinker_idr,shrinker,0,0,GFP_KERNEL);if(id<0)gotounlock;
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:36
From: Yang Shi <redacted>
Subject: mm: vmscan: add per memcg shrinker nr_deferred
Currently the number of deferred objects are per shrinker, but some slabs,
for example, vfs inode/dentry cache are per memcg, this would result in
poor isolation among memcgs.
The deferred objects typically are generated by __GFP_NOFS allocations,
one memcg with excessive __GFP_NOFS allocations may blow up deferred
objects, then other innocent memcgs may suffer from over shrink, excessive
reclaim latency, etc.
For example, two workloads run in memcgA and memcgB respectively, workload
in B is vfs heavy workload. Workload in A generates excessive deferred
objects, then B's vfs cache might be hit heavily (drop half of caches) by
B's limit reclaim or global reclaim.
We observed this hit in our production environment which was running vfs
heavy workload shown as the below tracing log:
<...>-409454 [016] .... 28286961.747146: mm_shrink_slab_start: super_cache_scan+0x0/0x1a0 ffff9a83046f3458:
nid: 1 objects to shrink 3641681686040 gfp_flags GFP_HIGHUSER_MOVABLE|__GFP_ZERO pgs_scanned 1 lru_pgs 15721
cache items 246404277 delta 31345 total_scan 123202138
<...>-409454 [022] .... 28287105.928018: mm_shrink_slab_end: super_cache_scan+0x0/0x1a0 ffff9a83046f3458:
nid: 1 unused scan count 3641681686040 new scan count 3641798379189 total_scan 602
last shrinker return val 123186855
The vfs cache and page cache ratio was 10:1 on this machine, and half of
caches were dropped. This also resulted in significant amount of page
caches were dropped due to inodes eviction.
Make nr_deferred per memcg for memcg aware shrinkers would solve the
unfairness and bring better isolation.
The following patch will add nr_deferred to parent memcg when memcg
offline. To preserve nr_deferred when reparenting memcgs to root, root
memcg needs shrinker_info allocated too.
When memcg is not enabled (!CONFIG_MEMCG or memcg disabled), the
shrinker's nr_deferred would be used. And non memcg aware shrinkers use
shrinker's nr_deferred all the time.
Link: https://lkml.kernel.org/r/20210311190845.9708-10-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Roman Gushchin <redacted>
Acked-by: Kirill Tkhai <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
include/linux/memcontrol.h | 7 ++--
mm/vmscan.c | 60 ++++++++++++++++++++++++-----------
2 files changed, 46 insertions(+), 21 deletions(-)
@@ -187,11 +187,17 @@ static DECLARE_RWSEM(shrinker_rwsem);#ifdef CONFIG_MEMCGstaticintshrinker_nr_max;+/* The shrinker_info is expanded in a batch of BITS_PER_LONG */staticinlineintshrinker_map_size(intnr_items){return(DIV_ROUND_UP(nr_items,BITS_PER_LONG)*sizeof(unsignedlong));}+staticinlineintshrinker_defer_size(intnr_items)+{+return(round_up(nr_items,BITS_PER_LONG)*sizeof(atomic_long_t));+}+staticstructshrinker_info*shrinker_info_protected(structmem_cgroup*memcg,intnid){
@@ -217,9 +225,16 @@ static int expand_one_shrinker_info(struif(!new)return-ENOMEM;-/* Set all old bits, clear all new bits */-memset(new->map,(int)0xff,old_size);-memset((void*)new->map+old_size,0,size-old_size);+new->nr_deferred=(atomic_long_t*)(new+1);+new->map=(void*)new->nr_deferred+defer_size;++/* map: set all old bits, clear all new bits */+memset(new->map,(int)0xff,old_map_size);+memset((void*)new->map+old_map_size,0,map_size-old_map_size);+/* nr_deferred: copy old values, clear all new values */+memcpy(new->nr_deferred,old->nr_deferred,old_defer_size);+memset((void*)new->nr_deferred+old_defer_size,0,+defer_size-old_defer_size);rcu_assign_pointer(pn->shrinker_info,new);kvfree_rcu(old,rcu);
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:39
From: Yang Shi <redacted>
Subject: mm: vmscan: use per memcg nr_deferred of shrinker
Use per memcg's nr_deferred for memcg aware shrinkers. The shrinker's
nr_deferred will be used in the following cases:
1. Non memcg aware shrinkers
2. !CONFIG_MEMCG
3. memcg is disabled by boot parameter
Link: https://lkml.kernel.org/r/20210311190845.9708-11-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Roman Gushchin <redacted>
Acked-by: Kirill Tkhai <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/vmscan.c | 78 ++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 66 insertions(+), 12 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:42
From: Yang Shi <redacted>
Subject: mm: vmscan: don't need allocate shrinker->nr_deferred for memcg aware shrinkers
Now nr_deferred is available on per memcg level for memcg aware shrinkers,
so don't need allocate shrinker->nr_deferred for such shrinkers anymore.
The prealloc_memcg_shrinker() would return -ENOSYS if !CONFIG_MEMCG or
memcg is disabled by kernel command line, then shrinker's
SHRINKER_MEMCG_AWARE flag would be cleared. This makes the implementation
of this patch simpler.
Link: https://lkml.kernel.org/r/20210311190845.9708-12-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Acked-by: Vlastimil Babka <redacted>
Reviewed-by: Kirill Tkhai <redacted>
Acked-by: Roman Gushchin <redacted>
Reviewed-by: Shakeel Butt <redacted>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/vmscan.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
@@ -346,6 +346,9 @@ static int prealloc_memcg_shrinker(struc{intid,ret=-ENOMEM;+if(mem_cgroup_disabled())+return-ENOSYS;+down_write(&shrinker_rwsem);/* This may call shrinker, so it must use down_read_trylock() */id=idr_alloc(&shrinker_idr,shrinker,0,0,GFP_KERNEL);
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-05-05 01:36:48
From: Yang Shi <redacted>
Subject: mm: vmscan: shrink deferred objects proportional to priority
The number of deferred objects might get windup to an absurd number, and
it results in clamp of slab objects. It is undesirable for sustaining
workingset.
So shrink deferred objects proportional to priority and cap nr_deferred to
twice of cache items.
The idea is borrowed from Dave Chinner's patch:
https://lore.kernel.org/linux-xfs/20191031234618.15403-13-david@fromorbit.com/
Tested with kernel build and vfs metadata heavy workload in our production
environment, no regression is spotted so far.
Link: https://lkml.kernel.org/r/20210311190845.9708-14-shy828301@gmail.com
Signed-off-by: Yang Shi <redacted>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Kirill Tkhai <redacted>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Roman Gushchin <redacted>
Cc: Shakeel Butt <redacted>
Cc: Vlastimil Babka <redacted>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
mm/vmscan.c | 46 +++++++++++-----------------------------------
1 file changed, 11 insertions(+), 35 deletions(-)