1. 程式人生 > >gfp_mask轉換成對應的zone和migratetype

gfp_mask轉換成對應的zone和migratetype

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
};