首页 > 系统相关 >linux内存管理(八)- 反向映射RMAP

linux内存管理(八)- 反向映射RMAP

时间:2024-06-15 20:54:04浏览次数:15  
标签:folio rwc RMAP struct vma anon 内存 linux rmap

这里有一篇博客讲的不错。linux内存管理笔记(三十八)----反向映射_linux 反向映射-CSDN博客

页表是把虚拟地址映射到物理页面,但是如何根据一个物理页找到所有映射它的pte呢?答案是用反向映射Reverse Mapping(RMAP)。这在页面回收中很有用。回收页面需要将到物理页的映射断开(改一下pte),前提是找到所有映射的pte,那就必须在page结构中留下线索,这就是mapping字段。

在讲page结构时我们提到过mapping可以指向匿名页的anon_vma结构,这个结构是反向映射的关键之一。

struct anon_vma {
    struct anon_vma *root;        /* Root of this anon_vma tree */
    struct rw_semaphore rwsem;    /* W: modification, R: walking the list */
    atomic_t refcount;
    unsigned long num_children;
    /* Count of VMAs whose ->anon_vma pointer points to this object. */
    unsigned long num_active_vmas;
    struct anon_vma *parent;    /* Parent of this anon_vma */
    struct rb_root_cached rb_root;  //avc结构会链接到这棵rbtree上
};

除了anon_vma(AV)还有一个AVC(anon_vma_chain)结构。

/*
 * 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_lock & page_table_lock */
    struct rb_node rb;            /* locked by anon_vma->rwsem */
    unsigned long rb_subtree_last;
#ifdef CONFIG_DEBUG_VM_RB
    unsigned long cached_vma_start, cached_vma_last;
#endif
};

看注释可知AVC可以通过rb_node链接到anon_vma的rbtree上,这个rbtree会链接所有与AV相关的VMA。也可以通过same_vma链表链接所有与该VMA相关的AV。AVC是anon_vma和vma的枢纽,可以让三者相互找到另外两方。

上图是一个简单的情形,描述三者之间的关系,这对理解后面反向映射的应用很重要。

反向映射的应用。

使用反向映射最常见的是在回收页面,try_to_unmap是其重要函数。

void try_to_unmap(struct folio *folio, enum ttu_flags flags)
{
    struct rmap_walk_control rwc = {
        .rmap_one = try_to_unmap_one,
        .arg = (void *)flags,
        .done = folio_not_mapped,
        .anon_lock = folio_lock_anon_vma_read,
    };

    if (flags & TTU_RMAP_LOCKED)
        rmap_walk_locked(folio, &rwc);
    else
        rmap_walk(folio, &rwc);
}

rmap_walk

void rmap_walk(struct folio *folio, struct rmap_walk_control *rwc)
{
    if (unlikely(folio_test_ksm(folio)))
        rmap_walk_ksm(folio, rwc);
    else if (folio_test_anon(folio))
        rmap_walk_anon(folio, rwc, false);
    else
        rmap_walk_file(folio, rwc, false);
}

只看rmap_walk_anon

static void rmap_walk_anon(struct folio *folio,
        struct rmap_walk_control *rwc, bool locked)
{
    struct anon_vma *anon_vma;
    pgoff_t pgoff_start, pgoff_end;
    struct anon_vma_chain *avc;

