内存管理(11)物理地址空間的有效性檢測主要講述了Linux内核是如何從memblock.memory
->regions->page->section->mem_section建立物理地址之間關系的。但是我們并沒有對mem_section所管理的有效頁框創建相應的映射關系以及初始化每個section下的頁框屬性。所以linux 内核是如何完成這件事的呢?
1.遍曆系統中所有可能存在的section,過濾無效的,計算每一個node中有多少個有效的section
2.為每個node申請一個元素數量為有效section個數數量相等的unsigned long*指針數組
3.把每個有效section的unsigned long*指針數組中的指針指向一個數組,這個數組存放了當前section裡面所有頁的pageblock_flags
4.mem_section.section_mem_map使用了同樣的套路
系統中稀疏内存模型分布圖
sparse_init函數
第17行:設置pageblock_order大小,相關函數實現細節如下↓
sparse_init實現(2)
第30~31行:Linux内核向memblock申請了NR_MEM_SECTIONS * sizeof(unsigned long *)字節的空間,用usemap_map指向其首地址。其中NR_MEM_SECTIONS的含義請參閱内存管理(11)物理地址空間的有效性檢測,那這個空間用來做什麼,繼續往下看。
第34行:alloc_usemap_and_memmap中遍曆系統中所有的section,計算出系統中每個node下的有效section數,函數實現如下↓。每遍曆完一個node後,就在sparse_early_usemaps_alloc_node中為該node下所有有效的section裡面所有的pageblock_flags申請空間,然後遍曆每一個section将其對應usemap_map指向對應的pageblock_flags數組首地址,因此上面申請的usemap_map集合中的每一個unsigned long *都會指向對應section下的pageflags數組,相關函數實現如下↓
第38~40行:如果定義了CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER,申請NR_MEM_SECTIONS * sizeof(struct page *)大小的空間,用map_map指向它。那這個map_map又是用來做什麼的,繼續往下看
第42~43行:在上文已解釋alloc_usemap_and_memma函數。在sparse_early_mem_maps_alloc_node ->sparse_mem_maps_populate_node中如果定義了CONFIG_SPARSEMEM_VMEMMAP那麼sparse_mem_maps_populate_node中遍曆了每一個有效的section,用前面申請的map_map中的每一個struct page *都建立了對應于section的一系列頁框數組的虛拟映射表,比如section[pnum]其對應的map_map[pnum]就會被用來建立一個虛拟映射表,它指向對應section下所有頁框的虛拟映射表空間,map_map[pnum]最終會被用去初始化mem_section[pnum].section_mem_map.
第46~48行:遍曆所有的section,過濾無效的section
sparse_init實現(3)
第54~58行:如果定義了CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER就取對應section的map_map,否則對對應section下的map在函數sparse_early_mem_map_alloc->sparse_mem_map_populate中真正的建立映射關系,其實現細節如下↓
第62行:将前面得到的pageblock_flags和map填充到對應section的mem_section中
sparse_init實現(4)
set_pageblock_order函數
set_pageblock_order實現
第107行:定義了超巨頁的話pageblock_order = HPAGE_SHIFT - PAGE_SHIFT = 21 - 12 = 9
第109行:沒有定義超巨頁pageblock_order = MAX_ORDER - 1 = 11 - 1 = 10
alloc_usemap_and_memmap函數:
alloc_usemap_and_memmap實現(1)
第128~132行:遍曆系統中所有的section,過濾掉無效section
第138行:同一個node,一個有效section記做一次map
alloc_usemap_and_memmap實現(2)
alloc_usemap_and_memmap實現(3)
第139~162行:計算一個node裡面有多少個有效的section需要進行多少次map,并在每遍曆完一個node後或對其pageblock_flags進行初始化或對其section_mem_map建立虛拟映射表
sparse_early_usemaps_alloc_node函數
sparse_early_usemaps_alloc_node實現
第259行:計算一個node裡面每個有效section的pageblock_flags所占用的空間大小,每個pageblock_flags使用4bit進行存放
為當前node下所有有效section的pageblock_flags申請空間并且用usemap指向它
為每一個section index為下标的usemap_map以此初始化use_map,為最終mem_section中的pageblock_flags初始化做準備
sparse_early_mem_map_alloc->sparse_mem_map_populate函數
sparse_mem_map_populate實現
第302行:通過頁框号找到對應物理地址
第304行:根據頁框數量偏移得到結尾頁框地址
第306行:建立映射關系的實際函數,實現↓
vmemmap_populate函數
vmemmap_populate實現(1)
vmemmap_populate實現(2)
,
本文的重點在于Linux内核是怎麼對mem_section中的section_mem_map和pageblock_flags初始化的。所以這個函數暫不分析,因為實在太晚了,該睡覺了~ 其實有一部分在前面分析過。
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!