aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/mm/gup.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index 45b405ca2567..65cb06e2af4e 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -52,7 +52,7 @@ static 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) 52 unsigned long end, int write, struct page **pages, int *nr)
53{ 53{
54 unsigned long mask, result; 54 unsigned long mask, result;
55 struct page *head, *page; 55 struct page *head, *page, *tail;
56 int refs; 56 int refs;
57 57
58 result = write ? 0 : _SEGMENT_ENTRY_RO; 58 result = write ? 0 : _SEGMENT_ENTRY_RO;
@@ -64,6 +64,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
64 refs = 0; 64 refs = 0;
65 head = pmd_page(pmd); 65 head = pmd_page(pmd);
66 page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT); 66 page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
67 tail = page;
67 do { 68 do {
68 VM_BUG_ON(compound_head(page) != head); 69 VM_BUG_ON(compound_head(page) != head);
69 pages[*nr] = page; 70 pages[*nr] = page;
@@ -81,6 +82,17 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
81 *nr -= refs; 82 *nr -= refs;
82 while (refs--) 83 while (refs--)
83 put_page(head); 84 put_page(head);
85 return 0;
86 }
87
88 /*
89 * Any tail page need their mapcount reference taken before we
90 * return.
91 */
92 while (refs--) {
93 if (PageTail(tail))
94 get_huge_page_tail(tail);
95 tail++;
84 } 96 }
85 97
86 return 1; 98 return 1;