mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 21:54:11 +08:00
Merge branch 'akpm' (patches from Andrew)
Merge fixes from Andrew Morton: "13 fixes" * emailed patches from Andrew Morton <akpm@linux-foundation.org>: dma-mapping: avoid oops when parameter cpu_addr is null mm/hugetlb: use EOPNOTSUPP in hugetlb sysctl handlers memremap: check pfn validity before passing to pfn_to_page() mm, thp: fix migration of PTE-mapped transparent huge pages dax: check return value of dax_radix_entry() ocfs2: fix return value from ocfs2_page_mkwrite() arm64: kasan: clear stale stack poison sched/kasan: remove stale KASAN poison after hotplug kasan: add functions to clear stack poison mm: fix mixed zone detection in devm_memremap_pages list: kill list_force_poison() mm: __delete_from_page_cache show Bad page if mapped mm/hugetlb: hugetlb_no_page: rate-limit warning message
This commit is contained in:
commit
380173ff56
@ -145,6 +145,10 @@ ENTRY(cpu_resume_mmu)
|
||||
ENDPROC(cpu_resume_mmu)
|
||||
.popsection
|
||||
cpu_resume_after_mmu:
|
||||
#ifdef CONFIG_KASAN
|
||||
mov x0, sp
|
||||
bl kasan_unpoison_remaining_stack
|
||||
#endif
|
||||
mov x0, #0 // return zero on success
|
||||
ldp x19, x20, [sp, #16]
|
||||
ldp x21, x22, [sp, #32]
|
||||
|
9
fs/dax.c
9
fs/dax.c
@ -1056,6 +1056,7 @@ EXPORT_SYMBOL_GPL(dax_pmd_fault);
|
||||
int dax_pfn_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
struct file *file = vma->vm_file;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* We pass NO_SECTOR to dax_radix_entry() because we expect that a
|
||||
@ -1065,7 +1066,13 @@ int dax_pfn_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
* saves us from having to make a call to get_block() here to look
|
||||
* up the sector.
|
||||
*/
|
||||
dax_radix_entry(file->f_mapping, vmf->pgoff, NO_SECTOR, false, true);
|
||||
error = dax_radix_entry(file->f_mapping, vmf->pgoff, NO_SECTOR, false,
|
||||
true);
|
||||
|
||||
if (error == -ENOMEM)
|
||||
return VM_FAULT_OOM;
|
||||
if (error)
|
||||
return VM_FAULT_SIGBUS;
|
||||
return VM_FAULT_NOPAGE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dax_pfn_mkwrite);
|
||||
|
@ -147,6 +147,10 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
ret = ocfs2_inode_lock(inode, &di_bh, 1);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
if (ret == -ENOMEM)
|
||||
ret = VM_FAULT_OOM;
|
||||
else
|
||||
ret = VM_FAULT_SIGBUS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -386,7 +386,7 @@ static inline void dma_free_attrs(struct device *dev, size_t size,
|
||||
if (dma_release_from_coherent(dev, get_order(size), cpu_addr))
|
||||
return;
|
||||
|
||||
if (!ops->free)
|
||||
if (!ops->free || !cpu_addr)
|
||||
return;
|
||||
|
||||
debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef _LINUX_KASAN_H
|
||||
#define _LINUX_KASAN_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct kmem_cache;
|
||||
@ -13,7 +14,6 @@ struct vm_struct;
|
||||
|
||||
#include <asm/kasan.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
extern unsigned char kasan_zero_page[PAGE_SIZE];
|
||||
extern pte_t kasan_zero_pte[PTRS_PER_PTE];
|
||||
@ -43,6 +43,8 @@ static inline void kasan_disable_current(void)
|
||||
|
||||
void kasan_unpoison_shadow(const void *address, size_t size);
|
||||
|
||||
void kasan_unpoison_task_stack(struct task_struct *task);
|
||||
|
||||
void kasan_alloc_pages(struct page *page, unsigned int order);
|
||||
void kasan_free_pages(struct page *page, unsigned int order);
|
||||
|
||||
@ -66,6 +68,8 @@ void kasan_free_shadow(const struct vm_struct *vm);
|
||||
|
||||
static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
|
||||
|
||||
static inline void kasan_unpoison_task_stack(struct task_struct *task) {}
|
||||
|
||||
static inline void kasan_enable_current(void) {}
|
||||
static inline void kasan_disable_current(void) {}
|
||||
|
||||
|
@ -113,17 +113,6 @@ extern void __list_del_entry(struct list_head *entry);
|
||||
extern void list_del(struct list_head *entry);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_LIST
|
||||
/*
|
||||
* See devm_memremap_pages() which wants DEBUG_LIST=y to assert if one
|
||||
* of the pages it allocates is ever passed to list_add()
|
||||
*/
|
||||
extern void list_force_poison(struct list_head *entry);
|
||||
#else
|
||||
/* fallback to the less strict LIST_POISON* definitions */
|
||||
#define list_force_poison list_del
|
||||
#endif
|
||||
|
||||
/**
|
||||
* list_replace - replace old entry by new one
|
||||
* @old : the element to be replaced
|
||||
|
@ -29,10 +29,10 @@ __weak void __iomem *ioremap_cache(resource_size_t offset, unsigned long size)
|
||||
|
||||
static void *try_ram_remap(resource_size_t offset, size_t size)
|
||||
{
|
||||
struct page *page = pfn_to_page(offset >> PAGE_SHIFT);
|
||||
unsigned long pfn = PHYS_PFN(offset);
|
||||
|
||||
/* In the simple case just return the existing linear address */
|
||||
if (!PageHighMem(page))
|
||||
if (pfn_valid(pfn) && !PageHighMem(pfn_to_page(pfn)))
|
||||
return __va(offset);
|
||||
return NULL; /* fallback to ioremap_cache */
|
||||
}
|
||||
@ -270,13 +270,16 @@ struct dev_pagemap *find_dev_pagemap(resource_size_t phys)
|
||||
void *devm_memremap_pages(struct device *dev, struct resource *res,
|
||||
struct percpu_ref *ref, struct vmem_altmap *altmap)
|
||||
{
|
||||
int is_ram = region_intersects(res->start, resource_size(res),
|
||||
"System RAM");
|
||||
resource_size_t key, align_start, align_size, align_end;
|
||||
struct dev_pagemap *pgmap;
|
||||
struct page_map *page_map;
|
||||
int error, nid, is_ram;
|
||||
unsigned long pfn;
|
||||
int error, nid;
|
||||
|
||||
align_start = res->start & ~(SECTION_SIZE - 1);
|
||||
align_size = ALIGN(res->start + resource_size(res), SECTION_SIZE)
|
||||
- align_start;
|
||||
is_ram = region_intersects(align_start, align_size, "System RAM");
|
||||
|
||||
if (is_ram == REGION_MIXED) {
|
||||
WARN_ONCE(1, "%s attempted on mixed region %pr\n",
|
||||
@ -314,8 +317,6 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
|
||||
|
||||
mutex_lock(&pgmap_lock);
|
||||
error = 0;
|
||||
align_start = res->start & ~(SECTION_SIZE - 1);
|
||||
align_size = ALIGN(resource_size(res), SECTION_SIZE);
|
||||
align_end = align_start + align_size - 1;
|
||||
for (key = align_start; key <= align_end; key += SECTION_SIZE) {
|
||||
struct dev_pagemap *dup;
|
||||
@ -351,8 +352,13 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
|
||||
for_each_device_pfn(pfn, page_map) {
|
||||
struct page *page = pfn_to_page(pfn);
|
||||
|
||||
/* ZONE_DEVICE pages must never appear on a slab lru */
|
||||
list_force_poison(&page->lru);
|
||||
/*
|
||||
* ZONE_DEVICE pages union ->lru with a ->pgmap back
|
||||
* pointer. It is a bug if a ZONE_DEVICE page is ever
|
||||
* freed or placed on a driver-private list. Seed the
|
||||
* storage with LIST_POISON* values.
|
||||
*/
|
||||
list_del(&page->lru);
|
||||
page->pgmap = pgmap;
|
||||
}
|
||||
devres_add(dev, page_map);
|
||||
|
@ -26,6 +26,7 @@
|
||||
* Thomas Gleixner, Mike Kravetz
|
||||
*/
|
||||
|
||||
#include <linux/kasan.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nmi.h>
|
||||
@ -5096,6 +5097,8 @@ void init_idle(struct task_struct *idle, int cpu)
|
||||
idle->state = TASK_RUNNING;
|
||||
idle->se.exec_start = sched_clock();
|
||||
|
||||
kasan_unpoison_task_stack(idle);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* Its possible that init_idle() gets called multiple times on a task,
|
||||
|
@ -12,13 +12,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/rculist.h>
|
||||
|
||||
static struct list_head force_poison;
|
||||
void list_force_poison(struct list_head *entry)
|
||||
{
|
||||
entry->next = &force_poison;
|
||||
entry->prev = &force_poison;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
@ -30,8 +23,6 @@ void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
WARN(new->next == &force_poison || new->prev == &force_poison,
|
||||
"list_add attempted on force-poisoned entry\n");
|
||||
WARN(next->prev != prev,
|
||||
"list_add corruption. next->prev should be "
|
||||
"prev (%p), but was %p. (next=%p).\n",
|
||||
|
25
mm/filemap.c
25
mm/filemap.c
@ -195,6 +195,30 @@ void __delete_from_page_cache(struct page *page, void *shadow,
|
||||
else
|
||||
cleancache_invalidate_page(mapping, page);
|
||||
|
||||
VM_BUG_ON_PAGE(page_mapped(page), page);
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_VM) && unlikely(page_mapped(page))) {
|
||||
int mapcount;
|
||||
|
||||
pr_alert("BUG: Bad page cache in process %s pfn:%05lx\n",
|
||||
current->comm, page_to_pfn(page));
|
||||
dump_page(page, "still mapped when deleted");
|
||||
dump_stack();
|
||||
add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
|
||||
|
||||
mapcount = page_mapcount(page);
|
||||
if (mapping_exiting(mapping) &&
|
||||
page_count(page) >= mapcount + 2) {
|
||||
/*
|
||||
* All vmas have already been torn down, so it's
|
||||
* a good bet that actually the page is unmapped,
|
||||
* and we'd prefer not to leak it: if we're wrong,
|
||||
* some other bad page check should catch it later.
|
||||
*/
|
||||
page_mapcount_reset(page);
|
||||
atomic_sub(mapcount, &page->_count);
|
||||
}
|
||||
}
|
||||
|
||||
page_cache_tree_delete(mapping, page, shadow);
|
||||
|
||||
page->mapping = NULL;
|
||||
@ -205,7 +229,6 @@ void __delete_from_page_cache(struct page *page, void *shadow,
|
||||
__dec_zone_page_state(page, NR_FILE_PAGES);
|
||||
if (PageSwapBacked(page))
|
||||
__dec_zone_page_state(page, NR_SHMEM);
|
||||
VM_BUG_ON_PAGE(page_mapped(page), page);
|
||||
|
||||
/*
|
||||
* At this point page must be either written or cleaned by truncate.
|
||||
|
@ -2751,7 +2751,7 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
|
||||
int ret;
|
||||
|
||||
if (!hugepages_supported())
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
table->data = &tmp;
|
||||
table->maxlen = sizeof(unsigned long);
|
||||
@ -2792,7 +2792,7 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
|
||||
int ret;
|
||||
|
||||
if (!hugepages_supported())
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tmp = h->nr_overcommit_huge_pages;
|
||||
|
||||
@ -3502,7 +3502,7 @@ static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||
* COW. Warn that such a situation has occurred as it may not be obvious
|
||||
*/
|
||||
if (is_vma_resv_set(vma, HPAGE_RESV_UNMAPPED)) {
|
||||
pr_warning("PID %d killed due to inadequate hugepage pool\n",
|
||||
pr_warn_ratelimited("PID %d killed due to inadequate hugepage pool\n",
|
||||
current->pid);
|
||||
return ret;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kmemleak.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/memory.h>
|
||||
#include <linux/mm.h>
|
||||
@ -60,6 +61,25 @@ void kasan_unpoison_shadow(const void *address, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
static void __kasan_unpoison_stack(struct task_struct *task, void *sp)
|
||||
{
|
||||
void *base = task_stack_page(task);
|
||||
size_t size = sp - base;
|
||||
|
||||
kasan_unpoison_shadow(base, size);
|
||||
}
|
||||
|
||||
/* Unpoison the entire stack for a task. */
|
||||
void kasan_unpoison_task_stack(struct task_struct *task)
|
||||
{
|
||||
__kasan_unpoison_stack(task, task_stack_page(task) + THREAD_SIZE);
|
||||
}
|
||||
|
||||
/* Unpoison the stack for the current task beyond a watermark sp value. */
|
||||
asmlinkage void kasan_unpoison_remaining_stack(void *sp)
|
||||
{
|
||||
__kasan_unpoison_stack(current, sp);
|
||||
}
|
||||
|
||||
/*
|
||||
* All functions below always inlined so compiler could
|
||||
|
@ -532,7 +532,7 @@ retry:
|
||||
nid = page_to_nid(page);
|
||||
if (node_isset(nid, *qp->nmask) == !!(flags & MPOL_MF_INVERT))
|
||||
continue;
|
||||
if (PageTail(page) && PageAnon(page)) {
|
||||
if (PageTransCompound(page) && PageAnon(page)) {
|
||||
get_page(page);
|
||||
pte_unmap_unlock(pte, ptl);
|
||||
lock_page(page);
|
||||
|
Loading…
Reference in New Issue
Block a user