《深入Linux内核架构》第4章 进程虚拟内存(5)

目录

4.8 反向映射

4.8.1 数据结构

4.8.2 建立逆向映射

4.8.2.1 匿名页

4.8.2.2 文件页

4.8.3 使用逆向映射


本专栏文章将有70篇左右,欢迎+关注,查看后续文章。

4.8 反向映射

反向/逆向映射:

        reverse mapping,即rmap。

反向映射:

        作用:

                通过一个页,找到所有映射该页的VMA。

        使用场景:

                页换出、页回收、页迁移。

RMAP中两个重要数据结构:

        struct vm_area_struct

        struct anon_vma

        struct anon_vma_chain

struct   vm_area_struct {

        struct list_head           anon_vma_chain;

        struct anon_vma         *anon_vma;

        ...

}

struct    anon_vma{

        //管理匿名类型VMAs

}

struct    anon_vma_chain {         //VMA和anon_vma之间的桥梁

        struct vm_area_struct         *vma;

        struct anon_vma         *anon_vma;

                //指向父进程或子进程的anon_vma数据结构

        struct list_head         same_vma;

                //链表节点,把struct anon_vma_chain添加到vma->anon_vma_chain链表中。

        struct rb_node         rb;

                //红黑树节点,把struct anon_vma_chain添加到anon_vma->rb_root的红黑树中。

        unsigned long         rb_subtree_last;

};

回收内存页时,如何找到使用该页的所有VMA:

        1. page结构中struct address_space *mapping字段指向anon_vma

总结:

        父进程每个VMA都有一个anon_vma数据结构,即vma->anon_vma。

        和某个VMA相关物理页面page->mapping都指向anon_vma。

        anon_vma_chain->vma指向VMA,anon_vma_chain->anon_vma指向anon_vma。

        anon_vma_chain添加到VMA->anon_vma_chain链表中。

        anon_vma_chain-添加到anon_vma->rb_root红黑树中

统计页所有使用者计数

page如何找到对应vma:

        1. 通过page的struct address_space mapping找到VMA

        2. VMA遍历自己管理的红黑树rb_root,找到树上的每个节点anon_vma_chain

        3. anon_vma_chain通过成员指针anon_vma找到对应的VMA

vm_area_struct和vm_struct区别联系:

        vm_area_struct:

                进程虚拟地址空间中一段连续地址范围,即VMA。并且拥有属性和状态,例如读/写/执行权限、是否共享等。通过它完成虚拟地址到物理地址映射和管理。

        vm_struct:

                描述一段未映射的、未分配的、虚拟地址空间中的内存区域,Virtual Memory Block,简称VMB。每个VMB属性,例如起始地址、大小、对齐要求等。在分配新的内存时,内核会在VMB中寻找一块合适大小的空间进行分配。

vmalloc函数从vm_struct中申请一块新的内存块,并将该内存块映射到新的VMA中,完成虚拟到物理地址的映射。

4.8.1 数据结构

struct page {

        atomic_t         _mapcount;

                //记录该页面被映射到多少个VMA

        struct address_space         *mapping;              

}

成员介绍:

mapping

  1. 若为文件映射:

        mapping指向struct address_space实例。

2. 若为匿名映射:

        此时mapping的最低位为PAGE_MAPPING_ANON,mapping指向struct anon_vma。

struct vm_area_struct {

        //下面联合体用于文件映射

        union {

                struct {

                        struct rb_node         rb;

                                //用于插入到address_space->i_mmap树中

                        unsigned long         rb_subtree_last;

                } linear;

        

                struct list_head         nonlinear;

                        //用于连接到address_space->i_mmap_nonlinear链表中

        } shared;

   

             //用于匿名映射

        struct list_head         anon_vma_chain;

        struct anon_vma         *anon_vma; 链表访问

}

匿名私有映射的VMA:如堆栈。只能在anon_vma链表中。

文件私有映射的VMA:可同时在i_mmap和anon_vma链表中。

共享映射的VMA:只能在i_mmap树中。

拓展

一个address_space管理了一个文件(inode)在内存中所有缓存。

举例:

        有5个进程,每个进程用mmap映射同一个文件的不同部分,将生成10个VMA,而这10个VMA都连接到同一个address_space->i_mmap树中或nonlinear链表中。

        使用一个address_space可很好管理同一文件(inode)的多个VMA。

        体现了address_space与文件(inode)对应关系。

        同理:匿名映射一个struct anon_vma也管理一个文件的多个映射(多个VMA)。

逆向映射:

        作用:通过一个页找到所有映射该页的VMA。

4.8.2 建立逆向映射

创建逆向映射时应区分:

        匿名映射。

        文件映射。

因为管理这两种映射的数据结构不同。

4.8.2.1 匿名页

把匿名页插入逆向映射数据结构:

void __page_set_anon_rmap(struct page *page, struct vm_area_struct *vma, unsigned long address)

{

        struct anon_vma         *anon_vma = vma->anon_vma;

        anon_vma   =  (void *) anon_vma + PAGE_MAPPING_ANON;

                //加上PAGE_MAPPING_ANON作用:区分是匿名页和文件页

                anon_vma最低位:

                        若为0,则是文件页。

                        若为PAGE_MAPPING_ANON,则是匿名页。

        page->mapping   =   (struct address_space) *anon_vma;

        page->index   =   linear_page_index(vma, address);

                //page->index:映射页内偏移

}

4.8.2.2 文件页

比匿名页更简单。

void page_add_file_rmap(struct page *page)

        //对page->_mapcount+1

4.8.3 使用逆向映射

等第18章讲解页交换时,就知道逆向映射的好处。

int   try_to_unmap(struct page *page, enum ttu_flags flags)

作用:

        从所有使用该页的进程的页表中删除该页。(需要借助于逆向映射)

        后续章节详解该函数。

page_referenced 函数和 struct page 中的 _mapcount 成员的联系:

        page_referenced() 函数:

                作用:返回活跃使用某共享页的进程数目。

        _mapcount 作用:

                统计映射该页的所有VMA数。即用于逆向映射统计。

逆向映射作用:

        通过一个页找到所有进程中映射了该页的VMA。

int page_referenced(struct page *page, int is_locked,

        struct mem_cgroup *memcg, unsigned long *vm_flags)

{

        int    referenced = 0;

        if (PageAnon(page)) {

                //活跃使用该匿名页的进程数

                referenced  +=  page_referenced_anon(page, memcg, vm_flags);

        } else if (page->mapping) {

                //活跃使用该文件页的进程数

                referenced  +=  page_referenced_file(page, memcg, vm_flags);

        }

        return referenced;

}

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山下小童

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值