【原创】(十五)Linux内存管理之RMAP

背景

  • Read the fucking source code! --By 鲁迅

  • A picture is worth a thousand words. --By 高尔基

说明:

  1. Kernel版本:4.14

  2. ARM64处理器,Contex-A53,双核

  3. 使用工具:Source Insight 3.5, Visio

1. 概述

RMAP反向映射是一种物理地址反向映射虚拟地址的方法。

  • 映射
    页表用于虚拟地址到物理地址映射,其中的PTE页表项记录了映射关系,同时struct page结构体中的mapcount字段保存了有多少PTE页表项映射了该物理页。

  • 反向映射
    当某个物理地址要进行回收或迁移时,此时需要去找到有多少虚拟地址射在该物理地址,并断开映射处理。在没有反向映射的机制时,需要去遍历进程的页表,这个效率显然是很低下的。反向映射可以找到虚拟地址空间VMA,并仅从VMA使用的用户页表中取消映射,可以快速解决这个问题。

反向映射的典型应用场景:

  1. kswapd进行页面回收时,需要断开所有映射了该匿名页面的PTE表项;

  2. 页面迁移时,需要断开所有映射了该匿名页面的PTE表项;

2. 数据结构

反向映射有三个关键的结构体:

  1. struct vm_area_struct,简称VMA;
    VMA我们在之前的文章中介绍过,用于描述进程地址空间中的一段区域。与反向映射相关的字段如下:

struct vm_area_struct {.../* * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma * list, after a COW of one of the file pages.A MAP_SHARED vma * can only be in the i_mmap tree.  An anonymous MAP_PRIVATE, stack * or brk vma (with NULL file) can only be in an anon_vma list. */struct list_head anon_vma_chain; /* Serialized by mmap_sem &  * page_table_lock */struct anon_vma *anon_vma;/* Serialized by page_table_lock */...}
  1. struct anon_vma,简称AV;
    AV结构用于管理匿名类型VMAs,当有匿名页需要unmap处理时,可以先找到AV,然后再通过AV进行查找处理。结构如下:

/* * The anon_vma heads a list of private "related" vmas, to scan if * an anonymous page pointing to this anon_vma needs to be unmapped: * the vmas on the list will be related by forking, or by splitting. * * Since vmas come and go as they are split and merged (particularly * in mprotect), the mapping field of an anonymous page cannot point * directly to a vma: instead it points to an anon_vma, on whose list * the related vmas can be easily linked or unlinked. * * After unlinking the last vma on the list, we must garbage collect * the anon_vma object itself: we're guaranteed no page can be * pointing to this anon_vma once its vma list is empty. */struct anon_vma {struct anon_vma *root;/* Root of this anon_vma tree */struct rw_semaphore rwsem;/* W: modification, R: walking the list *//* * The refcount is taken on an anon_vma when there is no * guarantee that the vma of page tables will exist for * the duration of the operation. A caller that takes * the reference is responsible for clearing up the * anon_vma if they are the last user on release */atomic_t refcount;/* * Count of child anon_vmas and VMAs which points to this anon_vma. * * This counter is used for making decision about reusing anon_vma * instead of forking new one. See comments in function anon_vma_clone. */unsigned degree;struct anon_vma *parent;/* Parent of this anon_vma *//* * NOTE: the LSB of the rb_root.rb_node is set by * mm_take_all_locks() _after_ taking the above lock. So the * rb_root must only be read/written after taking the above lock * to be sure to see a valid next pointer. The LSB bit itself * is serialized by a system wide lock only visible to * mm_take_all_locks() (mm_all_locks_mutex). *//* Interval tree of private "related" vmas */struct rb_root_cached rb_root;};
  1. struct anon_vma_chain,简称AVC;
    AVC是连接VMAAV之间的桥梁。

