aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/mm/gup.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index 45b405ca2567..668dda964f20 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -48,11 +48,22 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
48 return 1; 48 return 1;
49} 49}
50 50
51static inline void get_huge_page_tail(struct page *page)
52{
53 /*
54 * __split_huge_page_refcount() cannot run
55 * from under us.
56 */
57 VM_BUG_ON(page_mapcount(page) < 0);
58 VM_BUG_ON(atomic_read(&page->_count) != 0);
59 atomic_inc(&page->_mapcount);
60}
61
51static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, 62static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
52 unsigned long end, int write, struct page **pages, int *nr) 63 unsigned long end, int write, struct page **pages, int *nr)
53{ 64{
54 unsigned long mask, result; 65 unsigned long mask, result;
55 struct page *head, *page; 66 struct page *head, *page, *tail;
56 int refs; 67 int refs;
57 68
58 result = write ? 0 : _SEGMENT_ENTRY_RO; 69 result = write ? 0 : _SEGMENT_ENTRY_RO;
@@ -64,6 +75,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
64 refs = 0; 75 refs = 0;
65 head = pmd_page(pmd); 76 head = pmd_page(pmd);
66 page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT); 77 page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
78 tail = page;
67 do { 79 do {
68 VM_BUG_ON(compound_head(page) != head); 80 VM_BUG_ON(compound_head(page) != head);
69 pages[*nr] = page; 81 pages[*nr] = page;
@@ -81,6 +93,16 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
81 *nr -= refs; 93 *nr -= refs;
82 while (refs--) 94 while (refs--)
83 put_page(head); 95 put_page(head);
96 } else {
97 /*
98 * Any tail page need their mapcount reference taken
99 * before we return.
100 */
101 while (refs--) {
102 if (PageTail(tail))
103 get_huge_page_tail(tail);
104 tail++;
105 }
84 } 106 }
85 107
86 return 1; 108 return 1;