Commit f9aaa5b0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'akpm' (patches from Andrew)

Merge misc fixes from Andrew Morton:
 "10 patches.

  Subsystems affected by this patch series: ipc, MAINTAINERS, and mm
  (vmscan, debug, pagemap, kmemleak, and selftests)"

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  kselftest/vm: revert "tools/testing/selftests/vm/userfaultfd.c: use swap() to make code cleaner"
  MAINTAINERS: update rppt's email
  mm/kmemleak: avoid scanning potential huge holes
  ipc/sem: do not sleep with a spin lock held
  mm/pgtable: define pte_index so that preprocessor could recognize it
  mm/page_table_check: check entries at pmd levels
  mm/khugepaged: unify collapse pmd clear, flush and free
  mm/page_table_check: use unsigned long for page counters and cleanup
  mm/debug_vm_pgtable: remove pte entry from the page table
  Revert "mm/page_isolation: unset migratetype directly for non Buddy page"
parents cff7f223 07d2505b
...@@ -12399,7 +12399,7 @@ F: include/uapi/linux/membarrier.h ...@@ -12399,7 +12399,7 @@ F: include/uapi/linux/membarrier.h
F: kernel/sched/membarrier.c F: kernel/sched/membarrier.c
MEMBLOCK MEMBLOCK
M: Mike Rapoport <rppt@linux.ibm.com> M: Mike Rapoport <rppt@kernel.org>
L: linux-mm@kvack.org L: linux-mm@kvack.org
S: Maintained S: Maintained
F: Documentation/core-api/boot-time-mm.rst F: Documentation/core-api/boot-time-mm.rst
......
...@@ -26,6 +26,9 @@ void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr, ...@@ -26,6 +26,9 @@ void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t pmd); pmd_t *pmdp, pmd_t pmd);
void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr, void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
pud_t *pudp, pud_t pud); pud_t *pudp, pud_t pud);
void __page_table_check_pte_clear_range(struct mm_struct *mm,
unsigned long addr,
pmd_t pmd);
static inline void page_table_check_alloc(struct page *page, unsigned int order) static inline void page_table_check_alloc(struct page *page, unsigned int order)
{ {
...@@ -100,6 +103,16 @@ static inline void page_table_check_pud_set(struct mm_struct *mm, ...@@ -100,6 +103,16 @@ static inline void page_table_check_pud_set(struct mm_struct *mm,
__page_table_check_pud_set(mm, addr, pudp, pud); __page_table_check_pud_set(mm, addr, pudp, pud);
} }
static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
unsigned long addr,
pmd_t pmd)
{
if (static_branch_likely(&page_table_check_disabled))
return;
__page_table_check_pte_clear_range(mm, addr, pmd);
}
#else #else
static inline void page_table_check_alloc(struct page *page, unsigned int order) static inline void page_table_check_alloc(struct page *page, unsigned int order)
...@@ -143,5 +156,11 @@ static inline void page_table_check_pud_set(struct mm_struct *mm, ...@@ -143,5 +156,11 @@ static inline void page_table_check_pud_set(struct mm_struct *mm,
{ {
} }
static inline void page_table_check_pte_clear_range(struct mm_struct *mm,
unsigned long addr,
pmd_t pmd)
{
}
#endif /* CONFIG_PAGE_TABLE_CHECK */ #endif /* CONFIG_PAGE_TABLE_CHECK */
#endif /* __LINUX_PAGE_TABLE_CHECK_H */ #endif /* __LINUX_PAGE_TABLE_CHECK_H */
...@@ -62,6 +62,7 @@ static inline unsigned long pte_index(unsigned long address) ...@@ -62,6 +62,7 @@ static inline unsigned long pte_index(unsigned long address)
{ {
return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
} }
#define pte_index pte_index
#ifndef pmd_index #ifndef pmd_index
static inline unsigned long pmd_index(unsigned long address) static inline unsigned long pmd_index(unsigned long address)
......
...@@ -1964,6 +1964,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) ...@@ -1964,6 +1964,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
*/ */
un = lookup_undo(ulp, semid); un = lookup_undo(ulp, semid);
if (un) { if (un) {
spin_unlock(&ulp->lock);
kvfree(new); kvfree(new);
goto success; goto success;
} }
...@@ -1976,9 +1977,8 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid) ...@@ -1976,9 +1977,8 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
ipc_assert_locked_object(&sma->sem_perm); ipc_assert_locked_object(&sma->sem_perm);
list_add(&new->list_id, &sma->list_id); list_add(&new->list_id, &sma->list_id);
un = new; un = new;
success:
spin_unlock(&ulp->lock); spin_unlock(&ulp->lock);
success:
sem_unlock(sma, -1); sem_unlock(sma, -1);
out: out:
return un; return un;
......
...@@ -171,6 +171,8 @@ static void __init pte_advanced_tests(struct pgtable_debug_args *args) ...@@ -171,6 +171,8 @@ static void __init pte_advanced_tests(struct pgtable_debug_args *args)
ptep_test_and_clear_young(args->vma, args->vaddr, args->ptep); ptep_test_and_clear_young(args->vma, args->vaddr, args->ptep);
pte = ptep_get(args->ptep); pte = ptep_get(args->ptep);
WARN_ON(pte_young(pte)); WARN_ON(pte_young(pte));
ptep_get_and_clear_full(args->mm, args->vaddr, args->ptep, 1);
} }
static void __init pte_savedwrite_tests(struct pgtable_debug_args *args) static void __init pte_savedwrite_tests(struct pgtable_debug_args *args)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/userfaultfd_k.h> #include <linux/userfaultfd_k.h>
#include <linux/page_idle.h> #include <linux/page_idle.h>
#include <linux/page_table_check.h>
#include <linux/swapops.h> #include <linux/swapops.h>
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
...@@ -1416,6 +1417,21 @@ static int khugepaged_add_pte_mapped_thp(struct mm_struct *mm, ...@@ -1416,6 +1417,21 @@ static int khugepaged_add_pte_mapped_thp(struct mm_struct *mm,
return 0; return 0;
} }
static void collapse_and_free_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, pmd_t *pmdp)
{
spinlock_t *ptl;
pmd_t pmd;
mmap_assert_write_locked(mm);
ptl = pmd_lock(vma->vm_mm, pmdp);
pmd = pmdp_collapse_flush(vma, addr, pmdp);
spin_unlock(ptl);
mm_dec_nr_ptes(mm);
page_table_check_pte_clear_range(mm, addr, pmd);
pte_free(mm, pmd_pgtable(pmd));
}
/** /**
* collapse_pte_mapped_thp - Try to collapse a pte-mapped THP for mm at * collapse_pte_mapped_thp - Try to collapse a pte-mapped THP for mm at
* address haddr. * address haddr.
...@@ -1433,7 +1449,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr) ...@@ -1433,7 +1449,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
struct vm_area_struct *vma = find_vma(mm, haddr); struct vm_area_struct *vma = find_vma(mm, haddr);
struct page *hpage; struct page *hpage;
pte_t *start_pte, *pte; pte_t *start_pte, *pte;
pmd_t *pmd, _pmd; pmd_t *pmd;
spinlock_t *ptl; spinlock_t *ptl;
int count = 0; int count = 0;
int i; int i;
...@@ -1509,12 +1525,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr) ...@@ -1509,12 +1525,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
} }
/* step 4: collapse pmd */ /* step 4: collapse pmd */
ptl = pmd_lock(vma->vm_mm, pmd); collapse_and_free_pmd(mm, vma, haddr, pmd);
_pmd = pmdp_collapse_flush(vma, haddr, pmd);
spin_unlock(ptl);
mm_dec_nr_ptes(mm);
pte_free(mm, pmd_pgtable(_pmd));
drop_hpage: drop_hpage:
unlock_page(hpage); unlock_page(hpage);
put_page(hpage); put_page(hpage);
...@@ -1552,7 +1563,7 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff) ...@@ -1552,7 +1563,7 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct mm_struct *mm; struct mm_struct *mm;
unsigned long addr; unsigned long addr;
pmd_t *pmd, _pmd; pmd_t *pmd;
i_mmap_lock_write(mapping); i_mmap_lock_write(mapping);
vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) { vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
...@@ -1591,14 +1602,8 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff) ...@@ -1591,14 +1602,8 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
* reverse order. Trylock is a way to avoid deadlock. * reverse order. Trylock is a way to avoid deadlock.
*/ */
if (mmap_write_trylock(mm)) { if (mmap_write_trylock(mm)) {
if (!khugepaged_test_exit(mm)) { if (!khugepaged_test_exit(mm))
spinlock_t *ptl = pmd_lock(mm, pmd); collapse_and_free_pmd(mm, vma, addr, pmd);
/* assume page table is clear */
_pmd = pmdp_collapse_flush(vma, addr, pmd);
spin_unlock(ptl);
mm_dec_nr_ptes(mm);
pte_free(mm, pmd_pgtable(_pmd));
}
mmap_write_unlock(mm); mmap_write_unlock(mm);
} else { } else {
/* Try again later */ /* Try again later */
......
...@@ -1410,7 +1410,8 @@ static void kmemleak_scan(void) ...@@ -1410,7 +1410,8 @@ static void kmemleak_scan(void)
{ {
unsigned long flags; unsigned long flags;
struct kmemleak_object *object; struct kmemleak_object *object;
int i; struct zone *zone;
int __maybe_unused i;
int new_leaks = 0; int new_leaks = 0;
jiffies_last_scan = jiffies; jiffies_last_scan = jiffies;
...@@ -1450,9 +1451,9 @@ static void kmemleak_scan(void) ...@@ -1450,9 +1451,9 @@ static void kmemleak_scan(void)
* Struct page scanning for each node. * Struct page scanning for each node.
*/ */
get_online_mems(); get_online_mems();
for_each_online_node(i) { for_each_populated_zone(zone) {
unsigned long start_pfn = node_start_pfn(i); unsigned long start_pfn = zone->zone_start_pfn;
unsigned long end_pfn = node_end_pfn(i); unsigned long end_pfn = zone_end_pfn(zone);
unsigned long pfn; unsigned long pfn;
for (pfn = start_pfn; pfn < end_pfn; pfn++) { for (pfn = start_pfn; pfn < end_pfn; pfn++) {
...@@ -1461,8 +1462,8 @@ static void kmemleak_scan(void) ...@@ -1461,8 +1462,8 @@ static void kmemleak_scan(void)
if (!page) if (!page)
continue; continue;
/* only scan pages belonging to this node */ /* only scan pages belonging to this zone */
if (page_to_nid(page) != i) if (page_zone(page) != zone)
continue; continue;
/* only scan if page is in use */ /* only scan if page is in use */
if (page_count(page) == 0) if (page_count(page) == 0)
......
...@@ -115,7 +115,7 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype) ...@@ -115,7 +115,7 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
* onlining - just onlined memory won't immediately be considered for * onlining - just onlined memory won't immediately be considered for
* allocation. * allocation.
*/ */
if (!isolated_page && PageBuddy(page)) { if (!isolated_page) {
nr_pages = move_freepages_block(zone, page, migratetype, NULL); nr_pages = move_freepages_block(zone, page, migratetype, NULL);
__mod_zone_freepage_state(zone, nr_pages, migratetype); __mod_zone_freepage_state(zone, nr_pages, migratetype);
} }
......
...@@ -86,8 +86,8 @@ static void page_table_check_clear(struct mm_struct *mm, unsigned long addr, ...@@ -86,8 +86,8 @@ static void page_table_check_clear(struct mm_struct *mm, unsigned long addr,
{ {
struct page_ext *page_ext; struct page_ext *page_ext;
struct page *page; struct page *page;
unsigned long i;
bool anon; bool anon;
int i;
if (!pfn_valid(pfn)) if (!pfn_valid(pfn))
return; return;
...@@ -121,8 +121,8 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr, ...@@ -121,8 +121,8 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
{ {
struct page_ext *page_ext; struct page_ext *page_ext;
struct page *page; struct page *page;
unsigned long i;
bool anon; bool anon;
int i;
if (!pfn_valid(pfn)) if (!pfn_valid(pfn))
return; return;
...@@ -152,10 +152,10 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr, ...@@ -152,10 +152,10 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
void __page_table_check_zero(struct page *page, unsigned int order) void __page_table_check_zero(struct page *page, unsigned int order)
{ {
struct page_ext *page_ext = lookup_page_ext(page); struct page_ext *page_ext = lookup_page_ext(page);
int i; unsigned long i;
BUG_ON(!page_ext); BUG_ON(!page_ext);
for (i = 0; i < (1 << order); i++) { for (i = 0; i < (1ul << order); i++) {
struct page_table_check *ptc = get_page_table_check(page_ext); struct page_table_check *ptc = get_page_table_check(page_ext);
BUG_ON(atomic_read(&ptc->anon_map_count)); BUG_ON(atomic_read(&ptc->anon_map_count));
...@@ -206,17 +206,10 @@ EXPORT_SYMBOL(__page_table_check_pud_clear); ...@@ -206,17 +206,10 @@ EXPORT_SYMBOL(__page_table_check_pud_clear);
void __page_table_check_pte_set(struct mm_struct *mm, unsigned long addr, void __page_table_check_pte_set(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte) pte_t *ptep, pte_t pte)
{ {
pte_t old_pte;
if (&init_mm == mm) if (&init_mm == mm)
return; return;
old_pte = *ptep; __page_table_check_pte_clear(mm, addr, *ptep);
if (pte_user_accessible_page(old_pte)) {
page_table_check_clear(mm, addr, pte_pfn(old_pte),
PAGE_SIZE >> PAGE_SHIFT);
}
if (pte_user_accessible_page(pte)) { if (pte_user_accessible_page(pte)) {
page_table_check_set(mm, addr, pte_pfn(pte), page_table_check_set(mm, addr, pte_pfn(pte),
PAGE_SIZE >> PAGE_SHIFT, PAGE_SIZE >> PAGE_SHIFT,
...@@ -228,17 +221,10 @@ EXPORT_SYMBOL(__page_table_check_pte_set); ...@@ -228,17 +221,10 @@ EXPORT_SYMBOL(__page_table_check_pte_set);
void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr, void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t pmd) pmd_t *pmdp, pmd_t pmd)
{ {
pmd_t old_pmd;
if (&init_mm == mm) if (&init_mm == mm)
return; return;
old_pmd = *pmdp; __page_table_check_pmd_clear(mm, addr, *pmdp);
if (pmd_user_accessible_page(old_pmd)) {
page_table_check_clear(mm, addr, pmd_pfn(old_pmd),
PMD_PAGE_SIZE >> PAGE_SHIFT);
}
if (pmd_user_accessible_page(pmd)) { if (pmd_user_accessible_page(pmd)) {
page_table_check_set(mm, addr, pmd_pfn(pmd), page_table_check_set(mm, addr, pmd_pfn(pmd),
PMD_PAGE_SIZE >> PAGE_SHIFT, PMD_PAGE_SIZE >> PAGE_SHIFT,
...@@ -250,17 +236,10 @@ EXPORT_SYMBOL(__page_table_check_pmd_set); ...@@ -250,17 +236,10 @@ EXPORT_SYMBOL(__page_table_check_pmd_set);
void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr, void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
pud_t *pudp, pud_t pud) pud_t *pudp, pud_t pud)
{ {
pud_t old_pud;
if (&init_mm == mm) if (&init_mm == mm)
return; return;
old_pud = *pudp; __page_table_check_pud_clear(mm, addr, *pudp);
if (pud_user_accessible_page(old_pud)) {
page_table_check_clear(mm, addr, pud_pfn(old_pud),
PUD_PAGE_SIZE >> PAGE_SHIFT);
}
if (pud_user_accessible_page(pud)) { if (pud_user_accessible_page(pud)) {
page_table_check_set(mm, addr, pud_pfn(pud), page_table_check_set(mm, addr, pud_pfn(pud),
PUD_PAGE_SIZE >> PAGE_SHIFT, PUD_PAGE_SIZE >> PAGE_SHIFT,
...@@ -268,3 +247,23 @@ void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr, ...@@ -268,3 +247,23 @@ void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
} }
} }
EXPORT_SYMBOL(__page_table_check_pud_set); EXPORT_SYMBOL(__page_table_check_pud_set);
void __page_table_check_pte_clear_range(struct mm_struct *mm,
unsigned long addr,
pmd_t pmd)
{
if (&init_mm == mm)
return;
if (!pmd_bad(pmd) && !pmd_leaf(pmd)) {
pte_t *ptep = pte_offset_map(&pmd, addr);
unsigned long i;
pte_unmap(ptep);
for (i = 0; i < PTRS_PER_PTE; i++) {
__page_table_check_pte_clear(mm, addr, *ptep);
addr += PAGE_SIZE;
ptep++;
}
}
}
...@@ -1417,6 +1417,7 @@ static void userfaultfd_pagemap_test(unsigned int test_pgsize) ...@@ -1417,6 +1417,7 @@ static void userfaultfd_pagemap_test(unsigned int test_pgsize)
static int userfaultfd_stress(void) static int userfaultfd_stress(void)
{ {
void *area; void *area;
char *tmp_area;
unsigned long nr; unsigned long nr;
struct uffdio_register uffdio_register; struct uffdio_register uffdio_register;
struct uffd_stats uffd_stats[nr_cpus]; struct uffd_stats uffd_stats[nr_cpus];
...@@ -1527,9 +1528,13 @@ static int userfaultfd_stress(void) ...@@ -1527,9 +1528,13 @@ static int userfaultfd_stress(void)
count_verify[nr], nr); count_verify[nr], nr);
/* prepare next bounce */ /* prepare next bounce */
swap(area_src, area_dst); tmp_area = area_src;
area_src = area_dst;
area_dst = tmp_area;
swap(area_src_alias, area_dst_alias); tmp_area = area_src_alias;
area_src_alias = area_dst_alias;
area_dst_alias = tmp_area;
uffd_stats_report(uffd_stats, nr_cpus); uffd_stats_report(uffd_stats, nr_cpus);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment