1. 程式人生 > >【原創】(十五)Linux記憶體管理之RMAP

【原創】(十五)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_RB
    unsigned 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的詳細細節就不進一步深入了,把握好大體框架即可。

相關推薦

原創Linux記憶體管理RMAP

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

原創Linux記憶體管理vmap與vmalloc

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

原創Linux記憶體管理page fault處理

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

原創Linux記憶體管理CMA

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

原創Linux記憶體管理slub分配器

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

SpringCloud:Zuul的基本應用,反向代理和負載均衡

  Router and Filter: Zuul。 Zuul is a JVM based router and server side load balancer by Netflix。   Zu

原創十三Linux記憶體管理vma/malloc/mmap

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

Linux系列教程——Linux用戶和用戶組管理用戶管理命令

總結 usr 而且 ron 初始 切換 密碼規則 一個 郵箱目錄   上篇博客我們介紹了用戶管理的相關配置文件,包括用戶信息文件/etc/passwd,用戶密碼文件/etc/shadow;然後介紹了用戶組信息文件/etc/group,用戶組密碼文件/etc/gshadow。

Linux進程管理

終端 kill CI 無法 rip uid 進程管理 僵屍進程 停止 15.1 進程的基本介紹 (1)在linux中,每個執行的程序都稱為一個進程,每一個進程都分配一個ID號。 (2)每一個進程都會對應一個父進程,而這個父進程可以復制多個子線程。例如:www服務器 (3)每

java程式設計師菜鳥進階linux基礎入門linux使用者和組管理

我們大家都知道,要登入linux作業系統,我們必須要有一個使用者名稱和密碼。每一個使用者都由一個惟一的身份來標識,這個標識叫做使用者ID.系統中的每一個使用者也至少需要屬於一個"使用者分組".同樣,使用者分組也是由一個惟一的身份來標識的,該標識叫做使用者分組ID(GID).每位使用者的許可

Linux初級運維——bash指令碼程式設計函式

一、函式         函式:功能,function  程式碼重用的功能。         結構化程式設計,不能獨立執行,需要呼叫

深度學習筆記——理論與推導Structured LearningNLP

Language Technology Meaning of Word(一個vector表示一個word) Predicting the next word 給一串sequence of words,預測下一個單詞 我們現在要做的就是將wi

SpringCloud:超時機制和斷路器及 Hystrix簡單實踐

  上篇文章我們配置了Eureka叢集,實現了高可用。在微服務框架中,一個服務消費者可能是其他服務消費者的提供者,而當低層次的服務提供者出現問題時,會導致系統資源被耗盡。出現雪崩效應。 Hystri

SpringCloud:Feign對Hystrix的支援 fallbackFactory

  前面的文章中提到了fallback,這裡我們描述一個它的增強版。fallbackFactory。都是實現斷路器的功能。 UserFeignClient package com.dynam

Linux初級運維——Linux軟體管理

一、軟體包管理     1、應用程式:         程式,Architecture      C語言:原始碼-->(編譯

從程式設計師到專案經理:專案管理三大目標

        專案管理的三大目標即時間、成本和質量,實際是告訴專案經理應重點關注什麼因素,專案控制應該做什麼工作。三大目標雖然簡單,但如果能將其真正貫徹到自己的行動中,那麼對專案計劃制定、過程控制等工作,均能起到引導作用。有了努力的方向,專案經理也就可以真正告別“盲目”了。

Linux記憶體管理zone_sizes_init

背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,

、shell指令碼簡單控制流結構

一、基本的控制結構 1、控制流 常見的控制流就是if、then、else語句提供測試條件,測試條件可以基於各種條件。例如建立檔案是否成功、是否有讀寫許可權等,凡是執行的操作有失敗的可能就可以用控制流,注意控制流的真為0,假為1。 單層if語句   if 條件;then    &nbs

linuxValgrind工具集詳解:Callgrind效能分析圖

一、概述 1、Callgrind Callgrind用於記錄程式中函式之間的呼叫歷史資訊,對程式效能分析。預設情況下,收集的資料包括執行的指令數,它們與原始碼行的關係,函式之間的呼叫者、被呼叫者關係以及此類呼叫的數量。可選項是,對快取記憶體模擬和分支預測(類似於Cachegrin

原創Linux程序排程-CFS排程器

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器,Contex-A53,雙核 3. 使用工具:S