Skip to content

Commit f3f0e1d

Browse files
kiryltorvalds
authored andcommitted
khugepaged: add support of collapse for tmpfs/shmem pages
This patch extends khugepaged to support collapse of tmpfs/shmem pages. We share fair amount of infrastructure with anon-THP collapse. Few design points: - First we are looking for VMA which can be suitable for mapping huge page; - If the VMA maps shmem file, the rest scan/collapse operations operates on page cache, not on page tables as in anon VMA case. - khugepaged_scan_shmem() finds a range which is suitable for huge page. The scan is lockless and shouldn't disturb system too much. - once the candidate for collapse is found, collapse_shmem() attempts to create a huge page: + scan over radix tree, making the range point to new huge page; + new huge page is not-uptodate, locked and freezed (refcount is 0), so nobody can touch them until we say so. + we swap in pages during the scan. khugepaged_scan_shmem() filters out ranges with more than khugepaged_max_ptes_swap swapped out pages. It's HPAGE_PMD_NR/8 by default. + old pages are isolated, unmapped and put to local list in case to be restored back if collapse failed. - if collapse succeed, we retract pte page tables from VMAs where huge pages mapping is possible. The huge page will be mapped as PMD on next minor fault into the range. Link: http://lkml.kernel.org/r/1466021202-61880-35-git-send-email-kirill.shutemov@linux.intel.com Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 4595ef8 commit f3f0e1d

File tree

4 files changed

+500
-17
lines changed

4 files changed

+500
-17
lines changed

include/linux/shmem_fs.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
5454
unsigned long len, unsigned long pgoff, unsigned long flags);
5555
extern int shmem_lock(struct file *file, int lock, struct user_struct *user);
5656
extern bool shmem_mapping(struct address_space *mapping);
57+
extern bool shmem_huge_enabled(struct vm_area_struct *vma);
5758
extern void shmem_unlock_mapping(struct address_space *mapping);
5859
extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
5960
pgoff_t index, gfp_t gfp_mask);
@@ -64,13 +65,35 @@ extern unsigned long shmem_swap_usage(struct vm_area_struct *vma);
6465
extern unsigned long shmem_partial_swap_usage(struct address_space *mapping,
6566
pgoff_t start, pgoff_t end);
6667

68+
/* Flag allocation requirements to shmem_getpage */
69+
enum sgp_type {
70+
SGP_READ, /* don't exceed i_size, don't allocate page */
71+
SGP_CACHE, /* don't exceed i_size, may allocate page */
72+
SGP_NOHUGE, /* like SGP_CACHE, but no huge pages */
73+
SGP_HUGE, /* like SGP_CACHE, huge pages preferred */
74+
SGP_WRITE, /* may exceed i_size, may allocate !Uptodate page */
75+
SGP_FALLOC, /* like SGP_WRITE, but make existing page Uptodate */
76+
};
77+
78+
extern int shmem_getpage(struct inode *inode, pgoff_t index,
79+
struct page **pagep, enum sgp_type sgp);
80+
6781
static inline struct page *shmem_read_mapping_page(
6882
struct address_space *mapping, pgoff_t index)
6983
{
7084
return shmem_read_mapping_page_gfp(mapping, index,
7185
mapping_gfp_mask(mapping));
7286
}
7387

88+
static inline bool shmem_file(struct file *file)
89+
{
90+
if (!IS_ENABLED(CONFIG_SHMEM))
91+
return false;
92+
if (!file || !file->f_mapping)
93+
return false;
94+
return shmem_mapping(file->f_mapping);
95+
}
96+
7497
extern bool shmem_charge(struct inode *inode, long pages);
7598
extern void shmem_uncharge(struct inode *inode, long pages);
7699

include/trace/events/huge_memory.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
EM( SCAN_DEL_PAGE_LRU, "could_not_delete_page_from_lru")\
3030
EM( SCAN_ALLOC_HUGE_PAGE_FAIL, "alloc_huge_page_failed") \
3131
EM( SCAN_CGROUP_CHARGE_FAIL, "ccgroup_charge_failed") \
32-
EMe( SCAN_EXCEED_SWAP_PTE, "exceed_swap_pte")
32+
EM( SCAN_EXCEED_SWAP_PTE, "exceed_swap_pte") \
33+
EMe(SCAN_TRUNCATED, "truncated") \
3334

3435
#undef EM
3536
#undef EMe

0 commit comments

Comments
 (0)