Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: thp: optimize compound_trans_huge

Currently we don't clobber page_tail->first_page during split_huge_page,
so compound_trans_head can be set to compound_head without adverse
effects, and this mostly optimizes away a smp_rmb.

It looks worthwhile to keep around the implementation that doesn't relay
on page_tail->first_page not to be clobbered, because it would be
necessary if we'll decide to enforce page->private to zero at all times
whenever PG_private is not set, also for anonymous pages. For anonymous
pages enforcing such an invariant doesn't matter as anonymous pages
don't use page->private so we can get away with this microoptimization.

Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Cc: Khalid Aziz <khalid.aziz@oracle.com>
Cc: Pravin Shelar <pshelar@nicira.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Ben Hutchings <bhutchings@solarflare.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Johannes Weiner <jweiner@redhat.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Rik van Riel <riel@redhat.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Minchan Kim <minchan@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andrea Arcangeli and committed by
Linus Torvalds
ca641514 ebf360f9

+23
+23
include/linux/huge_mm.h
··· 157 157 return HPAGE_PMD_NR; 158 158 return 1; 159 159 } 160 + /* 161 + * compound_trans_head() should be used instead of compound_head(), 162 + * whenever the "page" passed as parameter could be the tail of a 163 + * transparent hugepage that could be undergoing a 164 + * __split_huge_page_refcount(). The page structure layout often 165 + * changes across releases and it makes extensive use of unions. So if 166 + * the page structure layout will change in a way that 167 + * page->first_page gets clobbered by __split_huge_page_refcount, the 168 + * implementation making use of smp_rmb() will be required. 169 + * 170 + * Currently we define compound_trans_head as compound_head, because 171 + * page->private is in the same union with page->first_page, and 172 + * page->private isn't clobbered. However this also means we're 173 + * currently leaving dirt into the page->private field of anonymous 174 + * pages resulting from a THP split, instead of setting page->private 175 + * to zero like for every other page that has PG_private not set. But 176 + * anonymous pages don't use page->private so this is not a problem. 177 + */ 178 + #if 0 179 + /* This will be needed if page->private will be clobbered in split_huge_page */ 160 180 static inline struct page *compound_trans_head(struct page *page) 161 181 { 162 182 if (PageTail(page)) { ··· 194 174 } 195 175 return page; 196 176 } 177 + #else 178 + #define compound_trans_head(page) compound_head(page) 179 + #endif 197 180 198 181 extern int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, 199 182 unsigned long addr, pmd_t pmd, pmd_t *pmdp);