Skip to content

Commit

Permalink
mm: shmem: fix khugepaged activation policy for shmem
Browse files Browse the repository at this point in the history
Shmem has a separate interface (different from anonymous pages) to control
huge page allocation, that means shmem THP can be enabled while anonymous
THP is disabled.  However, in this case, khugepaged will not start to
collapse shmem THP, which is unreasonable.

To fix this issue, we should call start_stop_khugepaged() to activate or
deactivate the khugepaged thread when setting shmem mTHP interfaces. 
Moreover, add a new helper shmem_hpage_pmd_enabled() to help to check
whether shmem THP is enabled, which will determine if khugepaged should be
activated.

Link: https://lkml.kernel.org/r/9b9c6cbc4499bf44c6455367fd9e0f6036525680.1726978977.git.baolin.wang@linux.alibaba.com
Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reported-by: Ryan Roberts <ryan.roberts@arm.com>
Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
  • Loading branch information
Baolin Wang authored and Andrew Morton committed Nov 6, 2024
1 parent f8f55e9 commit d2d243d
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 3 deletions.
6 changes: 6 additions & 0 deletions include/linux/shmem_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,19 @@ int shmem_unuse(unsigned int type);
unsigned long shmem_allowable_huge_orders(struct inode *inode,
struct vm_area_struct *vma, pgoff_t index,
loff_t write_end, bool shmem_huge_force);
bool shmem_hpage_pmd_enabled(void);
#else
static inline unsigned long shmem_allowable_huge_orders(struct inode *inode,
struct vm_area_struct *vma, pgoff_t index,
loff_t write_end, bool shmem_huge_force)
{
return 0;
}

static inline bool shmem_hpage_pmd_enabled(void)
{
return false;
}
#endif

#ifdef CONFIG_SHMEM
Expand Down
6 changes: 5 additions & 1 deletion mm/khugepaged.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,9 +416,11 @@ static inline int hpage_collapse_test_exit_or_disable(struct mm_struct *mm)
static bool hugepage_pmd_enabled(void)
{
/*
* We cover both the anon and the file-backed case here; file-backed
* We cover the anon, shmem and the file-backed case here; file-backed
* hugepages, when configured in, are determined by the global control.
* Anon pmd-sized hugepages are determined by the pmd-size control.
* Shmem pmd-sized hugepages are also determined by its pmd-size control,
* except when the global shmem_huge is set to SHMEM_HUGE_DENY.
*/
if (IS_ENABLED(CONFIG_READ_ONLY_THP_FOR_FS) &&
hugepage_global_enabled())
Expand All @@ -430,6 +432,8 @@ static bool hugepage_pmd_enabled(void)
if (test_bit(PMD_ORDER, &huge_anon_orders_inherit) &&
hugepage_global_enabled())
return true;
if (IS_ENABLED(CONFIG_SHMEM) && shmem_hpage_pmd_enabled())
return true;
return false;
}

Expand Down
29 changes: 27 additions & 2 deletions mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,23 @@ static gfp_t limit_gfp_mask(gfp_t huge_gfp, gfp_t limit_gfp)
}

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
bool shmem_hpage_pmd_enabled(void)
{
if (shmem_huge == SHMEM_HUGE_DENY)
return false;
if (test_bit(HPAGE_PMD_ORDER, &huge_shmem_orders_always))
return true;
if (test_bit(HPAGE_PMD_ORDER, &huge_shmem_orders_madvise))
return true;
if (test_bit(HPAGE_PMD_ORDER, &huge_shmem_orders_within_size))
return true;
if (test_bit(HPAGE_PMD_ORDER, &huge_shmem_orders_inherit) &&
shmem_huge != SHMEM_HUGE_NEVER)
return true;

return false;
}

unsigned long shmem_allowable_huge_orders(struct inode *inode,
struct vm_area_struct *vma, pgoff_t index,
loff_t write_end, bool shmem_huge_force)
Expand Down Expand Up @@ -5024,7 +5041,7 @@ static ssize_t shmem_enabled_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
char tmp[16];
int huge;
int huge, err;

if (count + 1 > sizeof(tmp))
return -EINVAL;
Expand All @@ -5048,7 +5065,9 @@ static ssize_t shmem_enabled_store(struct kobject *kobj,
shmem_huge = huge;
if (shmem_huge > SHMEM_HUGE_DENY)
SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
return count;

err = start_stop_khugepaged();
return err ? err : count;
}

struct kobj_attribute shmem_enabled_attr = __ATTR_RW(shmem_enabled);
Expand Down Expand Up @@ -5125,6 +5144,12 @@ static ssize_t thpsize_shmem_enabled_store(struct kobject *kobj,
ret = -EINVAL;
}

if (ret > 0) {
int err = start_stop_khugepaged();

if (err)
ret = err;
}
return ret;
}

Expand Down

0 comments on commit d2d243d

Please sign in to comment.