在网上查资料时看到几篇介绍 linux driver 编写的文章,其中提到 kmalloc()与 __get_free_page()返回地址的问题,我们都知道 kmalloc() 与 __get_free_page() 分配的是物理内存,但它返回的到底是什么?那几篇关于驱动编写的文章中提到申请的是物理地址,返回的依然是物理地址。但有一篇文章中,作者
对此提出了质疑,但没有给出答案。这也就是我写这篇笔记的原因。在找答案的同时也将 linux kernel 分配物理内存的流程做了下分析。这仅是篇笔记,写的比较乱。自己能看懂就行了。
这里只分析分配连续物理地址的函数。对于 vmalloc() 这种分配非连续物理地址的函数不在本记录范围之内。
1、kmalloc() 分配连续的物理地址,用于小内存分配。
2、__get_free_page() 分配连续的物理地址,用于整页分配。
至于为什么说以上函数分配的是连续的物理地址和返回的到底是物理地址还是虚拟地址,下面的记录会做出解释。
kmalloc() 函数本身是基于 slab 实现的。slab 是为分配小内存提供的一种高效机制。但 slab 这种分配机制又不是独立的,它本身也是在页分配器的基础上来划分更细粒度的内存供调用者使用。也就是说系统先用页分配器分配以页为最小单位的连续物理地址,然后 kmalloc() 再在这上面根据调用者的需要进行切分。
关于以上论述,我们可以查看 kmalloc() 的实现,kmalloc()函数的实现是在 __do_kmalloc() 中,可以看到在 __do_kmalloc()代码里最终调用了 __cache_alloc() 来分配一个 slab,其实
kmem_cache_alloc() 等函数的实现也是调用了这个函数来分配新的 slab。我们按照 __cache_alloc()函数的调用路径一直跟踪下去会发现在 cache_grow() 函数中使用了 kmem_getpages()函数来分配一个物理页面,kmem_getpages() 函数中调用的alloc_pages_node() 最终是使用 __alloc_pages() 来返回一个struct page 结构,而这个结构正是系统用来描述物理页面的。这样也就证实了上面所说的,slab 是在物理页面基础上实现的。kmalloc() 分配的是物理地址。