kernel伙伴系统分配的函数,只能分配2的整数幂个页,更细力度的分配只能借助与slab或者slub分配器
常见的分配函数是:
alloc_pages(mask, order)
分配2的order幂次个页面,如果成功返回第一个页框对应的page结构,失败则返回NULL
get_zeroed_page(mask)
分配一个页面,成功则返回这个页框对应的page结构,失败返回NULL,要求返回页面的内容为全0
get_dma_pages(gfp_mask, order)
用于获得适合DMA操作的2的order幂次个页面
在上面的两个函数中,都强制使用了gfp_mask参数,该参数指定了分配的域修饰符以及一些额外的标志
域修饰符
掩码的最低3位为域修饰符,用来描述从哪个域分配页面。
/* * GFP bitmasks.. * * Zone modifiers (see linux/mmzone.h - low three bits) * * Do not put any conditional on these. If necessary modify the definitions * without the underscores and use the consistently. The definitions here may * be used in bit comparisons. */ #define __GFP_DMA ((__force gfp_t)0x01u) #define __GFP_HIGHMEM ((__force gfp_t)0x02u) #define __GFP_DMA32 ((__force gfp_t)0x04u)
GFP 是 Get free pages的缩写
当域修饰符为__GFP_DMA时,表示分配只能发生在DMA zone,如果DMA zone分配失败,由于DMA zone是高级的Zone,那么kernel不会再尝试从Normal zone或者Highmem zone进行分配,这也是符合DMA操作特点的,因为有些DMA控制器无法操作大于16MB的地址空间。
当修饰符为__GFP_HIGHMEM时,表示优先从Highmem进行分配,如果分配失败,则会从Normal zone尝试分配,如果还失败,那么就使用DMA zone来分配,虽然这种方法可以尽量满足Highmem的分配请求,但是却使得不重要的分配请求,占用了重要的内存空间。从而导致后续的Normal zone或者DMA zone的分配失败。实际上我们可以通过修改zone_lists或者lowmem_reserved来限制低级分配请求占用高级内存域。
当修饰符为0时,表示缺省从Normal zone进行分配,如果分配失败,则会尝试从DMA zone进行分配。
操作修饰符
和域修饰符相反,操作修饰符不会限制从哪个内存分配页面,但是却影响着分配器的行为。
#define __GFP_WAIT ((__force gfp_t)0x10u) /* Can wait and reschedule? */ #define __GFP_HIGH ((__force gfp_t)0x20u) /* Should access emergency pools? */ #define __GFP_IO ((__force gfp_t)0x40u) /* Can start physical IO? */ #define __GFP_FS ((__force gfp_t)0x80u) /* Can call down to low-level FS? */ #define __GFP_COLD ((__force gfp_t)0x100u) /* Cache-cold page required */ #define __GFP_NOWARN ((__force gfp_t)0x200u) /* Suppress page allocation failure warning */ #define __GFP_REPEAT ((__force gfp_t)0x400u) /* Retry the allocation. Might fail */ #define __GFP_NOFAIL ((__force gfp_t)0x800u) /* Retry for ever. Cannot fail */ #define __GFP_NORETRY ((__force gfp_t)0x1000u)/* Do not retry. Might fail */ #define __GFP_COMP ((__force gfp_t)0x4000u)/* Add compound page metadata */ #define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */ #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */ #define __GFP_HARDWALL ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */ #define __GFP_THISNODE ((__force gfp_t)0x40000u)/* No fallback, no policies */ #define __GFP_RECLAIMABLE ((__force gfp_t)0x80000u) /* Page is reclaimable */ #define __GFP_MOVABLE ((__force gfp_t)0x100000u) /* Page is movable */
__GFP_HIGH 表示内核急切需要内存,系统分配内存会带了严重后果。由于__GFP_HIGH又等于GFP_ATOMIC,意味着__GFP_HIGH禁止中断,并且可以使用紧急分配链表的内存。
__GFP_IO 表示在查找空闲内存期间,内核可以执行IO操作,这意味着,如果没有足够的内存,那么当设置此标志时,允许回收系统把选择的页写回磁盘。
__GFP_FS 允许执行低层文件系统操作
__GFP_COLD 如果需要分配不在CPU高速缓存中的冷页面时,则设置__GFP_COLD
__GFP_NOWARN 在内核分配内存失败时,禁止内核故障警告。
__GFP_REPEAT 在分配失败后继续尝试,但在若干次后停止尝试。
__GFP_ZERO 分配成功后,把所有返回的页填充0
__GFP_NOMEMALLOC 不允许使用紧急预留内存。
__GFP_THISNODE 只有在NUMA系统上才有意义,如果置位,那么在分配失败的情况下,不允许尝试其他节点。
__GFP_RECLAIMABLE和__GFP_MOVABLE 标记从哪个空闲链表获取内存。