物理内存管理:请求PFN函数层次结构分析
http://lzz5235.github.io/2015/03/04/buddy-system.html
上篇讲到的伙伴系统是alloc_pages()族函数运行的基础,下面我来简单说明下alloc_pages()的结构。
alloc_pages()函数下存在五个子函数,他们最后都会调用到alloc_pages(),唯一的区别就是传入的参数不同。
###1.alloc_pages()
这个宏用来分配2的order次方个连续的页框,如果申请成功返回第一个所分配页框的描述符地址,这个地址是全局唯一的!申请失败的话返回NULL。
#define alloc_pages(gfp_mask, order) \
alloc_pages_node(numa_node_id(), gfp_mask, order)
###2.alloc_page()
这个函数是alloc_pages的特殊情况,它只分配一个页框,也就是order等于0。
#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
###3.__get_free_pages()
这个函数可以申请长为2的order次方大小的连续页框,但是它返回的是这段连续页框中第一个页所对应的线性地址(区别页框的描述符地址)。该函数内部仍然调用了alloc_pages(),并利用page_address()将页描述符地址转换为线性地址。
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
{
struct page *page;
VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);
page = alloc_pages(gfp_mask, order);
if (!page)
return 0;
return (unsigned long) page_address(page);
}
###4.__get_free_page()
该宏函数可以看作是__get_free_pages()的特殊情况,它用于申请一个单独的页框,然后返回这个单独页的线性地址。
#define __get_free_page(gfp_mask) \
__get_free_pages((gfp_mask),0)
###5.get_zeroed_page()
该函数用来获取一个填满0的页框,其中__GFP_ZERO参数用来体现这一点,类似于memset()清零的效果。
unsigned long get_zeroed_page(gfp_t gfp_mask)
{
return __get_free_pages(gfp_mask | __GFP_ZERO, 0);
}
###6.__get_dma_pages()
该宏函数获得的页框用于DMA操作。
#define (gfp_mask, order) \
__get_free_pages((gfp_mask) | GFP_DMA,(order))
请求页框的标志通过查阅手册,我可以发现有非常多的mask。 如下代码
13 #define ___GFP_DMA 0x01u
14 #define ___GFP_HIGHMEM 0x02u
15 #define ___GFP_DMA32 0x04u
16 #define ___GFP_MOVABLE 0x08u
17 #define ___GFP_WAIT 0x10u
18 #define ___GFP_HIGH 0x20u
19 #define ___GFP_IO 0x40u
20 #define ___GFP_FS 0x80u
21 #define ___GFP_COLD 0x100u
22 #define ___GFP_NOWARN 0x200u
23 #define ___GFP_REPEAT 0x400u
24 #define ___GFP_NOFAIL 0x800u
25 #define ___GFP_NORETRY 0x1000u
26 #define ___GFP_MEMALLOC 0x2000u
27 #define ___GFP_COMP 0x4000u
28 #define ___GFP_ZERO 0x8000u
29 #define ___GFP_NOMEMALLOC 0x10000u
30 #define ___GFP_HARDWALL 0x20000u
31 #define ___GFP_THISNODE 0x40000u
32 #define ___GFP_RECLAIMABLE 0x80000u
33 #define ___GFP_NOTRACK 0x200000u
34 #define ___GFP_NO_KSWAPD 0x400000u
35 #define ___GFP_OTHER_NODE 0x800000u
36 #define ___GFP_WRITE 0x1000000u
使用最多的莫过于__GFP_DMA,GFP_HIGHMEM,_GFP_DMA32。 当我们在写内核模块的时候,我们会用到kmalloc()函数,里面的标志位最多的应该就是GFP_KERNEL、GFP_USER和GFP_ATOMIC。这三个参数经过层层解析被系统解析为
106 #define GFP_ATOMIC (__GFP_HIGH)
109 #define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS)
112 #define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
系统中也会按照内存zone的区域分配,总的分配顺序是HIGHMEM、NORMAL、DMA ,如果API指定分配区域,系统就按照指定区域分配。
总的函数调用关系:
get_zeroed_page() __get_free_page() __get_dma_pages()
| | |
| | |
|----------------------------------------------
__get_free_pages() alloc_page()
| |
|-------------------------
alloc_pages()
|
alloc_pages_node()
|
__alloc_pages()
|
__alloc_pages_nodemask()
通过上面的结构表示,alloc_pages_node()是上述API的核心,而__alloc_pages_nodemask()为页框分配的心脏!
参考:
http://www.cnblogs.com/hanyan225/archive/2011/07/28/2119628.html