【安卓源码】简单分析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;
}
​
​

\

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: /proc/2042/smaps是一个特殊的文件,它提供了关于进程2042的虚拟内存映射的详细信息。当我们执行cat /proc/2042/smaps时,实际上是在读取该进程对应的虚拟内存区间的信息。这个过程涉及到两个主要步骤:open()和read()。首先,用户态的open("/proc/2042/smaps")函数会陷入内核,通过/proc/2042/smaps文件相关的inode来找到进程2042的相关信息,并将这些信息搜集到proc_maps_private结构中。然后,open()函数将proc_maps_private结构和smaps文件的具体操作函数结构放到file->private_data中,并返回smaps文件对应的文件描述符fd。接下来,用户态的read(fd)函数通过传入的文件描述符fd找到之前open()函数准备好的file结构,并进行读取操作,将文件内容显示给我们。\[1\]\[2\]所以,执行cat /proc/2042/smaps实际上是通过open()和read()函数来读取进程2042的虚拟内存映射信息。\[1\]\[2\] #### 引用[.reference_title] - *1* *2* [cat /proc/$pid/smaps浅析(一)](https://blog.csdn.net/wennuanddianbo/article/details/96473862)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Linux内存管理 -- /proc/{pid}/smaps讲解](https://blog.csdn.net/armlinuxww/article/details/109022698)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值