1.node的转换
在分配内存时,都会带分配参数比如GPF_KERNEL等等,那么,一次内存分配从哪个zone分配了?
这里就必需把mask转换成zone,gfp_mask低4位用于表示分配的zone
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;
}
其中ZONES_SHIFT,表示系统中的zone个数不超过2的ZONE_SHIFT次方,比如zone个数为5,那么zone_SHIFT=3,用
3bit表示zone的index(0-5),如果只有三个zone,那么ZONES_SHIFT=2,因为2个bit,可以表示4个数.
GFP_ZONEMASK定义的地方如下:
#define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
#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)位上,依此类推。
bit*ZONE_SHIFT即得到该ZONE所对应的BIT位,然后将GFP_ZONE_TABLE左移所得位数量,这时候得到的是从这个ZONE开始往上的所有BIT位,要将无关的ZONE清零,即只取低ZONE_SHIFT位,所以要&((1<<ZONE_SHITF) -1)
2.node的选择
在进行内存分配时,需要选择从哪个node分配内存,或者当前node内存不足时,又应该从哪个node分配了?
通过gfp_zone(gfp_mask),确认一个high zoneidx(最高的zone index),分配内存的优先级从high zoneidx-> low zone index
ZONE_MOVEBLE -> ZONE_NORMAL->ZONE_DMA,也就是ZONE_MOVEBLE不足时,可以从NORMAL和DMA Zone依次分配.列如GFP_KERNEL,优先从ZONE_NORMAL,不足时从ZONE_DMA分配,而如果标识GFP_DMA,那么只能从ZONE_DMA区分配,因为DMA ZONE的index=0,为最低.
选择zone的代码:
#define for_each_zone_zonelist_nodemask(zone, z, zlist, highidx, nodemask) \
for (z = first_zones_zonelist(zlist, highidx, nodemask, &zone); \
zone; \
z = next_zones_zonelist(++z, highidx, nodemask), \
zone = zonelist_zone(z))
static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist,
enum zone_type highest_zoneidx,
nodemask_t *nodes,
struct zone **zone)
{
struct zoneref *z = next_zones_zonelist(zonelist->_zonerefs,
highest_zoneidx, nodes);
*zone = zonelist_zone(z);
return z;
}
struct zoneref *next_zones_zonelist(struct zoneref *z,
enum zone_type highest_zoneidx, nodemask_t *nodes)
{
if (likely(nodes == NULL))
while (zonelist_zone_idx(z) > highest_zoneidx)//找到第一个合适的zone idx
z++;
return z;
}
3. migratetype的转换
static inline int gfpflags_to_migratetype(const gfp_t gfp_flags)
{
VM_WARN_ON((gfp_flags & GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK);
BUILD_BUG_ON((1UL << GFP_MOVABLE_SHIFT) != ___GFP_MOVABLE);
BUILD_BUG_ON((___GFP_MOVABLE >> GFP_MOVABLE_SHIFT) != MIGRATE_MOVABLE);
if (unlikely(page_group_by_mobility_disabled))
return MIGRATE_UNMOVABLE;
/* Group based on mobility */
return (gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT;
}
GFP_MOVABLE_MASK=0x18,GFP_MOVABLE_SHIFT=3,
可以看出,计算migrate type很简单,(gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT
可以看出gfp_flags的bit3-bit4表示migrate类型
enum {
MIGRATE_UNMOVABLE,
MIGRATE_MOVABLE,
MIGRATE_RECLAIMABLE,
MIGRATE_PCPTYPES, /* the number of types on the pcp lists */
MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,
#ifdef CONFIG_CMA
MIGRATE_CMA,
#endif
#ifdef CONFIG_MEMORY_ISOLATION
MIGRATE_ISOLATE, /* can't allocate from here */
#endif
MIGRATE_TYPES
};