Commit 06f055f3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'akpm' (incoming from Andrew)

Merge patches from Andrew Morton:
 "Ten fixes"

* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
  epoll: do not take the nested ep->mtx on EPOLL_CTL_DEL
  sh: add EXPORT_SYMBOL(min_low_pfn) and EXPORT_SYMBOL(max_low_pfn) to sh_ksyms_32.c
  drivers/dma/ioat/dma.c: check DMA mapping error in ioat_dma_self_test()
  mm/memory-failure.c: transfer page count from head page to tail page after split thp
  MAINTAINERS: set up proper record for Xilinx Zynq
  mm: remove bogus warning in copy_huge_pmd()
  memcg: fix memcg_size() calculation
  mm: fix use-after-free in sys_remap_file_pages
  mm: munlock: fix deadlock in __munlock_pagevec()
  mm: munlock: fix a bug where THP tail page is encountered
parents 152b734a 4ff36ee9
...@@ -1368,6 +1368,9 @@ T: git git://git.xilinx.com/linux-xlnx.git ...@@ -1368,6 +1368,9 @@ T: git git://git.xilinx.com/linux-xlnx.git
S: Supported S: Supported
F: arch/arm/mach-zynq/ F: arch/arm/mach-zynq/
F: drivers/cpuidle/cpuidle-zynq.c F: drivers/cpuidle/cpuidle-zynq.c
N: zynq
N: xilinx
F: drivers/clocksource/cadence_ttc_timer.c
ARM SMMU DRIVER ARM SMMU DRIVER
M: Will Deacon <will.deacon@arm.com> M: Will Deacon <will.deacon@arm.com>
......
...@@ -20,6 +20,11 @@ EXPORT_SYMBOL(csum_partial_copy_generic); ...@@ -20,6 +20,11 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(copy_page);
EXPORT_SYMBOL(__clear_user); EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(empty_zero_page);
#ifdef CONFIG_FLATMEM
/* need in pfn_valid macro */
EXPORT_SYMBOL(min_low_pfn);
EXPORT_SYMBOL(max_low_pfn);
#endif
#define DECLARE_EXPORT(name) \ #define DECLARE_EXPORT(name) \
extern void name(void);EXPORT_SYMBOL(name) extern void name(void);EXPORT_SYMBOL(name)
......
...@@ -817,7 +817,15 @@ int ioat_dma_self_test(struct ioatdma_device *device) ...@@ -817,7 +817,15 @@ int ioat_dma_self_test(struct ioatdma_device *device)
} }
dma_src = dma_map_single(dev, src, IOAT_TEST_SIZE, DMA_TO_DEVICE); dma_src = dma_map_single(dev, src, IOAT_TEST_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma_src)) {
dev_err(dev, "mapping src buffer failed\n");
goto free_resources;
}
dma_dest = dma_map_single(dev, dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE); dma_dest = dma_map_single(dev, dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, dma_dest)) {
dev_err(dev, "mapping dest buffer failed\n");
goto unmap_src;
}
flags = DMA_PREP_INTERRUPT; flags = DMA_PREP_INTERRUPT;
tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src, tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src,
IOAT_TEST_SIZE, flags); IOAT_TEST_SIZE, flags);
...@@ -855,8 +863,9 @@ int ioat_dma_self_test(struct ioatdma_device *device) ...@@ -855,8 +863,9 @@ int ioat_dma_self_test(struct ioatdma_device *device)
} }
unmap_dma: unmap_dma:
dma_unmap_single(dev, dma_src, IOAT_TEST_SIZE, DMA_TO_DEVICE);
dma_unmap_single(dev, dma_dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE); dma_unmap_single(dev, dma_dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE);
unmap_src:
dma_unmap_single(dev, dma_src, IOAT_TEST_SIZE, DMA_TO_DEVICE);
free_resources: free_resources:
dma->device_free_chan_resources(dma_chan); dma->device_free_chan_resources(dma_chan);
out: out:
......
...@@ -1907,10 +1907,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, ...@@ -1907,10 +1907,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
} }
} }
} }
if (op == EPOLL_CTL_DEL && is_file_epoll(tf.file)) {
tep = tf.file->private_data;
mutex_lock_nested(&tep->mtx, 1);
}
/* /*
* Try to lookup the file inside our RB tree, Since we grabbed "mtx" * Try to lookup the file inside our RB tree, Since we grabbed "mtx"
......
...@@ -208,9 +208,10 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, ...@@ -208,9 +208,10 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
if (mapping_cap_account_dirty(mapping)) { if (mapping_cap_account_dirty(mapping)) {
unsigned long addr; unsigned long addr;
struct file *file = get_file(vma->vm_file); struct file *file = get_file(vma->vm_file);
/* mmap_region may free vma; grab the info now */
vm_flags = vma->vm_flags;
addr = mmap_region(file, start, size, addr = mmap_region(file, start, size, vm_flags, pgoff);
vma->vm_flags, pgoff);
fput(file); fput(file);
if (IS_ERR_VALUE(addr)) { if (IS_ERR_VALUE(addr)) {
err = addr; err = addr;
...@@ -218,7 +219,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, ...@@ -218,7 +219,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
BUG_ON(addr != start); BUG_ON(addr != start);
err = 0; err = 0;
} }
goto out; goto out_freed;
} }
mutex_lock(&mapping->i_mmap_mutex); mutex_lock(&mapping->i_mmap_mutex);
flush_dcache_mmap_lock(mapping); flush_dcache_mmap_lock(mapping);
...@@ -253,6 +254,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, ...@@ -253,6 +254,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
out: out:
if (vma) if (vma)
vm_flags = vma->vm_flags; vm_flags = vma->vm_flags;
out_freed:
if (likely(!has_write_lock)) if (likely(!has_write_lock))
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
else else
......
...@@ -883,9 +883,6 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, ...@@ -883,9 +883,6 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
goto out_unlock; goto out_unlock;
} }
/* mmap_sem prevents this happening but warn if that changes */
WARN_ON(pmd_trans_migrating(pmd));
if (unlikely(pmd_trans_splitting(pmd))) { if (unlikely(pmd_trans_splitting(pmd))) {
/* split huge page running from under us */ /* split huge page running from under us */
spin_unlock(src_ptl); spin_unlock(src_ptl);
......
...@@ -338,7 +338,7 @@ struct mem_cgroup { ...@@ -338,7 +338,7 @@ struct mem_cgroup {
static size_t memcg_size(void) static size_t memcg_size(void)
{ {
return sizeof(struct mem_cgroup) + return sizeof(struct mem_cgroup) +
nr_node_ids * sizeof(struct mem_cgroup_per_node); nr_node_ids * sizeof(struct mem_cgroup_per_node *);
} }
/* internal only representation about the status of kmem accounting. */ /* internal only representation about the status of kmem accounting. */
......
...@@ -938,6 +938,16 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, ...@@ -938,6 +938,16 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
BUG_ON(!PageHWPoison(p)); BUG_ON(!PageHWPoison(p));
return SWAP_FAIL; return SWAP_FAIL;
} }
/*
* We pinned the head page for hwpoison handling,
* now we split the thp and we are interested in
* the hwpoisoned raw page, so move the refcount
* to it.
*/
if (hpage != p) {
put_page(hpage);
get_page(p);
}
/* THP is split, so ppage should be the real poisoned page. */ /* THP is split, so ppage should be the real poisoned page. */
ppage = p; ppage = p;
} }
......
...@@ -133,7 +133,10 @@ static void __munlock_isolation_failed(struct page *page) ...@@ -133,7 +133,10 @@ static void __munlock_isolation_failed(struct page *page)
/** /**
* munlock_vma_page - munlock a vma page * munlock_vma_page - munlock a vma page
* @page - page to be unlocked * @page - page to be unlocked, either a normal page or THP page head
*
* returns the size of the page as a page mask (0 for normal page,
* HPAGE_PMD_NR - 1 for THP head page)
* *
* called from munlock()/munmap() path with page supposedly on the LRU. * called from munlock()/munmap() path with page supposedly on the LRU.
* When we munlock a page, because the vma where we found the page is being * When we munlock a page, because the vma where we found the page is being
...@@ -148,21 +151,30 @@ static void __munlock_isolation_failed(struct page *page) ...@@ -148,21 +151,30 @@ static void __munlock_isolation_failed(struct page *page)
*/ */
unsigned int munlock_vma_page(struct page *page) unsigned int munlock_vma_page(struct page *page)
{ {
unsigned int page_mask = 0; unsigned int nr_pages;
BUG_ON(!PageLocked(page)); BUG_ON(!PageLocked(page));
if (TestClearPageMlocked(page)) { if (TestClearPageMlocked(page)) {
unsigned int nr_pages = hpage_nr_pages(page); nr_pages = hpage_nr_pages(page);
mod_zone_page_state(page_zone(page), NR_MLOCK, -nr_pages); mod_zone_page_state(page_zone(page), NR_MLOCK, -nr_pages);
page_mask = nr_pages - 1;
if (!isolate_lru_page(page)) if (!isolate_lru_page(page))
__munlock_isolated_page(page); __munlock_isolated_page(page);
else else
__munlock_isolation_failed(page); __munlock_isolation_failed(page);
} else {
nr_pages = hpage_nr_pages(page);
} }
return page_mask; /*
* Regardless of the original PageMlocked flag, we determine nr_pages
* after touching the flag. This leaves a possible race with a THP page
* split, such that a whole THP page was munlocked, but nr_pages == 1.
* Returning a smaller mask due to that is OK, the worst that can
* happen is subsequent useless scanning of the former tail pages.
* The NR_MLOCK accounting can however become broken.
*/
return nr_pages - 1;
} }
/** /**
...@@ -286,10 +298,12 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone) ...@@ -286,10 +298,12 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
{ {
int i; int i;
int nr = pagevec_count(pvec); int nr = pagevec_count(pvec);
int delta_munlocked = -nr; int delta_munlocked;
struct pagevec pvec_putback; struct pagevec pvec_putback;
int pgrescued = 0; int pgrescued = 0;
pagevec_init(&pvec_putback, 0);
/* Phase 1: page isolation */ /* Phase 1: page isolation */
spin_lock_irq(&zone->lru_lock); spin_lock_irq(&zone->lru_lock);
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
...@@ -318,18 +332,21 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone) ...@@ -318,18 +332,21 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
/* /*
* We won't be munlocking this page in the next phase * We won't be munlocking this page in the next phase
* but we still need to release the follow_page_mask() * but we still need to release the follow_page_mask()
* pin. * pin. We cannot do it under lru_lock however. If it's
* the last pin, __page_cache_release would deadlock.
*/ */
pagevec_add(&pvec_putback, pvec->pages[i]);
pvec->pages[i] = NULL; pvec->pages[i] = NULL;
put_page(page);
delta_munlocked++;
} }
} }
delta_munlocked = -nr + pagevec_count(&pvec_putback);
__mod_zone_page_state(zone, NR_MLOCK, delta_munlocked); __mod_zone_page_state(zone, NR_MLOCK, delta_munlocked);
spin_unlock_irq(&zone->lru_lock); spin_unlock_irq(&zone->lru_lock);
/* Now we can release pins of pages that we are not munlocking */
pagevec_release(&pvec_putback);
/* Phase 2: page munlock */ /* Phase 2: page munlock */
pagevec_init(&pvec_putback, 0);
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
struct page *page = pvec->pages[i]; struct page *page = pvec->pages[i];
...@@ -440,7 +457,8 @@ void munlock_vma_pages_range(struct vm_area_struct *vma, ...@@ -440,7 +457,8 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
while (start < end) { while (start < end) {
struct page *page = NULL; struct page *page = NULL;
unsigned int page_mask, page_increm; unsigned int page_mask;
unsigned long page_increm;
struct pagevec pvec; struct pagevec pvec;
struct zone *zone; struct zone *zone;
int zoneid; int zoneid;
...@@ -490,7 +508,9 @@ void munlock_vma_pages_range(struct vm_area_struct *vma, ...@@ -490,7 +508,9 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
goto next; goto next;
} }
} }
page_increm = 1 + (~(start >> PAGE_SHIFT) & page_mask); /* It's a bug to munlock in the middle of a THP page */
VM_BUG_ON((start >> PAGE_SHIFT) & page_mask);
page_increm = 1 + page_mask;
start += page_increm * PAGE_SIZE; start += page_increm * PAGE_SIZE;
next: next:
cond_resched(); cond_resched();
......
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