1. 程式人生 > >【原創】(十四)Linux記憶體管理之page fault處理

【原創】(十四)Linux記憶體管理之page fault處理

背景

  • 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. 概述

上篇文章分析到malloc/mmap函式中,核心實現只是在程序的地址空間建立好了vma區域,並沒有實際的虛擬地址到實體地址的對映操作。這部分就是在Page Fault異常錯誤處理中實現的。

Linux核心中的Page Fault異常處理很複雜,涉及的細節也很多,malloc/mmap

的實體記憶體對映只是它的一個子集功能,下圖大概涵蓋了出現Page Fault的情況:

下邊就開始來啃啃硬骨頭吧。

2. Arm64處理

Page Fault的異常處理,依賴於體系結構,因此有必要來介紹一下Arm64的處理。
程式碼主要參考:arch/arm64/kernel/entry.S

Arm64在取指令或者訪問資料時,需要把虛擬地址轉換成實體地址,這個過程需要進行幾種檢查,在不滿足的情況下都能造成異常:

  1. 地址的合法性,比如以39有效位地址為例,核心地址的高25位為全1,使用者程序地址的高25位為全0;
  2. 地址的許可權檢查,這裡邊的許可權位都位於頁表條目中;

從上圖中可以看到,最後都會調到do_mem_abort

函式,這個函式比較簡單,直接看程式碼,位於arch/arm64/mm/fault.c

/*
 * Dispatch a data abort to the relevant handler.
 */
asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
                     struct pt_regs *regs)
{
    const struct fault_info *inf = esr_to_fault_info(esr);
    struct siginfo info;

    if (!inf->fn(addr, esr, regs))
        return;

    pr_alert("Unhandled fault: %s (0x%08x) at 0x%016lx\n",
         inf->name, esr, addr);

    mem_abort_decode(esr);

    info.si_signo = inf->sig;
    info.si_errno = 0;
    info.si_code  = inf->code;
    info.si_addr  = (void __user *)addr;
    arm64_notify_die("", regs, &info, esr);
}

該函式中關鍵的處理:根據傳進來的esr獲取fault_info資訊,從而去呼叫函式。struct fault_info用於錯誤狀態下對應的處理方法,而核心中也定義了全域性結構fault_info,存放了所有的情況。
主要的錯誤狀態和處理函式對應如下:

