diff options
-rw-r--r-- | include/linux/mm.h | 2 | ||||
-rw-r--r-- | mm/swap.c | 37 |
2 files changed, 37 insertions, 2 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h index aa20bafa40f6..ce26716238c3 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -321,6 +321,7 @@ static inline int is_vmalloc_or_module_addr(const void *x) | |||
321 | static inline void compound_lock(struct page *page) | 321 | static inline void compound_lock(struct page *page) |
322 | { | 322 | { |
323 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 323 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
324 | VM_BUG_ON(PageSlab(page)); | ||
324 | bit_spin_lock(PG_compound_lock, &page->flags); | 325 | bit_spin_lock(PG_compound_lock, &page->flags); |
325 | #endif | 326 | #endif |
326 | } | 327 | } |
@@ -328,6 +329,7 @@ static inline void compound_lock(struct page *page) | |||
328 | static inline void compound_unlock(struct page *page) | 329 | static inline void compound_unlock(struct page *page) |
329 | { | 330 | { |
330 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 331 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
332 | VM_BUG_ON(PageSlab(page)); | ||
331 | bit_spin_unlock(PG_compound_lock, &page->flags); | 333 | bit_spin_unlock(PG_compound_lock, &page->flags); |
332 | #endif | 334 | #endif |
333 | } | 335 | } |
@@ -82,6 +82,25 @@ static void put_compound_page(struct page *page) | |||
82 | if (likely(page != page_head && | 82 | if (likely(page != page_head && |
83 | get_page_unless_zero(page_head))) { | 83 | get_page_unless_zero(page_head))) { |
84 | unsigned long flags; | 84 | unsigned long flags; |
85 | |||
86 | /* | ||
87 | * THP can not break up slab pages so avoid taking | ||
88 | * compound_lock(). Slab performs non-atomic bit ops | ||
89 | * on page->flags for better performance. In particular | ||
90 | * slab_unlock() in slub used to be a hot path. It is | ||
91 | * still hot on arches that do not support | ||
92 | * this_cpu_cmpxchg_double(). | ||
93 | */ | ||
94 | if (PageSlab(page_head)) { | ||
95 | if (PageTail(page)) { | ||
96 | if (put_page_testzero(page_head)) | ||
97 | VM_BUG_ON(1); | ||
98 | |||
99 | atomic_dec(&page->_mapcount); | ||
100 | goto skip_lock_tail; | ||
101 | } else | ||
102 | goto skip_lock; | ||
103 | } | ||
85 | /* | 104 | /* |
86 | * page_head wasn't a dangling pointer but it | 105 | * page_head wasn't a dangling pointer but it |
87 | * may not be a head page anymore by the time | 106 | * may not be a head page anymore by the time |
@@ -92,10 +111,10 @@ static void put_compound_page(struct page *page) | |||
92 | if (unlikely(!PageTail(page))) { | 111 | if (unlikely(!PageTail(page))) { |
93 | /* __split_huge_page_refcount run before us */ | 112 | /* __split_huge_page_refcount run before us */ |
94 | compound_unlock_irqrestore(page_head, flags); | 113 | compound_unlock_irqrestore(page_head, flags); |
95 | VM_BUG_ON(PageHead(page_head)); | 114 | skip_lock: |
96 | if (put_page_testzero(page_head)) | 115 | if (put_page_testzero(page_head)) |
97 | __put_single_page(page_head); | 116 | __put_single_page(page_head); |
98 | out_put_single: | 117 | out_put_single: |
99 | if (put_page_testzero(page)) | 118 | if (put_page_testzero(page)) |
100 | __put_single_page(page); | 119 | __put_single_page(page); |
101 | return; | 120 | return; |
@@ -115,6 +134,8 @@ static void put_compound_page(struct page *page) | |||
115 | VM_BUG_ON(atomic_read(&page_head->_count) <= 0); | 134 | VM_BUG_ON(atomic_read(&page_head->_count) <= 0); |
116 | VM_BUG_ON(atomic_read(&page->_count) != 0); | 135 | VM_BUG_ON(atomic_read(&page->_count) != 0); |
117 | compound_unlock_irqrestore(page_head, flags); | 136 | compound_unlock_irqrestore(page_head, flags); |
137 | |||
138 | skip_lock_tail: | ||
118 | if (put_page_testzero(page_head)) { | 139 | if (put_page_testzero(page_head)) { |
119 | if (PageHead(page_head)) | 140 | if (PageHead(page_head)) |
120 | __put_compound_page(page_head); | 141 | __put_compound_page(page_head); |
@@ -162,6 +183,18 @@ bool __get_page_tail(struct page *page) | |||
162 | struct page *page_head = compound_trans_head(page); | 183 | struct page *page_head = compound_trans_head(page); |
163 | 184 | ||
164 | if (likely(page != page_head && get_page_unless_zero(page_head))) { | 185 | if (likely(page != page_head && get_page_unless_zero(page_head))) { |
186 | |||
187 | /* Ref to put_compound_page() comment. */ | ||
188 | if (PageSlab(page_head)) { | ||
189 | if (likely(PageTail(page))) { | ||
190 | __get_page_tail_foll(page, false); | ||
191 | return true; | ||
192 | } else { | ||
193 | put_page(page_head); | ||
194 | return false; | ||
195 | } | ||
196 | } | ||
197 | |||
165 | /* | 198 | /* |
166 | * page_head wasn't a dangling pointer but it | 199 | * page_head wasn't a dangling pointer but it |
167 | * may not be a head page anymore by the time | 200 | * may not be a head page anymore by the time |