Commit aeb542a1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'akpm' (patches from Andrew)

Merge misc fixes from Andrew Morton:
 "7 fixes"

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  arch/Kconfig: update HAVE_RELIABLE_STACKTRACE description
  mm, hotplug: fix page online with DEBUG_PAGEALLOC compiled but not enabled
  mm/z3fold.c: do not include rwlock.h directly
  fat: fix uninit-memory access for partial initialized inode
  mm: avoid data corruption on CoW fault into PFN-mapped VMA
  mm: fix possible PMD dirty bit lost in set_pmd_migration_entry()
  mm, numa: fix bad pmd by atomically check for pmd_trans_huge when marking page tables prot_numa
parents b0b8a945 140d7e88
...@@ -738,8 +738,9 @@ config HAVE_STACK_VALIDATION ...@@ -738,8 +738,9 @@ config HAVE_STACK_VALIDATION
config HAVE_RELIABLE_STACKTRACE config HAVE_RELIABLE_STACKTRACE
bool bool
help help
Architecture has a save_stack_trace_tsk_reliable() function which Architecture has either save_stack_trace_tsk_reliable() or
only returns a stack trace if it can guarantee the trace is reliable. arch_stack_walk_reliable() function which only returns a stack trace
if it can guarantee the trace is reliable.
config HAVE_ARCH_HASH config HAVE_ARCH_HASH
bool bool
......
...@@ -750,6 +750,13 @@ static struct inode *fat_alloc_inode(struct super_block *sb) ...@@ -750,6 +750,13 @@ static struct inode *fat_alloc_inode(struct super_block *sb)
return NULL; return NULL;
init_rwsem(&ei->truncate_lock); init_rwsem(&ei->truncate_lock);
/* Zeroing to allow iput() even if partial initialized inode. */
ei->mmu_private = 0;
ei->i_start = 0;
ei->i_logstart = 0;
ei->i_attrs = 0;
ei->i_pos = 0;
return &ei->vfs_inode; return &ei->vfs_inode;
} }
...@@ -1374,16 +1381,6 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, ...@@ -1374,16 +1381,6 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
return 0; return 0;
} }
static void fat_dummy_inode_init(struct inode *inode)
{
/* Initialize this dummy inode to work as no-op. */
MSDOS_I(inode)->mmu_private = 0;
MSDOS_I(inode)->i_start = 0;
MSDOS_I(inode)->i_logstart = 0;
MSDOS_I(inode)->i_attrs = 0;
MSDOS_I(inode)->i_pos = 0;
}
static int fat_read_root(struct inode *inode) static int fat_read_root(struct inode *inode)
{ {
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
...@@ -1844,13 +1841,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, ...@@ -1844,13 +1841,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
fat_inode = new_inode(sb); fat_inode = new_inode(sb);
if (!fat_inode) if (!fat_inode)
goto out_fail; goto out_fail;
fat_dummy_inode_init(fat_inode);
sbi->fat_inode = fat_inode; sbi->fat_inode = fat_inode;
fsinfo_inode = new_inode(sb); fsinfo_inode = new_inode(sb);
if (!fsinfo_inode) if (!fsinfo_inode)
goto out_fail; goto out_fail;
fat_dummy_inode_init(fsinfo_inode);
fsinfo_inode->i_ino = MSDOS_FSINFO_INO; fsinfo_inode->i_ino = MSDOS_FSINFO_INO;
sbi->fsinfo_inode = fsinfo_inode; sbi->fsinfo_inode = fsinfo_inode;
insert_inode_hash(fsinfo_inode); insert_inode_hash(fsinfo_inode);
......
...@@ -2715,6 +2715,10 @@ static inline bool debug_pagealloc_enabled_static(void) ...@@ -2715,6 +2715,10 @@ static inline bool debug_pagealloc_enabled_static(void)
#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP) #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP)
extern void __kernel_map_pages(struct page *page, int numpages, int enable); extern void __kernel_map_pages(struct page *page, int numpages, int enable);
/*
* When called in DEBUG_PAGEALLOC context, the call should most likely be
* guarded by debug_pagealloc_enabled() or debug_pagealloc_enabled_static()
*/
static inline void static inline void
kernel_map_pages(struct page *page, int numpages, int enable) kernel_map_pages(struct page *page, int numpages, int enable)
{ {
......
...@@ -3043,8 +3043,7 @@ void set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw, ...@@ -3043,8 +3043,7 @@ void set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
return; return;
flush_cache_range(vma, address, address + HPAGE_PMD_SIZE); flush_cache_range(vma, address, address + HPAGE_PMD_SIZE);
pmdval = *pvmw->pmd; pmdval = pmdp_invalidate(vma, address, pvmw->pmd);
pmdp_invalidate(vma, address, pvmw->pmd);
if (pmd_dirty(pmdval)) if (pmd_dirty(pmdval))
set_page_dirty(page); set_page_dirty(page);
entry = make_migration_entry(page, pmd_write(pmdval)); entry = make_migration_entry(page, pmd_write(pmdval));
......
...@@ -2257,7 +2257,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src, ...@@ -2257,7 +2257,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
bool ret; bool ret;
void *kaddr; void *kaddr;
void __user *uaddr; void __user *uaddr;
bool force_mkyoung; bool locked = false;
struct vm_area_struct *vma = vmf->vma; struct vm_area_struct *vma = vmf->vma;
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
unsigned long addr = vmf->address; unsigned long addr = vmf->address;
...@@ -2282,11 +2282,11 @@ static inline bool cow_user_page(struct page *dst, struct page *src, ...@@ -2282,11 +2282,11 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
* On architectures with software "accessed" bits, we would * On architectures with software "accessed" bits, we would
* take a double page fault, so mark it accessed here. * take a double page fault, so mark it accessed here.
*/ */
force_mkyoung = arch_faults_on_old_pte() && !pte_young(vmf->orig_pte); if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) {
if (force_mkyoung) {
pte_t entry; pte_t entry;
vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl); vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl);
locked = true;
if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) { if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) {
/* /*
* Other thread has already handled the fault * Other thread has already handled the fault
...@@ -2310,18 +2310,37 @@ static inline bool cow_user_page(struct page *dst, struct page *src, ...@@ -2310,18 +2310,37 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
* zeroes. * zeroes.
*/ */
if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) { if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
if (locked)
goto warn;
/* Re-validate under PTL if the page is still mapped */
vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl);
locked = true;
if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) {
/* The PTE changed under us. Retry page fault. */
ret = false;
goto pte_unlock;
}
/* /*
* Give a warn in case there can be some obscure * The same page can be mapped back since last copy attampt.
* use-case * Try to copy again under PTL.
*/ */
WARN_ON_ONCE(1); if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
clear_page(kaddr); /*
* Give a warn in case there can be some obscure
* use-case
*/
warn:
WARN_ON_ONCE(1);
clear_page(kaddr);
}
} }
ret = true; ret = true;
pte_unlock: pte_unlock:
if (force_mkyoung) if (locked)
pte_unmap_unlock(vmf->pte, vmf->ptl); pte_unmap_unlock(vmf->pte, vmf->ptl);
kunmap_atomic(kaddr); kunmap_atomic(kaddr);
flush_dcache_page(dst); flush_dcache_page(dst);
......
...@@ -574,7 +574,13 @@ EXPORT_SYMBOL_GPL(restore_online_page_callback); ...@@ -574,7 +574,13 @@ EXPORT_SYMBOL_GPL(restore_online_page_callback);
void generic_online_page(struct page *page, unsigned int order) void generic_online_page(struct page *page, unsigned int order)
{ {
kernel_map_pages(page, 1 << order, 1); /*
* Freeing the page with debug_pagealloc enabled will try to unmap it,
* so we should map it first. This is better than introducing a special
* case in page freeing fast path.
*/
if (debug_pagealloc_enabled_static())
kernel_map_pages(page, 1 << order, 1);
__free_pages_core(page, order); __free_pages_core(page, order);
totalram_pages_add(1UL << order); totalram_pages_add(1UL << order);
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
......
...@@ -161,6 +161,31 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, ...@@ -161,6 +161,31 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
return pages; return pages;
} }
/*
* Used when setting automatic NUMA hinting protection where it is
* critical that a numa hinting PMD is not confused with a bad PMD.
*/
static inline int pmd_none_or_clear_bad_unless_trans_huge(pmd_t *pmd)
{
pmd_t pmdval = pmd_read_atomic(pmd);
/* See pmd_none_or_trans_huge_or_clear_bad for info on barrier */
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
barrier();
#endif
if (pmd_none(pmdval))
return 1;
if (pmd_trans_huge(pmdval))
return 0;
if (unlikely(pmd_bad(pmdval))) {
pmd_clear_bad(pmd);
return 1;
}
return 0;
}
static inline unsigned long change_pmd_range(struct vm_area_struct *vma, static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
pud_t *pud, unsigned long addr, unsigned long end, pud_t *pud, unsigned long addr, unsigned long end,
pgprot_t newprot, int dirty_accountable, int prot_numa) pgprot_t newprot, int dirty_accountable, int prot_numa)
...@@ -178,8 +203,17 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, ...@@ -178,8 +203,17 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
unsigned long this_pages; unsigned long this_pages;
next = pmd_addr_end(addr, end); next = pmd_addr_end(addr, end);
if (!is_swap_pmd(*pmd) && !pmd_trans_huge(*pmd) && !pmd_devmap(*pmd)
&& pmd_none_or_clear_bad(pmd)) /*
* Automatic NUMA balancing walks the tables with mmap_sem
* held for read. It's possible a parallel update to occur
* between pmd_trans_huge() and a pmd_none_or_clear_bad()
* check leading to a false positive and clearing.
* Hence, it's necessary to atomically read the PMD value
* for all the checks.
*/
if (!is_swap_pmd(*pmd) && !pmd_devmap(*pmd) &&
pmd_none_or_clear_bad_unless_trans_huge(pmd))
goto next; goto next;
/* invoke the mmu notifier if the pmd is populated */ /* invoke the mmu notifier if the pmd is populated */
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rwlock.h>
#include <linux/zpool.h> #include <linux/zpool.h>
#include <linux/magic.h> #include <linux/magic.h>
......
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