thp: introduce deferred_split_huge_page()
Currently we don't split huge page on partial unmap. It's not an ideal situation. It can lead to memory overhead. Furtunately, we can detect partial unmap on page_remove_rmap(). But we cannot call split_huge_page() from there due to locking context. It's also counterproductive to do directly from munmap() codepath: in many cases we will hit this from exit(2) and splitting the huge page just to free it up in small pages is not what we really want. The patch introduce deferred_split_huge_page() which put the huge page into queue for splitting. The splitting itself will happen when we get memory pressure via shrinker interface. The page will be dropped from list on freeing through compound page destructor. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Tested-by: Sasha Levin <sasha.levin@oracle.com> Tested-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Acked-by: Vlastimil Babka <vbabka@suse.cz> Acked-by: Jerome Marchand <jmarchan@redhat.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Rik van Riel <riel@redhat.com> Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Cc: Steve Capper <steve.capper@linaro.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@suse.cz> Cc: Christoph Lameter <cl@linux.com> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:

committed by
Linus Torvalds

parent
248db92da1
commit
9a982250f7
@@ -90,11 +90,15 @@ extern bool is_vma_temporary_stack(struct vm_area_struct *vma);
|
||||
|
||||
extern unsigned long transparent_hugepage_flags;
|
||||
|
||||
extern void prep_transhuge_page(struct page *page);
|
||||
extern void free_transhuge_page(struct page *page);
|
||||
|
||||
int split_huge_page_to_list(struct page *page, struct list_head *list);
|
||||
static inline int split_huge_page(struct page *page)
|
||||
{
|
||||
return split_huge_page_to_list(page, NULL);
|
||||
}
|
||||
void deferred_split_huge_page(struct page *page);
|
||||
|
||||
void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
|
||||
unsigned long address);
|
||||
@@ -170,6 +174,7 @@ static inline int split_huge_page(struct page *page)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void deferred_split_huge_page(struct page *page) {}
|
||||
#define split_huge_pmd(__vma, __pmd, __address) \
|
||||
do { } while (0)
|
||||
static inline int hugepage_madvise(struct vm_area_struct *vma,
|
||||
|
@@ -507,6 +507,9 @@ enum compound_dtor_id {
|
||||
COMPOUND_PAGE_DTOR,
|
||||
#ifdef CONFIG_HUGETLB_PAGE
|
||||
HUGETLB_PAGE_DTOR,
|
||||
#endif
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
TRANSHUGE_PAGE_DTOR,
|
||||
#endif
|
||||
NR_COMPOUND_DTORS,
|
||||
};
|
||||
@@ -537,6 +540,8 @@ static inline void set_compound_order(struct page *page, unsigned int order)
|
||||
page[1].compound_order = order;
|
||||
}
|
||||
|
||||
void free_compound_page(struct page *page);
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
/*
|
||||
* Do pte_mkwrite, but only if the vma says VM_WRITE. We do this when
|
||||
|
@@ -55,6 +55,7 @@ struct page {
|
||||
*/
|
||||
void *s_mem; /* slab first object */
|
||||
atomic_t compound_mapcount; /* first tail page */
|
||||
/* page_deferred_list().next -- second tail page */
|
||||
};
|
||||
|
||||
/* Second double word */
|
||||
@@ -62,6 +63,7 @@ struct page {
|
||||
union {
|
||||
pgoff_t index; /* Our offset within mapping. */
|
||||
void *freelist; /* sl[aou]b first free object */
|
||||
/* page_deferred_list().prev -- second tail page */
|
||||
};
|
||||
|
||||
union {
|
||||
|
Reference in New Issue
Block a user