thp: add compound_trans_head() helper
Cleanup some code with common compound_trans_head helper. Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Johannes Weiner <jweiner@redhat.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: Avi Kivity <avi@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
29ad768cfc
commit
22e5c47ee2
3 changed files with 35 additions and 36 deletions
|
@ -126,6 +126,23 @@ static inline int hpage_nr_pages(struct page *page)
|
||||||
return HPAGE_PMD_NR;
|
return HPAGE_PMD_NR;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
static inline struct page *compound_trans_head(struct page *page)
|
||||||
|
{
|
||||||
|
if (PageTail(page)) {
|
||||||
|
struct page *head;
|
||||||
|
head = page->first_page;
|
||||||
|
smp_rmb();
|
||||||
|
/*
|
||||||
|
* head may be a dangling pointer.
|
||||||
|
* __split_huge_page_refcount clears PageTail before
|
||||||
|
* overwriting first_page, so if PageTail is still
|
||||||
|
* there it means the head pointer isn't dangling.
|
||||||
|
*/
|
||||||
|
if (PageTail(page))
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
#else /* CONFIG_TRANSPARENT_HUGEPAGE */
|
#else /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||||
#define HPAGE_PMD_SHIFT ({ BUG(); 0; })
|
#define HPAGE_PMD_SHIFT ({ BUG(); 0; })
|
||||||
#define HPAGE_PMD_MASK ({ BUG(); 0; })
|
#define HPAGE_PMD_MASK ({ BUG(); 0; })
|
||||||
|
@ -144,6 +161,7 @@ static inline int split_huge_page(struct page *page)
|
||||||
do { } while (0)
|
do { } while (0)
|
||||||
#define wait_split_huge_page(__anon_vma, __pmd) \
|
#define wait_split_huge_page(__anon_vma, __pmd) \
|
||||||
do { } while (0)
|
do { } while (0)
|
||||||
|
#define compound_trans_head(page) compound_head(page)
|
||||||
static inline int hugepage_madvise(struct vm_area_struct *vma,
|
static inline int hugepage_madvise(struct vm_area_struct *vma,
|
||||||
unsigned long *vm_flags, int advice)
|
unsigned long *vm_flags, int advice)
|
||||||
{
|
{
|
||||||
|
|
15
mm/ksm.c
15
mm/ksm.c
|
@ -415,20 +415,11 @@ static void break_cow(struct rmap_item *rmap_item)
|
||||||
static struct page *page_trans_compound_anon(struct page *page)
|
static struct page *page_trans_compound_anon(struct page *page)
|
||||||
{
|
{
|
||||||
if (PageTransCompound(page)) {
|
if (PageTransCompound(page)) {
|
||||||
struct page *head;
|
struct page *head = compound_trans_head(page);
|
||||||
head = compound_head(page);
|
|
||||||
/*
|
/*
|
||||||
* head may be a dangling pointer.
|
* head may actually be splitted and freed from under
|
||||||
* __split_huge_page_refcount clears PageTail
|
* us but it's ok here.
|
||||||
* before overwriting first_page, so if
|
|
||||||
* PageTail is still there it means the head
|
|
||||||
* pointer isn't dangling.
|
|
||||||
*/
|
*/
|
||||||
if (head != page) {
|
|
||||||
smp_rmb();
|
|
||||||
if (!PageTransCompound(page))
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (PageAnon(head))
|
if (PageAnon(head))
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,35 +104,25 @@ static pfn_t fault_pfn;
|
||||||
inline int kvm_is_mmio_pfn(pfn_t pfn)
|
inline int kvm_is_mmio_pfn(pfn_t pfn)
|
||||||
{
|
{
|
||||||
if (pfn_valid(pfn)) {
|
if (pfn_valid(pfn)) {
|
||||||
struct page *head;
|
int reserved;
|
||||||
struct page *tail = pfn_to_page(pfn);
|
struct page *tail = pfn_to_page(pfn);
|
||||||
head = compound_head(tail);
|
struct page *head = compound_trans_head(tail);
|
||||||
|
reserved = PageReserved(head);
|
||||||
if (head != tail) {
|
if (head != tail) {
|
||||||
smp_rmb();
|
|
||||||
/*
|
/*
|
||||||
* head may be a dangling pointer.
|
* "head" is not a dangling pointer
|
||||||
* __split_huge_page_refcount clears PageTail
|
* (compound_trans_head takes care of that)
|
||||||
* before overwriting first_page, so if
|
* but the hugepage may have been splitted
|
||||||
* PageTail is still there it means the head
|
* from under us (and we may not hold a
|
||||||
* pointer isn't dangling.
|
* reference count on the head page so it can
|
||||||
|
* be reused before we run PageReferenced), so
|
||||||
|
* we've to check PageTail before returning
|
||||||
|
* what we just read.
|
||||||
*/
|
*/
|
||||||
if (PageTail(tail)) {
|
|
||||||
/*
|
|
||||||
* the "head" is not a dangling
|
|
||||||
* pointer but the hugepage may have
|
|
||||||
* been splitted from under us (and we
|
|
||||||
* may not hold a reference count on
|
|
||||||
* the head page so it can be reused
|
|
||||||
* before we run PageReferenced), so
|
|
||||||
* we've to recheck PageTail before
|
|
||||||
* returning what we just read.
|
|
||||||
*/
|
|
||||||
int reserved = PageReserved(head);
|
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
if (PageTail(tail))
|
if (PageTail(tail))
|
||||||
return reserved;
|
return reserved;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return PageReserved(tail);
|
return PageReserved(tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue