内存检测_内存管理(12)物理地址空间的有效性检测(终)

本文详细介绍了Linux内核如何在内存管理过程中进行物理地址空间的有效性检测,包括遍历section、分配内存、建立映射关系等步骤。通过sparse_init函数及相关子函数,阐述了Linux如何计算有效section、申请空间、初始化pageblock_flags和section_mem_map,以及在不同配置下建立虚拟映射表的过程。
摘要由CSDN通过智能技术生成

内存管理(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使用了同样的套路

2d9c6015c6be50ac924432afe1175e4f.png

系统中稀疏内存模型分布图

sparse_init函数

6273e675b47d30a7889d86f3b0f3cbd1.png

sparse_init实现(1)

  • 第17行:设置pageblock_order大小,相关函数实现细节如下↓

4dd532c8f3844386585e793139d13dc4.png

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

6d5ac81e137024913cbf461bd2cd25a2.png

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中

8bfc6d345815b4ca5de9c6f13954e822.png

sparse_init实现(4)

set_pageblock_order函数

cf5d257bd7063ee0deab1d6969654947.png

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函数:

b2a6cc63d14d722899986ed9b2f83d42.png

alloc_usemap_and_memmap实现(1)

  • 第128~132行:遍历系统中所有的section,过滤掉无效section

  • 第138行:同一个node,一个有效section记做一次map

dc9d3ff617c33bbce02707975dc6b810.png

alloc_usemap_and_memmap实现(2)

64cd248fa969cf31a71ea89325f501e5.png

alloc_usemap_and_memmap实现(3)

  • 第139~162行:计算一个node里面有多少个有效的section需要进行多少次map,并在每遍历完一个node后或对其pageblock_flags进行初始化或对其section_mem_map建立虚拟映射表

sparse_early_usemaps_alloc_node函数

142e00d04c598e2d9a2e685594847465.png

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函数

ba22b9c1f14b9acc769eb58a1b55fa06.png

sparse_mem_map_populate实现

  • 第302行:通过页框号找到对应物理地址

  • 第304行:根据页框数量偏移得到结尾页框地址

  • 第306行:建立映射关系的实际函数,实现↓

vmemmap_populate函数

3fbfa940513e77f517fdfddc523bf548.png

vmemmap_populate实现(1)

4dfb72aa7fd18af823added16b3dc42b.png

vmemmap_populate实现(2)

  • 本文的重点在于Linux内核是怎么对mem_section中的section_mem_map和pageblock_flags初始化的。所以这个函数暂不分析,因为实在太晚了,该睡觉了~ 其实有一部分在前面分析过。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值