Support numa_maps Signed-off-by: Yin Tirui <yintirui@huawei.com> --- mm/share_pool.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 4 deletions(-) diff --git a/mm/share_pool.c b/mm/share_pool.c index b6e543f1cefc..4e11c60db2fc 100644 --- a/mm/share_pool.c +++ b/mm/share_pool.c @@ -3984,11 +3984,125 @@ static void get_process_non_sp_res(unsigned long total_rss, unsigned long shmem, static void print_process_prot(struct seq_file *seq, unsigned long prot) { if (prot == PROT_READ) - seq_puts(seq, "R"); + seq_printf(seq, "%-4s ", "R"); else if (prot == (PROT_READ | PROT_WRITE)) - seq_puts(seq, "RW"); + seq_printf(seq, "%-4s ", "RW"); else - seq_puts(seq, "-"); + seq_printf(seq, "%-4s ", "-"); +} + +static int sp_numa_pte_entry(pte_t *pte, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + unsigned long *size_array = walk->private; + pte_t entry = ptep_get(pte); + struct page *page; + int nid; + + if (pte_present(entry)) { + if (is_zero_pfn(pte_pfn(entry))) + return 0; + + page = pte_page(entry); + if (page && !PageReserved(page)) { + nid = page_to_nid(page); + if (nid >= 0 && nid < MAX_NUMNODES) + size_array[nid] += PAGE_SIZE; + } + } + return 0; +} + +static int sp_numa_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + unsigned long *size_array = walk->private; + pmd_t entry = pmdp_get(pmd); + struct page *page; + int nid; + + if (pmd_present(entry) && pmd_huge(entry)) { + if (is_zero_pfn(pmd_pfn(entry))) + goto skip; + + page = pmd_page(entry); + if (page && !PageReserved(page)) { + nid = page_to_nid(page); + if (nid >= 0 && nid < MAX_NUMNODES) + size_array[nid] += PMD_SIZE; + } +skip: + walk->action = ACTION_CONTINUE; + } + return 0; +} + +static int sp_numa_hugetlb_entry(pte_t *ptep, unsigned long hmask, + unsigned long addr, unsigned long next, + struct mm_walk *walk) +{ + unsigned long *size_array = walk->private; + pte_t pte = huge_ptep_get(ptep); + struct page *page; + int nid; + + if (pte_present(pte)) { + if (is_zero_pfn(pte_pfn(pte))) + return 0; + page = pte_page(pte); + if (page && !PageReserved(page)) { + nid = page_to_nid(page); + if (nid >= 0 && nid < MAX_NUMNODES) + size_array[nid] += (~hmask + 1); + } + } + return 0; +} + +static const struct mm_walk_ops sp_numa_walk_ops = { + .pte_entry = sp_numa_pte_entry, + .pmd_entry = sp_numa_pmd_entry, + .hugetlb_entry = sp_numa_hugetlb_entry, +}; + +static void print_process_numa_maps(struct seq_file *seq, struct sp_group_node *spg_node) +{ + struct mm_struct *mm = spg_node->master->mm; + struct sp_group *spg = spg_node->spg; + unsigned long size[MAX_NUMNODES] = {0}; + struct rb_node *p, *n; + struct sp_area *spa; + int nid, ret; + + if (!mmget_not_zero(mm)) + goto out; + + for (p = rb_first(&spg->spa_root); p; p = n) { + n = rb_next(p); + spa = container_of(p, struct sp_area, spg_link); + + if (spa->type != SPA_TYPE_ALLOC || + spa->applier != spg_node->master->tgid) + continue; + + mmap_read_lock(mm); + ret = walk_page_range(mm, spa->va_start, spa->va_start + spa_size(spa), + &sp_numa_walk_ops, size); + mmap_read_unlock(mm); + if (ret < 0) { + pr_err_ratelimited("walk_page_range failed %d for 0x%lx.\n", + ret, spa->va_start); + continue; + } + + cond_resched(); + } + + mmput_async(mm); + +out: + for_each_node_state(nid, N_MEMORY) + seq_printf(seq, "%-9ld ", byte2kb(size[nid])); } static void spa_stat_of_mapping_show(struct seq_file *seq, struct sp_mapping *spm) @@ -4180,6 +4294,7 @@ static int proc_usage_by_group(int id, void *p, void *data) page2kb(mm->total_vm), page2kb(total_rss), page2kb(shmem)); print_process_prot(seq, spg_node->prot); + print_process_numa_maps(seq, spg_node); seq_putc(seq, '\n'); } up_read(&spg->rw_lock); @@ -4190,6 +4305,8 @@ static int proc_usage_by_group(int id, void *p, void *data) static int proc_group_usage_show(struct seq_file *seq, void *offset) { + int nid; + if (!should_show_statistics()) return -EPERM; @@ -4197,10 +4314,15 @@ static int proc_group_usage_show(struct seq_file *seq, void *offset) spa_overview_show(seq); /* print the file header */ - seq_printf(seq, "%-8s %-8s %-9s %-9s %-9s %-8s %-7s %-7s %-4s\n", + seq_printf(seq, "%-8s %-8s %-9s %-9s %-9s %-8s %-7s %-7s %-4s ", "PID", "Group_ID", "SP_ALLOC", "SP_K2U", "SP_RES", "VIRT", "RES", "Shm", "PROT"); + for_each_node_state(nid, N_MEMORY) + seq_printf(seq, "N%-8d ", nid); + + seq_putc(seq, '\n'); + down_read(&sp_global_sem); idr_for_each(&sp_group_idr, proc_usage_by_group, seq); up_read(&sp_global_sem); -- 2.43.0