日期:2014-05-16 浏览次数:20727 次
伙伴系统中用于分配页的函数如下:
alloc_pages(mask,order)分配2^order页并返回一个struct page的实例,表示分配的内存块的起始页。alloc_page(mask)是前者在order=0情况下的简化形式,只分配一页。
get_zeroed_page(mask)分配一页并返回一个page实例,页对应的内存填充0(所有其他函数分配之后的内容是未定义的)。
__get_free_pages(mask,order)和__get_free_page(mask)的工作方式与上述函数相同,但返回分配内存块的虚拟地址,而不是page实例。
get_dma_pages(gfp_mask,order)用来获得适用于DMA的页。
在空闲内存无法满足请求以至于分配失败的情况下,所有上述函数都返回空指针(alloc_pages和alloc_page)或者0(get_zeroed_page、__get_free_pages和__get_free_page)。因此内核在各次分配之后必须检查返回的结果。这种惯例与设计得很好的用户层应用程序没有什么不同,但在内核中忽略检查将会导致严重得多的故障。
前述所有函数中使用的mask参数的语义是什么?linux将内核划分为内存域,内核提供了所谓的内存域修饰符,来指定从哪个内存域分配所需的页。
#define __GFP_DMA ((__force gfp_t)0x01u) #define __GFP_HIGHMEM ((__force gfp_t)0x02u) #define __GFP_DMA32 ((__force gfp_t)0x04u)除了内存域修饰符之外,掩码中还可以设置一些标志,这些额外的标志并不限制从哪个物理内存段分配内存,但确实可以改变分配器的行为。
#define __GFP_WAIT ((__force gfp_t)0x10u) //表示分配内存的请求可以中断。也就是说,调度器在该请求期间可随意选择另一个过程执行,或者该请求可以被另一个更重要的事件中断。 #define __GFP_HIGH ((__force gfp_t)0x20u) //如果请求非常重要,则设置__GFP_HIGH,即内核急切的需要内存时。在分配内存失败可能给内核带来严重得后果时,一般会设置该标志 #define __GFP_IO ((__force gfp_t)0x40u) //在查找空闲内存期间内核可以进行I/O操作。这意味着如果内核在内存分配期间换出页,那么仅当设置该标志时,才能将选择的页写入磁盘。 #define __GFP_FS ((__force gfp_t)0x80u) //允许内核执行VFS操作 #define __GFP_COLD ((__force gfp_t)0x100u) //如果需要分配不在CPU高速缓存中的“冷”页时,则设置__GFP_COLD。 #define __GFP_NOWARN ((__force gfp_t)0x200u) //在分配失败时禁止内核故障警告。 #define __GFP_REPEAT ((__force gfp_t)0x400u) //在分配失败后自动重试,但在尝试若干次之后会停止。 #define __GFP_NOFAIL ((__force gfp_t)0x800u) //在分配失败后一直重试,直至成功。 #define __GFP_NORETRY ((__force gfp_t)0x1000u)//不重试,可能失败 #define __GFP_COMP ((__force gfp_t)0x4000u)//增加复合页元数据 #define __GFP_ZERO ((__force gfp_t)0x8000u)//在分配成功时,将返回填充字节0的页。 #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) //不适用紧急分配链表 #define __GFP_HARDWALL ((__force gfp_t)0x20000u) //只在NUMA系统上有意义。它限制只在分配到当前进程的各个CPU所关联的结点分配内存。如果进程允许在所有的CPU上运行(默认情况下),该标志是没有意义的。只有进程可以运行的CPU受限时,该标志才有意义。 #define __GFP_THISNODE ((__force gfp_t)0x40000u)//页只在NUMA系统上有意义,如果设置该比特位,则内存分配失败的情况下不允许使用其他结点作为备用,需要保证在当前结点或者明确指定的结点上成功分配内存。 #define __GFP_RECLAIMABLE ((__force gfp_t)0x80000u) //将分配的内存标记为可回收 #define __GFP_MOVABLE ((__force gfp_t)0x100000u) //将分配的内存标记为可移动 #define __GFP_BITS_SHIFT 21 /* Room for 21 __GFP_FOO bits */ #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) /* This equals 0, but use constants in case they ever change */ #define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH)由于这些标志总是组合使用,内核做了一些分组,包含了用于各种标准情形的适当地标志。
#define GFP_ATOMIC (__GFP_HIGH)//用于原子分配,在任何情况下都不能中断,可能使用紧急分配链表中的内存 #define GFP_NOIO (__GFP_WAIT)//明确禁止IO操作,但可以被中断 #define GFP_NOFS (__GFP_WAIT | __GFP_IO)//明确禁止访问VFS层操作,但可以被中断 #define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS)//内核分配的默认配置 #define GFP_TEMPORARY (__GFP_WAIT | __GFP_IO | __GFP_FS | \ __GFP_RECLAIMABLE) #define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL)//用户分配的默认配置 #define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \ __GFP_HIGHMEM)//是GFP_USER的一个扩展,页用于用户空间,它允许分配无法直接映射的高端内存,使用高端内存页是没有坏处的,因为用户过程的地址空间总是通过非线性页表组织的 #define GFP_HIGHUSER_MOVABLE (__GFP_WAIT | __GFP_IO | __GFP_FS | \ __GFP_HARDWALL | __GFP_HIGHMEM | \ __GFP_MOVABLE)//类似于GFP_HIGHUSER,但分配是在虚拟内存域ZONE_MOVABLE中进行 #define GFP_NOFS_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_MOVABLE) #define GFP_USER_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_FS | \ __GFP_HARDWALL | __GFP_MOVABLE) #define GFP_HIGHUSER_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_FS | \ __GFP_HARDWALL | __GFP_HIGHMEM | \ __GFP_MOVABLE) #ifdef CONFIG_NUMA #define GFP_THISNODE (__GFP_THI