static const struct fault_info fault_info[] = {
    { do_bad,       SIGBUS,  0,     "ttbr address size fault"   },
    { do_bad,       SIGBUS,  0,     "level 1 address size fault"    },
    { do_bad,       SIGBUS,  0,     "level 2 address size fault"    },
    { do_bad,       SIGBUS,  0,     "level 3 address size fault"    },
    { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 0 translation fault" },
    { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 1 translation fault" },
    { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 2 translation fault" },
    { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 3 translation fault" },
    { do_bad,       SIGBUS,  0,     "unknown 8"         },
    { do_page_fault,    SIGSEGV, SEGV_ACCERR,   "level 1 access flag fault" },
    { do_page_fault,    SIGSEGV, SEGV_ACCERR,   "level 2 access flag fault" },
    { do_page_fault,    SIGSEGV, SEGV_ACCERR,   "level 3 access flag fault" },
    { do_bad,       SIGBUS,  0,     "unknown 12"            },
    { do_page_fault,    SIGSEGV, SEGV_ACCERR,   "level 1 permission fault"  },
    { do_page_fault,    SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"  },
    { do_page_fault,    SIGSEGV, SEGV_ACCERR,   "level 3 permission fault"  },
     ...
};

從程式碼中可以看出:

  • 出現0/1/2/3級頁錶轉換錯誤時,會呼叫do_translation_fault,實際中do_translation_fault最終也會呼叫到do_page_fault
  • 出現1/2/3級頁表訪問許可權的時候,會呼叫do_page_fault
  • 其他的錯誤則呼叫do_bad,其中未列出來的部分還包括do_sea等操作函式;

do_translation_fault

do_page_fault

do_page_fault函式為頁錯誤異常處理的核心函式,與體系結構相關,上圖中的handle_mm_fault函式為通用函式,也就是不管哪種處理器結構,最終都會呼叫到該函式。

3. handle_mm_fault

handle_mm_fault用於處理使用者空間的頁錯誤異常:

  • 程序在使用者模式下訪問使用者虛擬地址,觸發頁錯誤異常;
  • 程序在核心模式下訪問使用者虛擬地址,觸發頁錯誤異常;
    do_page_fault函式的流程圖中也能看出來,當觸發異常的虛擬地址屬於某個vma,並且擁有觸發頁錯誤異常的許可權時,會呼叫到handle_mm_fault函式,而handle_mm_fault函式的主要邏輯是通過__handle_mm_fault來實現的。

流程如下圖:

3.1 do_fault

do_fault函式用於處理檔案頁異常,包括以下三種情況:

  1. 讀檔案頁錯誤;
  2. 寫私有檔案頁錯誤;
  3. 寫共享檔案頁錯誤;

3.2 do_anonymous_page

匿名頁的缺頁異常處理呼叫本函式,在以下情況下會觸發:

  1. malloc/mmap分配了程序地址空間區域,但是沒有進行對映處理,在首次訪問時觸發;
  2. 使用者棧不夠的情況下,進行棧區的擴大處理;

3.3 do_swap_page

如果訪問Swap頁面出錯(頁面不在記憶體中),則從Swap cacheSwap檔案中讀取該頁面。
由於在4.14核心版本中,do_swap_page呼叫的很多函式都是空函式,無法進一步的瞭解,大體的流程如下圖:

3.4 do_wp_page

do_wp_page函式用於處理寫時複製(copy on write),會在以下兩種情況處理:

  1. 建立子程序時,父子程序會以只讀方式共享私有的匿名頁和檔案頁,當試圖寫的時候,觸發頁錯誤異常,從而複製物理頁,並建立對映;
  2. 程序建立私有檔案對映,讀訪問後觸發異常,將檔案頁讀入到page cache中,並以只讀模式建立對映,之後發生寫訪問後,觸發COW

關鍵的複製工作是由wp_page_copy完成的:

相關推薦

原創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記憶體管理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記憶體管理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記憶體管理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:Feign對Hystrix的支援 fallbackFactory

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

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

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

原創Linux記憶體模型Sparse Memory Model

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

ASP.NET Core快速入門MVC開發:UI、 EF + Identity實現

dfa models cti ted lec inpu word pri numeric 前言 之前我們進行了MVC的web頁面的Cookie-based認證實現,接下來的開發我們要基於之前的MvcCookieAuthSample項目做修改。 MvcCookieAuth

TeeChart Pro ActiveX教程:列印圖表

下載TeeChart Pro ActiveX最新版本 標準列印 TeeChart Pro提供標準列印方法,可將“螢幕圖表”按原樣列印到印表機。 簡單列印命令 要列印圖表,請使用Print方法。這將打印出螢幕上顯示的圖表: [C#] tChart1.Printer.Print(); [VB.N

Gitgit pull 衝突的解決與避免

問題如圖: 分析:       1.專案分支:master和fcarloan_branch_V1.0.4,一個是主分支,一個是“電銷分支”       2.現在需要新建一個解決“is_rightnow_bill”問題的分支,我在本地checkout -b 一個新分支,如上(1

Python3.6爬蟲學習記錄多執行緒爬蟲模板總結

前言:這幾天忙活的做個網頁玩玩,網上也沒有教程。買個域名又得解析,又得備案,真是麻煩,覺得一個簡單的HTML網頁應該用不到那麼麻煩吧。 昨天又看了幾個關於多執行緒爬蟲的例子,覺得很好,提煉出來,總結幾

原創Linux記憶體管理 - zoned page frame allocator - 1

背景 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記憶體管理 - zoned page frame allocator - 2

背景 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記憶體管理 - zoned page frame allocator - 3

背景 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記憶體管理 - zoned page frame allocator - 4

背景 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記憶體管理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,

java程式設計師菜鳥進階linux基礎入門linux檔案及目錄命令管理

大家都知道,熟悉命令操作的開發人員,Linux作業系統命令操作效率要高於圖形介面的操作,所以瞭解和學習linux基本命令操作是學習linux作業系統的首要任務,本文主要介紹以下四個知識點:   1.      She

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

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

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

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