diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/task_mmu.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 187b3b5f242e..85ef60fdf2c0 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -451,6 +451,7 @@ struct mem_size_stats { unsigned long private_hugetlb; u64 pss; u64 swap_pss; + bool check_shmem_swap; }; static void smaps_account(struct mem_size_stats *mss, struct page *page, @@ -485,6 +486,45 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page, } } +#ifdef CONFIG_SHMEM +static unsigned long smaps_shmem_swap(struct vm_area_struct *vma, + unsigned long addr) +{ + struct page *page; + + page = find_get_entry(vma->vm_file->f_mapping, + linear_page_index(vma, addr)); + if (!page) + return 0; + + if (radix_tree_exceptional_entry(page)) + return PAGE_SIZE; + + page_cache_release(page); + return 0; + +} + +static int smaps_pte_hole(unsigned long addr, unsigned long end, + struct mm_walk *walk) +{ + struct mem_size_stats *mss = walk->private; + + while (addr < end) { + mss->swap += smaps_shmem_swap(walk->vma, addr); + addr += PAGE_SIZE; + } + + return 0; +} +#else +static unsigned long smaps_shmem_swap(struct vm_area_struct *vma, + unsigned long addr) +{ + return 0; +} +#endif + static void smaps_pte_entry(pte_t *pte, unsigned long addr, struct mm_walk *walk) { @@ -512,6 +552,9 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr, } } else if (is_migration_entry(swpent)) page = migration_entry_to_page(swpent); + } else if (unlikely(IS_ENABLED(CONFIG_SHMEM) && mss->check_shmem_swap + && pte_none(*pte))) { + mss->swap += smaps_shmem_swap(vma, addr); } if (!page) @@ -671,6 +714,14 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) }; memset(&mss, 0, sizeof mss); + +#ifdef CONFIG_SHMEM + if (vma->vm_file && shmem_mapping(vma->vm_file->f_mapping)) { + mss.check_shmem_swap = true; + smaps_walk.pte_hole = smaps_pte_hole; + } +#endif + /* mmap_sem is held in m_start */ walk_page_vma(vma, &smaps_walk); |