本篇文章只是分析一下gfp_mask到zone的对应关系在内核中的实现:
内核代码如下:(3.0)
#define GFP_ZONE_TABLE (ZONE_NORMAL << 0 * ZONES_SHIFT) \
| (OPT_ZONE_DMA << ___GFP_DMA * ZONES_SHIFT) \
| (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * ZONES_SHIFT) \
| (OPT_ZONE_DMA32 << ___GFP_DMA32 * ZONES_SHIFT) \
| (ZONE_NORMAL << ___GFP_MOVABLE * ZONES_SHIFT) \
| (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * ZONES_SHIFT) \
| (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * ZONES_SHIFT) \
| (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * ZONES_SHIFT) \
)
static inline enum zone_type gfp_zone(gfp_t flags)
{
enum zone_type z;
int bit = (__force int) (flags & GFP_ZONEMASK);
z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
((1 << ZONES_SHIFT) - 1);
VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
return z;
}
分析一下gfp_zone函数,首先系统中的ZONE的个数,不超过2的ZONE_SHIFT次方,即可以用ZONE_SHIFT个BIT位来表示ZONE的值,
GFP_ZONEMASK定义的地方如下:
#define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
flags&GFP_ZONEMASK,是将与GFP_XXX无关的其他位清零,下面看一下GFP_ZONE_TABLE的定义,定义中包含的几个宏变量,定义如下:
#ifdef CONFIG_HIGHMEM
#define OPT_ZONE_HIGHMEM ZONE_HIGHMEM
#else
#define OPT_ZONE_HIGHMEM ZONE_NORMAL
#endif
#ifdef CONFIG_ZONE_DMA
#define OPT_ZONE_DMA ZONE_DMA
#else
#define OPT_ZONE_DMA ZONE_NORMAL
#endif
#ifdef CONFIG_ZONE_DMA32
#define OPT_ZONE_DMA32 ZONE_DMA32
#else
#define OPT_ZONE_DMA32 ZONE_NORMAL
#endif
从其定义可以看出,如果没有定义HIGHMEM,则ZONE_HIGHMEM自动指向ZONE_NORMAL,其他类似。GFP_ZONE_TABLE的定义,其实是将各个ZONE的值放到对应的BIT位上,ZONE_NORMAL放到[0,ZONE_SHIFT)位,GFP_DMA放到[ZONE_SHIFT, 2*ZONE_SHIFT)位上,依此类推。
知道了GFP_ZONE_TABLE的意义,下面的语句也就不难理解了,bit*ZONE_SHIFT即得到该ZONE所对应的BIT位,然后将GFP_ZONE_TABLE左移所得位数量,这时候得到的是从这个ZONE开始往上的所有BIT位,要将无关的ZONE清零,即只取低ZONE_SHIFT位,所以要&((1<<ZONE_SHITF) -1)。下面VM_BUG_ON内的语句只是做一下校验,读者可以自行分析一下,应该不难理解。