linux上构建GFP_ZONE_TABLE

当内核分配内存时,需要指定gfp flag, 内核通过gfp标志判断从哪个zone分配内存。例如kmalloc(size_t size, gfp_t flags).

在linux中存在ZONE_DMA, ZONE_DMA32, ZONE_NORMAL, ZONE_HIGHMEM, ZONE_MOVABLE几个zone。

 

由于gfp_t 低4位,共有2^4=16中情况,而linux规定了低3位(DMA, DMA32, HIGHMEM)只能有1位为1.

gfp_t定义:

#define __GFP_DMA   0X01u

#define __GFP_HIGHMEM   0X02u

#define __GFP_DMA32   0X04u

#define __GFP_MOVABLE   0X08u

 

序号

__GFP_DMA

__GFP_HIGHMEM

__GFP_DMA32

__GFP_MOVABLE

组合结果

0

0

0

0

0

从ZONE_NORMAL分配

1

1

0

0

0

从ZONE_NORMAL或ZONE_DMA分配

2

0

1

0

0

从ZONE_HIGNMEM或ZONE_NORMAL分配

3

1

1

0

0

BAD

4

0

0

1

0

从ZONE_DMA32或ZONE_NORMAL分配

5

1

0

1

0

BAD

6

0

1

1

0

BAD

7

1

1

1

0

BAD

8

0

0

0

1

从ZONE_NORMAL分配

9

1

0

0

1

从ZONE_DMA或ZONE_NORMAL分配

a

0

1

0

1

从ZONE_MOVABLE分配

Movable is valid only if HIGHMEM is set too

b

1

1

0

1

BAD

c

0

0

1

1

从ZONE_DMA32分配

d

1

0

1

1

BAD

e

0

1

1

1

BAD

f

1

1

1

1

BAD

 

根据上表,很容易得到GFP_ZONE_BAD,即上述BAD的bit或在一起。

#define GFP_ZONE_BAD ( \

1 << (___GFP_DMA | ___GFP_HIGHMEM)                                      \

| 1 << (___GFP_DMA | ___GFP_DMA32)                                      \

| 1 << (___GFP_DMA32 | ___GFP_HIGHMEM)                                      \

| 1 << (___GFP_DMA | ___GFP_DMA32 | ___GFP_HIGHMEM)                      \

| 1 << (___GFP_MOVABLE | ___GFP_HIGHMEM | ___GFP_DMA)                      \

| 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA)                      \

| 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_HIGHMEM)                      \

| 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA | ___GFP_HIGHMEM)  \

)

 

内核中定义ZONE_SHIFT,根据MAX_NR_ZONES,得到相应的ZONE_SHIFT。

#if MAX_NR_ZONES < 2

#define ZONES_SHIFT 0

#elif MAX_NR_ZONES <= 2

#define ZONES_SHIFT 1

#elif MAX_NR_ZONES <= 4

#define ZONES_SHIFT 2

#else

#error ZONES_SHIFT -- too many zones configured adjust calculation

#endif

 

将上表换一种形式表示,如下:

 

 

由于每种分配策略用ZONE_SHIFT位就可以表示,所以将上图中非BAD的位bitN,对应的分配策略,左移bitN * ZONE_SHIFT位,组合成GFP_ZONE_TABLE, 即:

#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)   \

)

 

另外还定义GFP_ZONEMASK:

#define GFP_ZONEMASK        (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)

 

通过GFP_ZONE_TABLE宏,给定gfp的低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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值