diff options
author | Andrea Arcangeli <aarcange@redhat.com> | 2011-01-13 18:46:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 20:32:39 -0500 |
commit | 9180706344487700b40da9eca5dedd3d11cb33b4 (patch) | |
tree | eb0347efe7e40adc78a271752c7382aa67875d6a /arch | |
parent | e9da73d67729b58bba256123e2b4651e0d8a01ac (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.c | 12 | ||||
-rw-r--r-- | arch/x86/mm/gup.c | 12 |
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 | ||
19 | static 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 | ||
108 | static 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 | |||
108 | static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr, | 118 | static 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++; |