summaryrefslogtreecommitdiff
path: root/arch/s390/mm/gup.c
diff options
context:
space:
mode:
authorGerald Schaefer <gerald.schaefer@de.ibm.com>2016-03-17 15:00:04 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-03-17 16:42:14 +0100
commitfc897c95e91451271cd707ee0f71022b9b201ce9 (patch)
treeb0a44cffdfb8193ba708719e9d7a9bb033f64e61 /arch/s390/mm/gup.c
parent91d37211769510ae0b4747045d8f81d3b9dd4278 (diff)
s390/mm: handle PTE-mapped tail pages in fast gup
With the THP refcounting rework it is possible to see THP compound tail pages mapped with PTEs during a THP split. This needs to be considered when using page_cache_get_speculative(), which will always fail on tail pages because ->_count is always zero. commit 7aef4172 "mm: handle PTE-mapped tail pages in gerneric fast gup implementaiton" fixed it for the generic fast gup code by using compound_head(page) instead of page, but not for s390. This patch is a 1:1 adaption of commit 7aef4172 for the s390 fast gup code. Without this fix, gup will fall back to the slow path or fail in the unlikely scenario that we hit a THP under splitting in-between the page table split and the compound page split. Cc: stable@vger.kernel.org # v4.5 Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/mm/gup.c')
-rw-r--r--arch/s390/mm/gup.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index 13dab0c1645c..3776aca22082 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -20,9 +20,9 @@
static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
+ struct page *head, *page;
unsigned long mask;
pte_t *ptep, pte;
- struct page *page;
mask = (write ? _PAGE_PROTECT : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
@@ -37,12 +37,14 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
return 0;
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
page = pte_page(pte);
- if (!page_cache_get_speculative(page))
+ head = compound_head(page);
+ if (!page_cache_get_speculative(head))
return 0;
if (unlikely(pte_val(pte) != pte_val(*ptep))) {
- put_page(page);
+ put_page(head);
return 0;
}
+ VM_BUG_ON_PAGE(compound_head(page) != head, page);
pages[*nr] = page;
(*nr)++;