http://www.lizhaozhong.info/archives/1254
上篇讲到的伙伴系统是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