diff options
Diffstat (limited to 'arch/s390/mm/gup.c')
-rw-r--r-- | arch/s390/mm/gup.c | 14 |
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; |