aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAndrea Arcangeli <aarcange@redhat.com>2011-01-13 18:46:32 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 20:32:39 -0500
commit9180706344487700b40da9eca5dedd3d11cb33b4 (patch)
treeeb0347efe7e40adc78a271752c7382aa67875d6a /arch
parente9da73d67729b58bba256123e2b4651e0d8a01ac (diff)
thp: alter compound get_page/put_page
Alter compound get_page/put_page to keep references on subpages too, in order to allow __split_huge_page_refcount to split an hugepage even while subpages have been pinned by one of the get_user_pages() variants. Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Acked-by: Rik van Riel <riel@redhat.com> Acked-by: Mel Gorman <mel@csn.ul.ie> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/mm/gup.c12
-rw-r--r--arch/x86/mm/gup.c12
2 files changed, 24 insertions, 0 deletions
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
index d7efdbf640c7..fec13200868f 100644
--- a/arch/powerpc/mm/gup.c
+++ b/arch/powerpc/mm/gup.c
@@ -16,6 +16,16 @@
16 16
17#ifdef __HAVE_ARCH_PTE_SPECIAL 17#ifdef __HAVE_ARCH_PTE_SPECIAL
18 18
19static inline void get_huge_page_tail(struct page *page)
20{
21 /*
22 * __split_huge_page_refcount() cannot run
23 * from under us.
24 */
25 VM_BUG_ON(atomic_read(&page->_count) < 0);
26 atomic_inc(&page->_count);
27}
28
19/* 29/*
20 * The performance critical leaf functions are made noinline otherwise gcc 30 * The performance critical leaf functions are made noinline otherwise gcc
21 * inlines everything into a single function which results in too much 31 * inlines everything into a single function which results in too much
@@ -47,6 +57,8 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
47 put_page(page); 57 put_page(page);
48 return 0; 58 return 0;
49 } 59 }
60 if (PageTail(page))
61 get_huge_page_tail(page);
50 pages[*nr] = page; 62 pages[*nr] = page;
51 (*nr)++; 63 (*nr)++;
52 64
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index 738e6593799d..06f56fcf9a77 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -105,6 +105,16 @@ static inline void get_head_page_multiple(struct page *page, int nr)
105 atomic_add(nr, &page->_count); 105 atomic_add(nr, &page->_count);
106} 106}
107 107
108static inline void get_huge_page_tail(struct page *page)
109{
110 /*
111 * __split_huge_page_refcount() cannot run
112 * from under us.
113 */
114 VM_BUG_ON(atomic_read(&page->_count) < 0);
115 atomic_inc(&page->_count);
116}
117
108static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr, 118static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
109 unsigned long end, int write, struct page **pages, int *nr) 119 unsigned long end, int write, struct page **pages, int *nr)
110{ 120{
@@ -128,6 +138,8 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
128 do { 138 do {
129 VM_BUG_ON(compound_head(page) != head); 139 VM_BUG_ON(compound_head(page) != head);
130 pages[*nr] = page; 140 pages[*nr] = page;
141 if (PageTail(page))
142 get_huge_page_tail(page);
131 (*nr)++; 143 (*nr)++;
132 page++; 144 page++;
133 refs++; 145 refs++;