aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorAndrea Arcangeli <aarcange@redhat.com>2011-11-02 16:37:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-02 19:06:58 -0400
commit220a2eb228d032acde60e9fd044ca802706ff583 (patch)
treea764d37aace07cf5a9fa2c1e5b7f81662dfee7ae /arch/s390
parentcf592bf768c4fa40282b8fce58a80820065de2cb (diff)
s390: gup_huge_pmd() support THP tail recounting
Up to this point the code assumed old refcounting for hugepages (pre-thp). This updates the code directly to the thp mapcount tail page refcounting. Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Hugh Dickins <hughd@google.com> Cc: Johannes Weiner <jweiner@redhat.com> Cc: Rik van Riel <riel@redhat.com> Cc: Mel Gorman <mgorman@suse.de> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: David Gibson <david@gibson.dropbear.id.au> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: David Miller <davem@davemloft.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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;