/* * The copy-on-write semantics of fork mean that an anon_vma * can become associated with multiple processes. Furthermore, * each child process will have its own anon_vma, where new * pages for that process are instantiated. * * This structure allows us to find the anon_vmas associated * with a VMA, or the VMAs associated with an anon_vma. * The "same_vma" list contains the anon_vma_chains linking * all the anon_vmas associated with this VMA. * The "rb" field indexes on an interval tree the anon_vma_chains * which link all the VMAs associated with this anon_vma. */struct anon_vma_chain {struct vm_area_struct *vma;struct anon_vma *anon_vma;struct list_head same_vma;   /* locked by mmap_sem & page_table_lock */struct rb_node rb;/* locked by anon_vma->rwsem */unsigned long rb_subtree_last;#ifdef CONFIG_DEBUG_VM_RBunsigned long cached_vma_start, cached_vma_last;#endif};

来一张图就清晰明了了:

  • 通过same_vma链表节点,将anon_vma_chain添加到vma->anon_vma_chain链表中;

  • 通过rb红黑树节点,将anon_vma_chain添加到anon_vma->rb_root的红黑树中;

2. 流程分析

先看一下宏观的图:

  • 地址空间VMA可以通过页表完成虚拟地址到物理地址的映射;

  • 页框与page结构对应,page结构中的mapping字段指向anon_vma,从而可以通过RMAP机制去找到与之关联的VMA

2.1 anon_vma_prepare

之前在page fault的文章中,提到过anon_vma_prepare函数,这个函数完成的工作就是为进程地址空间中的VMA准备struct anon_vma结构。

调用例程及函数流程如下图所示:

至于VMA,AV,AVC三者之间的关联关系,在上文的图中已经有所描述。

当创建了与VMA关联的AV后,还有关键的一步需要做完,才能算是真正的把RMAP通路打通,那就是让pageAV关联起来。只有这样才能通过page找到AV,进而找到VMA,从而完成对应的PTE unmap操作。

2.2 子进程创建anon_vma

父进程通过fork()来创建子进程,子进程会复制整个父进程的地址空间及页表。子进程拷贝了父进程的VMA数据结构内容,而子进程创建相应的anon_vma结构,是通过anon_vma_fork()函数来实现的。

anon_vma_fork()效果图如下:

以实际fork()两次为例,发生COW之后,看看三个进程的链接关系,如下图:

2.3 TTU(try to unmap)Rmap Walk

如果有page被映射到多个虚拟地址,可以通过Rmap Walk机制来遍历所有的VMA,并最终调用回调函数来取消映射。

与之相关的结构体为struct rmap_walk_control,如下:

/* * rmap_walk_control: To control rmap traversing for specific needs * * arg: passed to rmap_one() and invalid_vma() * rmap_one: executed on each vma where page is mapped * done: for checking traversing termination condition * anon_lock: for getting anon_lock by optimized way rather than default * invalid_vma: for skipping uninterested vma */struct rmap_walk_control {void *arg;/* * Return false if page table scanning in rmap_walk should be stopped. * Otherwise, return true. */bool (*rmap_one)(struct page *page, struct vm_area_struct *vma,unsigned long addr, void *arg);int (*done)(struct page *page);struct anon_vma *(*anon_lock)(struct page *page);bool (*invalid_vma)(struct vm_area_struct *vma, void *arg);};

取消映射的入口为try_to_unmap,流程如下图所示:

基本的套路就是围绕着struct rmap_walk_control结构,初始化回调函数,以便在适当的时候能调用到。

关于取消映射try_to_unmap_one的详细细节就不进一步深入了,把握好大体框架即可。

(0)

相关推荐

  • Linux内存管理

    关于Linux的内存管理,本文分别从内核空间和用户空间两个视角来阐述 一.内核空间 1.1 页 页(page)是内核的内存管理基本单位. ==> linux/mm_types.h struct ...

  • 【原创】(十)Linux内存管理 - zoned page frame allocator - 5

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  • 【原创】(十四)Linux内存管理之page fault处理

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  • 【原创】(十六)Linux内存管理之CMA

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  • 万字整理,肝翻Linux内存管理所有知识点

    Linux的内存管理可谓是学好Linux的必经之路,也是Linux的关键知识点,有人说打通了内存管理的知识,也就打通了Linux的任督二脉,这一点不夸张.有人问网上有很多Linux内存管理的内容,为什 ...

  • Linux 内存管理之vmalloc

    走进vmalloc 根据前面的系列文章,我们知道了buddy system是基于页框分配器,kmalloc是基于slab分配器,而且这些分配的地址都是物理内存连续的.但是随着碎片化的积累,连续物理内存 ...

  • Linux 内存管理之CMA

    什么是CMA CMA是reserved的一块内存,用于分配连续的大块内存.当设备驱动不用时,内存管理系统将该区域用于分配和管理可移动类型页面:当设备驱动使用时,此时已经分配的页面需要进行迁移,又用于连 ...

  • 十五种经典管理法则

    一.       木桶效应 木桶定律是讲一只水桶能装多少水取决于它最短的那块木板 .一只木桶想盛满水,必须每块木板都一样平齐且无破损,如果这只桶的木板中有一块不齐或者某块木板下面有破洞,这只桶就无法盛 ...

  • Linux内存管理 (3)内核内存的布局图

    专题:Linux内存管理专题 关键词:内核内存布局图.lowmem线性映射区.kernel image.ZONE_NORMAL.ZONE_HIGHMEM.swapper_pg_dir.fixmap.v ...