aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/mm/gup.c12
-rw-r--r--arch/x86/mm/gup.c12
-rw-r--r--include/linux/mm.h24
-rw-r--r--mm/swap.c90
4 files changed, 129 insertions, 9 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++;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 3b1754ad8785..a2718e1ed585 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -353,9 +353,29 @@ static inline int page_count(struct page *page)
353 353
354static inline void get_page(struct page *page) 354static inline void get_page(struct page *page)
355{ 355{
356 page = compound_head(page); 356 /*
357 VM_BUG_ON(atomic_read(&page->_count) == 0); 357 * Getting a normal page or the head of a compound page
358 * requires to already have an elevated page->_count. Only if
359 * we're getting a tail page, the elevated page->_count is
360 * required only in the head page, so for tail pages the
361 * bugcheck only verifies that the page->_count isn't
362 * negative.
363 */
364 VM_BUG_ON(atomic_read(&page->_count) < !PageTail(page));
358 atomic_inc(&page->_count); 365 atomic_inc(&page->_count);
366 /*
367 * Getting a tail page will elevate both the head and tail
368 * page->_count(s).
369 */
370 if (unlikely(PageTail(page))) {
371 /*
372 * This is safe only because
373 * __split_huge_page_refcount can't run under
374 * get_page().
375 */
376 VM_BUG_ON(atomic_read(&page->first_page->_count) <= 0);
377 atomic_inc(&page->first_page->_count);
378 }
359} 379}
360 380
361static inline struct page *virt_to_head_page(const void *x) 381static inline struct page *virt_to_head_page(const void *x)
diff --git a/mm/swap.c b/mm/swap.c
index 3f4854205b16..33f5292fe132 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -56,17 +56,93 @@ static void __page_cache_release(struct page *page)
56 del_page_from_lru(zone, page); 56 del_page_from_lru(zone, page);
57 spin_unlock_irqrestore(&zone->lru_lock, flags); 57 spin_unlock_irqrestore(&zone->lru_lock, flags);
58 } 58 }
59}
60
61static void __put_single_page(struct page *page)
62{
63 __page_cache_release(page);
59 free_hot_cold_page(page, 0); 64 free_hot_cold_page(page, 0);
60} 65}
61 66
62static void put_compound_page(struct page *page) 67static void __put_compound_page(struct page *page)
63{ 68{
64 page = compound_head(page); 69 compound_page_dtor *dtor;
65 if (put_page_testzero(page)) { 70
66 compound_page_dtor *dtor; 71 __page_cache_release(page);
72 dtor = get_compound_page_dtor(page);
73 (*dtor)(page);
74}
67 75
68 dtor = get_compound_page_dtor(page); 76static void put_compound_page(struct page *page)
69 (*dtor)(page); 77{
78 if (unlikely(PageTail(page))) {
79 /* __split_huge_page_refcount can run under us */
80 struct page *page_head = page->first_page;
81 smp_rmb();
82 /*
83 * If PageTail is still set after smp_rmb() we can be sure
84 * that the page->first_page we read wasn't a dangling pointer.
85 * See __split_huge_page_refcount() smp_wmb().
86 */
87 if (likely(PageTail(page) && get_page_unless_zero(page_head))) {
88 unsigned long flags;
89 /*
90 * Verify that our page_head wasn't converted
91 * to a a regular page before we got a
92 * reference on it.
93 */
94 if (unlikely(!PageHead(page_head))) {
95 /* PageHead is cleared after PageTail */
96 smp_rmb();
97 VM_BUG_ON(PageTail(page));
98 goto out_put_head;
99 }
100 /*
101 * Only run compound_lock on a valid PageHead,
102 * after having it pinned with
103 * get_page_unless_zero() above.
104 */
105 smp_mb();
106 /* page_head wasn't a dangling pointer */
107 flags = compound_lock_irqsave(page_head);
108 if (unlikely(!PageTail(page))) {
109 /* __split_huge_page_refcount run before us */
110 compound_unlock_irqrestore(page_head, flags);
111 VM_BUG_ON(PageHead(page_head));
112 out_put_head:
113 if (put_page_testzero(page_head))
114 __put_single_page(page_head);
115 out_put_single:
116 if (put_page_testzero(page))
117 __put_single_page(page);
118 return;
119 }
120 VM_BUG_ON(page_head != page->first_page);
121 /*
122 * We can release the refcount taken by
123 * get_page_unless_zero now that
124 * split_huge_page_refcount is blocked on the
125 * compound_lock.
126 */
127 if (put_page_testzero(page_head))
128 VM_BUG_ON(1);
129 /* __split_huge_page_refcount will wait now */
130 VM_BUG_ON(atomic_read(&page->_count) <= 0);
131 atomic_dec(&page->_count);
132 VM_BUG_ON(atomic_read(&page_head->_count) <= 0);
133 compound_unlock_irqrestore(page_head, flags);
134 if (put_page_testzero(page_head))
135 __put_compound_page(page_head);
136 } else {
137 /* page_head is a dangling pointer */
138 VM_BUG_ON(PageTail(page));
139 goto out_put_single;
140 }
141 } else if (put_page_testzero(page)) {
142 if (PageHead(page))
143 __put_compound_page(page);
144 else
145 __put_single_page(page);
70 } 146 }
71} 147}
72 148
@@ -75,7 +151,7 @@ void put_page(struct page *page)
75 if (unlikely(PageCompound(page))) 151 if (unlikely(PageCompound(page)))
76 put_compound_page(page); 152 put_compound_page(page);
77 else if (put_page_testzero(page)) 153 else if (put_page_testzero(page))
78 __page_cache_release(page); 154 __put_single_page(page);
79} 155}
80EXPORT_SYMBOL(put_page); 156EXPORT_SYMBOL(put_page);
81 157