    if (locked) {
        anon_vma = folio_anon_vma(folio);
        /* anon_vma disappear under us? */
        VM_BUG_ON_FOLIO(!anon_vma, folio);
    } else {
//从folio中获取anon_vma anon_vma = rmap_walk_anon_lock(folio, rwc); } if (!anon_vma) return; //page->index是page在file或内存区域中的偏移,单位是page pgoff_start = folio_pgoff(folio);
//得到复合页的末尾index pgoff_end = pgoff_start + folio_nr_pages(folio) - 1;
//遍历avc anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff_start, pgoff_end) { struct vm_area_struct *vma = avc->vma;
//得到page的虚拟地址 unsigned long address = vma_address(&folio->page, vma); VM_BUG_ON_VMA(address == -EFAULT, vma); cond_resched(); if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg)) continue; //使用回调函数rmap_one断开虚拟地址对应的pte if (!rwc->rmap_one(folio, vma, address, rwc->arg)) break; if (rwc->done && rwc->done(folio)) break; } if (!locked) anon_vma_unlock_read(anon_vma); }

rmap_walk_anon遍历anon_vma对应的rbtree,找到所有映射该页的vma,然后断开物理页对应虚拟地址的pte。

这里要理解page->index和vma->pgoff和vma->vm_start的关系。

由上图可以看到page->index指的是在整个文件或者进程地址空间(不一定是vma)上的偏移,要想得到它在当前vma内的偏移公式是vma->vm_start + (page->index - vma->vm_pgoff) << PAGE_SHIFT.

 

标签:folio,rwc,RMAP,struct,vma,anon,内存,linux,rmap
From: https://www.cnblogs.com/banshanjushi/p/18001881

相关文章

  • 【PL理论】(24) C- 语言:有块的作用域 | 更新的语法 | 新的语义域 | 环境 vs. 内存
    ......
  • Linux 并发与竞争实验学习
    Linux并发与竞争实验学习原子操作实验这里原子操作就是采用原子变量来保护一个程序运行的完整过程,使用atomic来实现一次只能允许一个应用访问LED,创建atomic.c文件,其实改动内容就是添加原子变量,要在设备结构体数据添加原子变量,具体代码如下:structgpioled_dev{dev_td......
  • Linux vim 文本编辑 操作文本 三种模式
    介绍vi是一个经典的行编辑器,支持模式编辑(包括普通模式、插入模式和命令模式)。vim保留vi核心功能的基础上,增加了多级撤销、语法高亮、插件支持等高级功能。两者的最大区别,简单的来说vim就是vi的增强版三种模式命令模式(CommandMode)默认进入的是命令模式。在这个模式......
  • Linux PM:wakeup count、wakelock、autosleep
     在进行wakeupcount、wakelock、autosleep之前,先参考《Linux电源管理(7)_Wakeupeventsframework(wowotech.net)》。下面简单跟一下,wakeupcount、wakelock、autosleep,及其使用方法。1PM初始化PM子系统初始化:pm_initpm_start_workqueuehibernate_image_size_ini......
  • SoftReference 到底在什么时候被回收 ? 如何量化内存不足 ?
    本文基于OpenJDK17进行讨论,垃圾回收器为ZGC。提示:为了方便大家索引,特将在上篇文章《以ZGC为例,谈一谈JVM是如何实现Reference语义的》中讨论的众多主题独立出来。大家在网上或者在其他讲解JVM的书籍中多多少少会看到这样一段关于SoftReference的描述——“......
  • Linux:vim
    目录1、vim简单介绍2、vim使用2.1、进入vim2.2、模式切换2.3、常用命令2.3.1、进出vim2.3.2、定位2.3.3、查找字符串:2.3.4、替换字符串2.3.5、复制粘贴2.3.6、撤销1、vim简单介绍超强的文本编辑器,在Linux中编写代码比较常用,可以根据不同的语言提供高亮,类似notepad+......
  • Linux 虚拟网络 host gw
    hostgw把host作为网关,通过网关进行数据包传输。使用Containerlab模拟网络a|拓扑b|网络拓扑文件#host-gw.clab.ymlname:host-gwtopology:nodes:gw1:kind:linuximage:vyos/vyos:1.2.8cmd:/sbin/initbinds:-/......
  • Linux下Nginx安装并开启SSL
    Linux下Nginx安装并开启SSL一.下载nginxNginxdownload下载后上传至服务器。PS:博主使用的Nginx版本为:nginx-1.23.4.tar.gz二.安装Nginx所需要的环境1.安装gcc-c++yuminstallgcc-c++yuminstall-yopensslopenssl-devel2.安装pcre包yuminstall-ypcrepcre......
  • Linux文件系统【真的很详细】
    目录 一.认识磁盘1.1磁盘的物理结构1.2磁盘的存储结构1.3磁盘的逻辑存储结构二.理解文件系统 2.1如何管理磁盘2.2如何在磁盘中找到文件 2.3关于文件名哈喽,大家好。今天我们学习文件系统,我们之前在Linux基础IO中研究的是进程和被打开文件之间的关系,以及如何管理被......
  • Linux项目部署套餐
    第一步准备工作创建一个目录用于存放要用到的工具并上传所需要用到的文件#下载上传需要用到的工具yuminstalllrzsz#创建目录mkdir-p/usr/local/mytools#进入mytools目录下cd/usr/local/mytools#上传可一次性上传jdk,mysql,tomcat,redis压缩包rz第二步安装jd......