forked from Minki/linux
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"
This commit is contained in:
commit
f9aaa5b05e
@ -12399,7 +12399,7 @@ F: include/uapi/linux/membarrier.h
|
||||
F: kernel/sched/membarrier.c
|
||||
|
||||
MEMBLOCK
|
||||
M: Mike Rapoport <rppt@linux.ibm.com>
|
||||
M: Mike Rapoport <rppt@kernel.org>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
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,
|
||||
pmd_t *pmdp, pmd_t pmd);
|
||||
void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
|
||||
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)
|
||||
{
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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,
|
||||
{
|
||||
}
|
||||
|
||||
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 /* __LINUX_PAGE_TABLE_CHECK_H */
|
||||
|
@ -62,6 +62,7 @@ static inline unsigned long pte_index(unsigned long address)
|
||||
{
|
||||
return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
|
||||
}
|
||||
#define pte_index pte_index
|
||||
|
||||
#ifndef pmd_index
|
||||
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)
|
||||
*/
|
||||
un = lookup_undo(ulp, semid);
|
||||
if (un) {
|
||||
spin_unlock(&ulp->lock);
|
||||
kvfree(new);
|
||||
goto success;
|
||||
}
|
||||
@ -1976,9 +1977,8 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
|
||||
ipc_assert_locked_object(&sma->sem_perm);
|
||||
list_add(&new->list_id, &sma->list_id);
|
||||
un = new;
|
||||
|
||||
success:
|
||||
spin_unlock(&ulp->lock);
|
||||
success:
|
||||
sem_unlock(sma, -1);
|
||||
out:
|
||||
return un;
|
||||
|
@ -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);
|
||||
pte = ptep_get(args->ptep);
|
||||
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)
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/userfaultfd_k.h>
|
||||
#include <linux/page_idle.h>
|
||||
#include <linux/page_table_check.h>
|
||||
#include <linux/swapops.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
|
||||
@ -1416,6 +1417,21 @@ static int khugepaged_add_pte_mapped_thp(struct mm_struct *mm,
|
||||
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
|
||||
* address haddr.
|
||||
@ -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 page *hpage;
|
||||
pte_t *start_pte, *pte;
|
||||
pmd_t *pmd, _pmd;
|
||||
pmd_t *pmd;
|
||||
spinlock_t *ptl;
|
||||
int count = 0;
|
||||
int i;
|
||||
@ -1509,12 +1525,7 @@ void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr)
|
||||
}
|
||||
|
||||
/* step 4: collapse pmd */
|
||||
ptl = pmd_lock(vma->vm_mm, pmd);
|
||||
_pmd = pmdp_collapse_flush(vma, haddr, pmd);
|
||||
spin_unlock(ptl);
|
||||
mm_dec_nr_ptes(mm);
|
||||
pte_free(mm, pmd_pgtable(_pmd));
|
||||
|
||||
collapse_and_free_pmd(mm, vma, haddr, pmd);
|
||||
drop_hpage:
|
||||
unlock_page(hpage);
|
||||
put_page(hpage);
|
||||
@ -1552,7 +1563,7 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
|
||||
struct vm_area_struct *vma;
|
||||
struct mm_struct *mm;
|
||||
unsigned long addr;
|
||||
pmd_t *pmd, _pmd;
|
||||
pmd_t *pmd;
|
||||
|
||||
i_mmap_lock_write(mapping);
|
||||
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)
|
||||
* reverse order. Trylock is a way to avoid deadlock.
|
||||
*/
|
||||
if (mmap_write_trylock(mm)) {
|
||||
if (!khugepaged_test_exit(mm)) {
|
||||
spinlock_t *ptl = pmd_lock(mm, 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));
|
||||
}
|
||||
if (!khugepaged_test_exit(mm))
|
||||
collapse_and_free_pmd(mm, vma, addr, pmd);
|
||||
mmap_write_unlock(mm);
|
||||
} else {
|
||||
/* Try again later */
|
||||
|
@ -1410,7 +1410,8 @@ static void kmemleak_scan(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kmemleak_object *object;
|
||||
int i;
|
||||
struct zone *zone;
|
||||
int __maybe_unused i;
|
||||
int new_leaks = 0;
|
||||
|
||||
jiffies_last_scan = jiffies;
|
||||
@ -1450,9 +1451,9 @@ static void kmemleak_scan(void)
|
||||
* Struct page scanning for each node.
|
||||
*/
|
||||
get_online_mems();
|
||||
for_each_online_node(i) {
|
||||
unsigned long start_pfn = node_start_pfn(i);
|
||||
unsigned long end_pfn = node_end_pfn(i);
|
||||
for_each_populated_zone(zone) {
|
||||
unsigned long start_pfn = zone->zone_start_pfn;
|
||||
unsigned long end_pfn = zone_end_pfn(zone);
|
||||
unsigned long pfn;
|
||||
|
||||
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
|
||||
@ -1461,8 +1462,8 @@ static void kmemleak_scan(void)
|
||||
if (!page)
|
||||
continue;
|
||||
|
||||
/* only scan pages belonging to this node */
|
||||
if (page_to_nid(page) != i)
|
||||
/* only scan pages belonging to this zone */
|
||||
if (page_zone(page) != zone)
|
||||
continue;
|
||||
/* only scan if page is in use */
|
||||
if (page_count(page) == 0)
|
||||
|
@ -115,7 +115,7 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
|
||||
* onlining - just onlined memory won't immediately be considered for
|
||||
* allocation.
|
||||
*/
|
||||
if (!isolated_page && PageBuddy(page)) {
|
||||
if (!isolated_page) {
|
||||
nr_pages = move_freepages_block(zone, page, migratetype, NULL);
|
||||
__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,
|
||||
{
|
||||
struct page_ext *page_ext;
|
||||
struct page *page;
|
||||
unsigned long i;
|
||||
bool anon;
|
||||
int i;
|
||||
|
||||
if (!pfn_valid(pfn))
|
||||
return;
|
||||
@ -121,8 +121,8 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
|
||||
{
|
||||
struct page_ext *page_ext;
|
||||
struct page *page;
|
||||
unsigned long i;
|
||||
bool anon;
|
||||
int i;
|
||||
|
||||
if (!pfn_valid(pfn))
|
||||
return;
|
||||
@ -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)
|
||||
{
|
||||
struct page_ext *page_ext = lookup_page_ext(page);
|
||||
int i;
|
||||
unsigned long i;
|
||||
|
||||
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);
|
||||
|
||||
BUG_ON(atomic_read(&ptc->anon_map_count));
|
||||
@ -206,17 +206,10 @@ EXPORT_SYMBOL(__page_table_check_pud_clear);
|
||||
void __page_table_check_pte_set(struct mm_struct *mm, unsigned long addr,
|
||||
pte_t *ptep, pte_t pte)
|
||||
{
|
||||
pte_t old_pte;
|
||||
|
||||
if (&init_mm == mm)
|
||||
return;
|
||||
|
||||
old_pte = *ptep;
|
||||
if (pte_user_accessible_page(old_pte)) {
|
||||
page_table_check_clear(mm, addr, pte_pfn(old_pte),
|
||||
PAGE_SIZE >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
__page_table_check_pte_clear(mm, addr, *ptep);
|
||||
if (pte_user_accessible_page(pte)) {
|
||||
page_table_check_set(mm, addr, pte_pfn(pte),
|
||||
PAGE_SIZE >> PAGE_SHIFT,
|
||||
@ -228,17 +221,10 @@ EXPORT_SYMBOL(__page_table_check_pte_set);
|
||||
void __page_table_check_pmd_set(struct mm_struct *mm, unsigned long addr,
|
||||
pmd_t *pmdp, pmd_t pmd)
|
||||
{
|
||||
pmd_t old_pmd;
|
||||
|
||||
if (&init_mm == mm)
|
||||
return;
|
||||
|
||||
old_pmd = *pmdp;
|
||||
if (pmd_user_accessible_page(old_pmd)) {
|
||||
page_table_check_clear(mm, addr, pmd_pfn(old_pmd),
|
||||
PMD_PAGE_SIZE >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
__page_table_check_pmd_clear(mm, addr, *pmdp);
|
||||
if (pmd_user_accessible_page(pmd)) {
|
||||
page_table_check_set(mm, addr, pmd_pfn(pmd),
|
||||
PMD_PAGE_SIZE >> PAGE_SHIFT,
|
||||
@ -250,17 +236,10 @@ EXPORT_SYMBOL(__page_table_check_pmd_set);
|
||||
void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
|
||||
pud_t *pudp, pud_t pud)
|
||||
{
|
||||
pud_t old_pud;
|
||||
|
||||
if (&init_mm == mm)
|
||||
return;
|
||||
|
||||
old_pud = *pudp;
|
||||
if (pud_user_accessible_page(old_pud)) {
|
||||
page_table_check_clear(mm, addr, pud_pfn(old_pud),
|
||||
PUD_PAGE_SIZE >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
__page_table_check_pud_clear(mm, addr, *pudp);
|
||||
if (pud_user_accessible_page(pud)) {
|
||||
page_table_check_set(mm, addr, pud_pfn(pud),
|
||||
PUD_PAGE_SIZE >> PAGE_SHIFT,
|
||||
@ -268,3 +247,23 @@ void __page_table_check_pud_set(struct mm_struct *mm, unsigned long addr,
|
||||
}
|
||||
}
|
||||
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)
|
||||
static int userfaultfd_stress(void)
|
||||
{
|
||||
void *area;
|
||||
char *tmp_area;
|
||||
unsigned long nr;
|
||||
struct uffdio_register uffdio_register;
|
||||
struct uffd_stats uffd_stats[nr_cpus];
|
||||
@ -1527,9 +1528,13 @@ static int userfaultfd_stress(void)
|
||||
count_verify[nr], nr);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user