Read the fucking source code!
--By 魯迅A picture is worth a thousand words.
--By 高爾基說明:數組
Contiguous Memory Allocator, CMA
,連續內存分配器,用於分配連續的大塊內存。
CMA分配器
,會Reserve一片物理內存區域:數據結構
此外,CMA分配器
還能夠與DMA子系統
集成在一塊兒,使用DMA的設備驅動程序無需使用單獨的CMA API
。併發
內核定義了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
值;來一張圖就會清晰明瞭:ide
以前的文章也都分析過,物理內存的描述放置在dts
中,最終會在系統啓動過程當中,對dtb
文件進行解析,從而完成內存信息註冊。函數
CMA
的內存在dts
中的描述示例以下圖:工具
在dtb
解析過程當中,會調用到rmem_cma_setup
函數:學習
RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);
能夠經過內核參數或配置宏,來進行CMA區域的建立,最終會調用到cma_declare_contiguous
函數,以下圖:ui
在建立完CMA區域
後,該內存區域成了保留區域,若是單純給驅動使用,顯然會形成內存的浪費,所以內存管理模塊會將CMA區域
添加到Buddy System
中,用於可移動頁面的分配和管理。CMA區域
是經過cma_init_reserved_areas
接口來添加到Buddy System
中的。this
core_initcall(cma_init_reserved_areas);
core_initcall
宏將cma_init_reserved_areas
函數放置到特定的段中,在系統啓動的時候會調用到該函數。
cma_alloc
: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; }
代碼參考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分配器仍是比較簡單易懂,也再也不深刻分析。
內存管理的分析先告一段落,後續可能還會針對某些模塊進一步的研究與完善。
內存管理子系統,極其複雜,盤根錯節,很容易就懵圈了,儘管費了很多心力,也只能說略知皮毛。
學習就像是登山,面對一座高山,可能會有心理障礙,可是當你跨越以後,再看到一樣高的山,心理上你將再也不畏懼。
接下來將研究進程管理子系統
,將任督二脈打通。
將來會持續分析內核中的各種框架,併發機制等,敬請關注,一塊兒探討。