diff options
-rw-r--r-- | include/linux/hugetlb.h | 6 | ||||
-rw-r--r-- | include/linux/mm.h | 32 | ||||
-rw-r--r-- | mm/internal.h | 3 | ||||
-rw-r--r-- | mm/swap.c | 33 |
4 files changed, 60 insertions, 14 deletions
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 251233c1494d..d01cc972a1d9 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h | |||
@@ -31,7 +31,6 @@ struct hugepage_subpool *hugepage_new_subpool(long nr_blocks); | |||
31 | void hugepage_put_subpool(struct hugepage_subpool *spool); | 31 | void hugepage_put_subpool(struct hugepage_subpool *spool); |
32 | 32 | ||
33 | int PageHuge(struct page *page); | 33 | int PageHuge(struct page *page); |
34 | int PageHeadHuge(struct page *page_head); | ||
35 | 34 | ||
36 | void reset_vma_resv_huge_pages(struct vm_area_struct *vma); | 35 | void reset_vma_resv_huge_pages(struct vm_area_struct *vma); |
37 | int hugetlb_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); | 36 | int hugetlb_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); |
@@ -104,11 +103,6 @@ static inline int PageHuge(struct page *page) | |||
104 | return 0; | 103 | return 0; |
105 | } | 104 | } |
106 | 105 | ||
107 | static inline int PageHeadHuge(struct page *page_head) | ||
108 | { | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static inline void reset_vma_resv_huge_pages(struct vm_area_struct *vma) | 106 | static inline void reset_vma_resv_huge_pages(struct vm_area_struct *vma) |
113 | { | 107 | { |
114 | } | 108 | } |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 9fac6dd69b11..f95c71b7c1fd 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -414,15 +414,45 @@ static inline int page_count(struct page *page) | |||
414 | return atomic_read(&compound_head(page)->_count); | 414 | return atomic_read(&compound_head(page)->_count); |
415 | } | 415 | } |
416 | 416 | ||
417 | #ifdef CONFIG_HUGETLB_PAGE | ||
418 | extern int PageHeadHuge(struct page *page_head); | ||
419 | #else /* CONFIG_HUGETLB_PAGE */ | ||
420 | static inline int PageHeadHuge(struct page *page_head) | ||
421 | { | ||
422 | return 0; | ||
423 | } | ||
424 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
425 | |||
426 | static inline bool __compound_tail_refcounted(struct page *page) | ||
427 | { | ||
428 | return !PageSlab(page) && !PageHeadHuge(page); | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * This takes a head page as parameter and tells if the | ||
433 | * tail page reference counting can be skipped. | ||
434 | * | ||
435 | * For this to be safe, PageSlab and PageHeadHuge must remain true on | ||
436 | * any given page where they return true here, until all tail pins | ||
437 | * have been released. | ||
438 | */ | ||
439 | static inline bool compound_tail_refcounted(struct page *page) | ||
440 | { | ||
441 | VM_BUG_ON(!PageHead(page)); | ||
442 | return __compound_tail_refcounted(page); | ||
443 | } | ||
444 | |||
417 | static inline void get_huge_page_tail(struct page *page) | 445 | static inline void get_huge_page_tail(struct page *page) |
418 | { | 446 | { |
419 | /* | 447 | /* |
420 | * __split_huge_page_refcount() cannot run | 448 | * __split_huge_page_refcount() cannot run |
421 | * from under us. | 449 | * from under us. |
450 | * In turn no need of compound_trans_head here. | ||
422 | */ | 451 | */ |
423 | VM_BUG_ON(page_mapcount(page) < 0); | 452 | VM_BUG_ON(page_mapcount(page) < 0); |
424 | VM_BUG_ON(atomic_read(&page->_count) != 0); | 453 | VM_BUG_ON(atomic_read(&page->_count) != 0); |
425 | atomic_inc(&page->_mapcount); | 454 | if (compound_tail_refcounted(compound_head(page))) |
455 | atomic_inc(&page->_mapcount); | ||
426 | } | 456 | } |
427 | 457 | ||
428 | extern bool __get_page_tail(struct page *page); | 458 | extern bool __get_page_tail(struct page *page); |
diff --git a/mm/internal.h b/mm/internal.h index 684f7aa9692a..a85a3ab1f7ef 100644 --- a/mm/internal.h +++ b/mm/internal.h | |||
@@ -51,7 +51,8 @@ static inline void __get_page_tail_foll(struct page *page, | |||
51 | VM_BUG_ON(page_mapcount(page) < 0); | 51 | VM_BUG_ON(page_mapcount(page) < 0); |
52 | if (get_page_head) | 52 | if (get_page_head) |
53 | atomic_inc(&page->first_page->_count); | 53 | atomic_inc(&page->first_page->_count); |
54 | atomic_inc(&page->_mapcount); | 54 | if (compound_tail_refcounted(page->first_page)) |
55 | atomic_inc(&page->_mapcount); | ||
55 | } | 56 | } |
56 | 57 | ||
57 | /* | 58 | /* |
@@ -88,8 +88,9 @@ static void put_compound_page(struct page *page) | |||
88 | 88 | ||
89 | /* | 89 | /* |
90 | * THP can not break up slab pages so avoid taking | 90 | * THP can not break up slab pages so avoid taking |
91 | * compound_lock(). Slab performs non-atomic bit ops | 91 | * compound_lock() and skip the tail page refcounting |
92 | * on page->flags for better performance. In | 92 | * (in _mapcount) too. Slab performs non-atomic bit |
93 | * ops on page->flags for better performance. In | ||
93 | * particular slab_unlock() in slub used to be a hot | 94 | * particular slab_unlock() in slub used to be a hot |
94 | * path. It is still hot on arches that do not support | 95 | * path. It is still hot on arches that do not support |
95 | * this_cpu_cmpxchg_double(). | 96 | * this_cpu_cmpxchg_double(). |
@@ -102,7 +103,7 @@ static void put_compound_page(struct page *page) | |||
102 | * PageTail clear after smp_rmb() and we'll treat it | 103 | * PageTail clear after smp_rmb() and we'll treat it |
103 | * as a single page. | 104 | * as a single page. |
104 | */ | 105 | */ |
105 | if (PageSlab(page_head) || PageHeadHuge(page_head)) { | 106 | if (!__compound_tail_refcounted(page_head)) { |
106 | /* | 107 | /* |
107 | * If "page" is a THP tail, we must read the tail page | 108 | * If "page" is a THP tail, we must read the tail page |
108 | * flags after the head page flags. The | 109 | * flags after the head page flags. The |
@@ -117,10 +118,30 @@ static void put_compound_page(struct page *page) | |||
117 | * cannot race here. | 118 | * cannot race here. |
118 | */ | 119 | */ |
119 | VM_BUG_ON(!PageHead(page_head)); | 120 | VM_BUG_ON(!PageHead(page_head)); |
120 | VM_BUG_ON(page_mapcount(page) <= 0); | 121 | VM_BUG_ON(page_mapcount(page) != 0); |
121 | atomic_dec(&page->_mapcount); | 122 | if (put_page_testzero(page_head)) { |
122 | if (put_page_testzero(page_head)) | 123 | /* |
124 | * If this is the tail of a | ||
125 | * slab compound page, the | ||
126 | * tail pin must not be the | ||
127 | * last reference held on the | ||
128 | * page, because the PG_slab | ||
129 | * cannot be cleared before | ||
130 | * all tail pins (which skips | ||
131 | * the _mapcount tail | ||
132 | * refcounting) have been | ||
133 | * released. For hugetlbfs the | ||
134 | * tail pin may be the last | ||
135 | * reference on the page | ||
136 | * instead, because | ||
137 | * PageHeadHuge will not go | ||
138 | * away until the compound | ||
139 | * page enters the buddy | ||
140 | * allocator. | ||
141 | */ | ||
142 | VM_BUG_ON(PageSlab(page_head)); | ||
123 | __put_compound_page(page_head); | 143 | __put_compound_page(page_head); |
144 | } | ||
124 | return; | 145 | return; |
125 | } else | 146 | } else |
126 | /* | 147 | /* |