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

【原創】(十六)Linux記憶體管理之CMA

背景

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

Contiguous Memory Allocator, CMA,連續記憶體分配器,用於分配連續的大塊記憶體。
CMA分配器,會Reserve一片實體記憶體區域:

  1. 裝置驅動不用時,記憶體管理系統將該區域用於分配和管理可移動型別頁面;
  2. 裝置驅動使用時,用於連續記憶體分配,此時已經分配的頁面需要進行遷移;

此外,CMA分配器還可以與DMA子系統整合在一起,使用DMA的裝置驅動程式無需使用單獨的CMA API

2. 資料結構

核心定義了struct cma結構,用於管理一個CMA區域,此外還定義了全域性的cma陣列,如下:

struct cma {
    unsigned long   base_pfn;
    unsigned long   count;
    unsigned long   *bitmap;
    unsigned int order_per_bit; /* Order of pages represented by one bit */
    struct mutex    lock;
#ifdef CONFIG_CMA_DEBUGFS
    struct hlist_head mem_head;
    spinlock_t mem_head_lock;
#endif
    const char *name;
};

extern struct cma cma_areas[MAX_CMA_AREAS];
extern unsigned cma_area_count;
  • base_pfn:CMA區域實體地址的起始頁幀號;
  • count:CMA區域總體的頁數;
  • *bitmap:點陣圖,用於描述頁的分配情況;
  • order_per_bit:點陣圖中每個bit描述的物理頁面的order值,其中頁面數為2^order值;

來一張圖就會清晰明瞭:

3. 流程分析

3.1 CMA區域建立

3.1.1 方式一 根據dts來配置

之前的文章也都分析過,實體記憶體的描述放置在dts中,最終會在系統啟動過程中,對dtb檔案進行解析,從而完成記憶體資訊註冊。

CMA的記憶體在dts中的描述示例如下圖:

dtb解析過程中,會呼叫到rmem_cma_setup函式:

RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);

3.1.2 方式二 根據引數或巨集配置

可以通過核心引數或配置巨集,來進行CMA區域的建立,最終會呼叫到cma_declare_contiguous函式,如下圖:

3.2 CMA新增到Buddy System

在建立完CMA區域後,該記憶體區域成了保留區域,如果單純給驅動使用,顯然會造成記憶體的浪費,因此記憶體管理模組會將CMA區域新增到Buddy System中,用於可移動頁面的分配和管理。CMA區域是通過cma_init_reserved_areas介面來新增到Buddy System中的。

core_initcall(cma_init_reserved_areas);

core_initcall巨集將cma_init_reserved_areas函式放置到特定的段中,在系統啟動的時候會呼叫到該函式。

3.3 CMA分配/釋放

  • CMA分配,入口函式為cma_alloc

  • CMA釋放,入口函式為cma_release
    函式比較簡單,直接貼上程式碼
/**
 * cma_release() - release allocated pages
 * @cma:   Contiguous memory region for which the allocation is performed.
 * @pages: Allocated pages.
 * @count: Number of allocated pages.
 *
 * This function releases memory allocated by alloc_cma().
 * It returns false when provided pages do not belong to contiguous area and
 * true otherwise.
 */
bool cma_release(struct cma *cma, const struct page *pages, unsigned int count)
{
    unsigned long pfn;

    if (!cma || !pages)
        return false;

    pr_debug("%s(page %p)\n", __func__, (void *)pages);

    pfn = page_to_pfn(pages);

    if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
        return false;

    VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);

    free_contig_range(pfn, count);
    cma_clear_bitmap(cma, pfn, count);
    trace_cma_release(pfn, pages, count);

    return true;
}

3.4 DMA使用

程式碼參考driver/base/dma-contiguous.c,主要包括的介面有:

/**
 * dma_alloc_from_contiguous() - allocate pages from contiguous area
 * @dev:   Pointer to device for which the allocation is performed.
 * @count: Requested number of pages.
 * @align: Requested alignment of pages (in PAGE_SIZE order).
 * @gfp_mask: GFP flags to use for this allocation.
 *
 * This function allocates memory buffer for specified device. It uses
 * device specific contiguous memory area if available or the default
 * global one. Requires architecture specific dev_get_cma_area() helper
 * function.
 */
struct page *dma_alloc_from_contiguous(struct device *dev, size_t count,
                       unsigned int align, gfp_t gfp_mask);
 
 /**
 * dma_release_from_contiguous() - release allocated pages
 * @dev:   Pointer to device for which the pages were allocated.
 * @pages: Allocated pages.
 * @count: Number of allocated pages.
 *
 * This function releases memory allocated by dma_alloc_from_contiguous().
 * It returns false when provided pages do not belong to contiguous area and
 * true otherwise.
 */
bool dma_release_from_contiguous(struct device *dev, struct page *pages,
                 int count);

在上述的介面中,實際呼叫的就是cma_alloc/cma_release介面來實現的。

整體來看,CMA分配器還是比較簡單易懂,也不再深入分析。

4.後記

記憶體管理的分析先告一段落,後續可能還會針對某些模組進一步的研究與完善。
記憶體管理子系統,極其複雜,盤根錯節,很容易就懵圈了,儘管費了不少心力,也只能說略知皮毛。
學習就像是爬山,面對一座高山,可能會有心理障礙,但是當你跨越之後,再看到同樣高的山,心理上你將不再畏懼。

接下來將研究程序管理子系統,將任督二脈打通。

未來會持續分析核心中的各類框架,併發機制等,敬請關注,一起探討。

相關推薦

原創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記憶體管理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記憶體管理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記憶體管理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,

原創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,

gitnew project visable level

1.Public access     GitLab allows you to change your projects' visibility in order be accessed  publicly or internally.

D3.js資料視覺化系列教程--更新、過度和動畫

//(1) 準備資料集 var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13, 11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ]; //(2) 設定SVG的高寬 var w=600; va

原創十三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下VIM文字編輯器使用

  linux下編寫配置檔案最好的編輯工具莫過於vim了。Vim的功能實在太多太全,Vim的很多功能也許我們很少用得到,真正為大家常用的功能可能只佔到所有功能的冰山一角。Vim終歸只是一個編寫程式碼或編輯文件的工具,所以只要掌握一些足夠我們使用的功能即可。 做個廣告

深度學習筆記——理論與推導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

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

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

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

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

Angular學習筆記元件週期鉤子投影和AfterContentInit

投影 定義:在執行時動態改變模版內容,父元件主動控制子元件的顯示內容。 指令:ng-content 方法:在html中,父元件中引用子元件標籤的寫入要顯示的內容,子元件使用<ng-content></ng-content>確定投影點

原創Linux程序排程-實時排程器

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

JMeter學習JMeter函數學習

blog 自動 當前 3.2 add 函數的調用 瀏覽器 con 保存 JMeter函數是一些能夠轉化在測試樹中取樣器或者其他配置元件的域的特殊值。一個函數的調用就像這樣:${_functionName(var1,var2,var3)},-functionName匹配函數名

練習題章--類和函式Think Python

class Time: hour=0 minute=0 second=0 def print_time(t): print("%.2d:%.2d:%.2d"%(t.hour,t.minute,t.second)) def is_after(t1,t2):

Python小白學習內置函數一

tro item 求和 整數 Coding rop 數學運算 memory 保留 將68個內置函數按照其功能分為了10類,分別是: 數學運算(7個) abs()   divmod()   max()    min()   pow()   round()