【安卓源码】简单分析smaps节点

smap节点,位于/proc/{pid}/smaps。

通过这个节点可以看到一个进程映射的内存信息,不会包括设备使用的内存,比如gpumem。

smaps节点内核定义

kernel/msm-4.19/fs/proc/base.c
    
#ifdef CONFIG_PROC_PAGE_MONITOR
    REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
    REG("smaps",     S_IRUGO, proc_pid_smaps_operations),
    REG("smaps_rollup", S_IRUGO, proc_pid_smaps_rollup_operations),
    REG("pagemap",    S_IRUSR, proc_pagemap_operations),
#endif
​
​
kernel/msm-4.19/fs/proc/task_mmu.c
    
const struct file_operations proc_pid_smaps_operations = {
    .open       = pid_smaps_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = proc_map_release,
};

open系统调用分析

对smaps节点的open系统调用,我觉得应该类似binder_open,打开这个节点做一些初始化工作

调用堆栈如下:

kernel/msm-4.19/fs/proc/task_mmu.c    pid_smaps_open()
    --->kernel/msm-4.19/fs/proc/task_mmu.c    do_maps_open()
        --->kernel/msm-4.19/fs/proc/task_mmu.c    proc_maps_open()

重点看一下阿proc_maps_open函数调用了__seq_open_private方法,这一番操作实际上是把smaps文件与proc_pid_smaps_op关联上。

实际上就是在seq_file结构体的seq_operations指针上放了proc_pid_smaps_op,之后对smaps进行cat操作就会执行到show_smap()方法。

具体的细节可以按照

kernel/msm-4.19/fs/proc/task_mmu.c    
    
 static int proc_maps_open(struct inode *inode, struct file *file,
            const struct seq_operations *ops, int psize)
{
     //在这里初始化,关联了seq_file的proc_pid_smaps_op
    struct proc_maps_private *priv = __seq_open_private(file, ops, psize);
​
    priv->inode = inode;
    priv->mm = proc_mem_open(inode, PTRACE_MODE_READ);
    if (IS_ERR(priv->mm)) {
        int err = PTR_ERR(priv->mm);
​
        seq_release_private(inode, file);
        return err;
    }
​
    return 0;
}  
​
kernel/msm-4.19/include/linux/seq_file.h
    
struct seq_file {
    char *buf;
    size_t size;
    size_t from;
    size_t count;
    size_t pad_until;
    loff_t index;
    loff_t read_pos;
    u64 version;
    struct mutex lock;
    const struct seq_operations *op;
    int poll_event;
    const struct file *file;
    void *private;
};
​

show方法分析

在执行cat /proc/{pid}/smaps之后,会执行下面的调用栈。

在调用栈(2)的smap_gather_stats()函数中,会初始化一个mm_walk结构体,并设置smaps_pte_range()函数作为回调,

所以在smap_gather_stats()函数最后执行walk_page_vma()后,遍历页表时会回调smaps_pte_range()函数。

然后在smaps_account方法中把VMA的所有子项与结构体mem_size_stats关联起来。

最后在show_smap方法里就可以通过打印mem_size_stats中的数据,将一个进程的一块VMA信息打印出来了。

分析到这里,可以知道smaps节点的信息都是从mm_struct中的vma中获得的。

调用栈:

1. kernel/msm-4.19/fs/proc/task_mmu.c    show_smap()
2.     --->kernel/msm-4.19/fs/proc/task_mmu.c    smap_gather_stats()
3.       --->kernel/msm-4.19/mm/pagewalk.c    walk_page_vma()
4.          --->kernel/msm-4.19/mm/pagewalk.c    __walk_page_range()
5.              --->kernel/msm-4.19/mm/pagewalk.c    walk_pgd_range()
6.                  --->kernel/msm-4.19/mm/pagewalk.c    walk_p4d_range()
7.                      --->kernel/msm-4.19/mm/pagewalk.c    walk_pud_range()
8.                          --->kernel/msm-4.19/mm/pagewalk.c    walk_pmd_range()
9.                              --->kernel/msm-4.19/fs/proc/task_mmu.c    smaps_pte_range()
10.                                 --->kernel/msm-4.19/fs/proc/task_mmu.c    smaps_pte_entry()
11.                                     --->kernel/msm-4.19/fs/proc/task_mmu.c    smaps_account()

每执行一次,会打印smaps节点的一块VMA信息,如下:

在这里插入图片描述

kernel/msm-4.19/fs/proc/task_mmu.c
    
static const struct seq_operations proc_pid_smaps_op = {
    .start  = m_start,
    .next   = m_next,
    .stop   = m_stop,
    .show   = show_smap
};
​
​
static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
               struct mm_walk *walk)
{
    struct vm_area_struct *vma = walk->vma;
    pte_t *pte;
    spinlock_t *ptl;
​
    ptl = pmd_trans_huge_lock(pmd, vma);
    ...
    /*
     * The mmap_sem held all the way back in m_start() is what
     * keeps khugepaged out of here and from collapsing things
     * in here.
     */
    pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
    for (; addr != end; pte++, addr += PAGE_SIZE)
        //在这里遍历此vma的每一个页表项
        smaps_pte_entry(pte, addr, walk);
    pte_unmap_unlock(pte - 1, ptl);
​
    return 0;
}
​
​

\

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值