一.总体说明
1.1 在mm/slab.c中定义了kmem_cache_s结构
-
struct kmem_cache_s {
-
/* 1) each alloc & free */
-
/* full, partial first, then free */
-
struct list_head slabs_full;
-
struct list_head slabs_partial;
-
struct list_head slabs_free;
-
unsigned int objsize;
-
unsigned int flags; /* constant flags */
-
unsigned int num; /* # of objs per slab */
-
spinlock_t spinlock;
-
#ifdef CONFIG_SMP
-
unsigned int batchcount;
-
#endif
-
-
/* 2) slab additions /removals */
-
/* order of pgs per slab (2^n) */
-
unsigned int gfporder;
-
-
/* force GFP flags, e.g. GFP_DMA */
-
unsigned int gfpflags;
-
-
size_t colour; /* cache colouring range */
-
unsigned int colour_off; /* colour offset */
-
unsigned int colour_next; /* cache colouring */
-
kmem_cache_t *slabp_cache;
-
unsigned int growing;
-
unsigned int dflags; /* dynamic flags */
-
-
/* constructor func */
-
void (*ctor)(void *, kmem_cache_t *, unsigned long);
-
-
/* de-constructor func */
-
void (*dtor)(void *, kmem_cache_t *, unsigned long);
-
-
unsigned long failures;
-
-
/* 3) cache creation/removal */
-
char name[CACHE_NAMELEN];
-
struct list_head next;
-
#ifdef CONFIG_SMP
-
/* 4) per-cpu data */
-
cpucache_t *cpudata[NR_CPUS];
-
#endif
-
#if STATS
-
unsigned long num_active;
-
unsigned long num_allocations;
-
unsigned long high_mark;
-
unsigned long grown;
-
unsigned long reaped;
-
unsigned long errors;
-
#ifdef CONFIG_SMP
-
atomic_t allochit;
-
atomic_t allocmiss;
-
atomic_t freehit;
-
atomic_t freemiss;
-
#endif
-
#endif
-
};
-
typedef struct slab_s {
-
struct list_head list;
-
unsigned long colouroff;
-
void *s_mem; /* including colour offset */
-
unsigned int inuse; /* num of objs active in slab */
-
kmem_bufctl_t free; //注意这儿free不是left.判断结束free==BUFCLT_END?结束:不结束
-
} slab_t;
关于free,有如下define
-
#define BUFCTL_END 0xffffFFFF //用最大值+1来代表结束
-
#define SLAB_LIMIT 0xffffFFFE //即slab的最大值是0xFFFFFFFE,结束值是最大值加1
二.代码分析
Kernel hacking --->
[*] Debug memory allocations --> CONFIG_DEBUG_SLAB
-
static kmem_cache_t cache_cache = {
-
slabs_full: LIST_HEAD_INIT(cache_cache.slabs_full),
-
slabs_partial: LIST_HEAD_INIT(cache_cache.slabs_partial),
-
slabs_free: LIST_HEAD_INIT(cache_cache.slabs_free),
-
objsize: sizeof(kmem_cache_t),
-
flags: SLAB_NO_REAP,
-
spinlock: SPIN_LOCK_UNLOCKED,
-
colour_off: L1_CACHE_BYTES,
-
name: "kmem_cache",
-
};
2.1 在mm/slab.c中L415-->kmem_cache_init
start_kernel-->kmem_cache_init
-
void __init kmem_cache_init(void)
-
{
-
size_t left_over;
-
-
init_MUTEX(&cache_chain_sem);
-
//#define cache_chain (cache_cache.next), 初始化高速缓存链表cache_cache.next
-
INIT_LIST_HEAD(&cache_chain);
-
//计算对象的数量以及消耗的字节数
-
kmem_cache_estimate(0, cache_cache.objsize, 0, &left_over, &cache_cache.num);
-
if (!cache_cache.num)
-
BUG();
-
cache_cache.colour = left_over/cache_cache.colour_off; //colour_off是L1高速缓存对齐时可用的不同高速缓存行数目,执行后colour=0
-
cache_cache.colour_next = 0; //colour_next表明要使用的下个高速缓存行,从0开始
-
}
执行后:NO_DEBUG时cache_cache的地址=0xc02cf7c0,sizeof(cache_cache)=248
-
$1 = {slabs_full = {next = 0xc02cf7c0 <cache_cache>, prev = 0xc02cf7c0 <cache_cache>}, slabs_partial = {next = 0xc02cf7c8 <cache_cache+8>, prev = 0xc02cf7c8 <cache_cache+8>},
-
slabs_free = {next = 0xc02cf7d0 <cache_cache+16>, prev = 0xc02cf7d0 <cache_cache+16>}, objsize = 248, flags = 4096, num = 16, spinlock = {lock = 1, magic = 3735899821},
-
batchcount = 0, gfporder = 0, gfpflags = 0, colour = 0, colour_off = 128, colour_next = 0, slabp_cache = 0x0, growing = 0, dflags = 0, ctor = 0x0, dtor = 0x0, failures = 0,
-
name = "kmem_cache\000\000\000\000\000\000\000\000\000", next = {next = 0xc02cf830 <cache_cache+112>, prev = 0xc02cf830 <cache_cache+112>}, cpudata = {0x0 <repeats 32 times>}}
2.1.1 在mm/slab.c中L387-->kmem_cache_init-->kmem_cache_estimate
gfporder=0, size=sizeof(kmem_cache_t)=0xF8=248,flags=0x0 DEUB时size=288
-
static void kmem_cache_estimate (unsigned long gfporder, size_t size, int flags, size_t *left_over, unsigned int *num)
-
{
-
int i;
-
size_t wastage = PAGE_SIZE<<gfporder; //这儿gfporder=0,所以wastage=4096=0x1000
-
size_t extra = 0;
-
size_t base = 0;
-
-
if (!(flags & CFLGS_OFF_SLAB)) { //CFLAGS_OFF_SLAB表示slab描述符存储在slab之外
-
base = sizeof(slab_t); //base=24
-
extra = sizeof(kmem_bufctl_t); //extra=4
-
}
-
i = 0;
-
while (i*size + L1_CACHE_ALIGN(base+i*extra) <= wastage) //wastage=4096,size=248
-
i++; //执行后i=17
-
if (i > 0)
-
i--; //执行后i=16
-
-
if (i > SLAB_LIMIT) //SLAB_LIMIT=0xffffFFFE
-
i = SLAB_LIMIT;
-
-
*num = i;
-
wastage -= i*size; //i=16,size=248,i*size=3968,执行后wastage=128 //DEBUG时wastage=352
-
wastage -= L1_CACHE_ALIGN(base+i*extra); //执行后wastage=0 //DEBUG时:wastage=224
-
*left_over = wastage; //执行后*left_over=0 //DEBUG时:*left_over=224
-
}
2.2 start_kernel-->mem_init之后-->kmem_cache_sizes_init
-
/* Initialisation - setup remaining internal and general caches.
-
* Called after the gfp() functions have been enabled, and before smp_init().
-
*/
-
void __init kmem_cache_sizes_init(void)
-
{
-
cache_sizes_t *sizes = cache_sizes; //cache_sizes最小32Byte, 最大131072=128KB=32个pages
-
char name[20];
-
-
if (num_physpages > (32 << 20) >> PAGE_SHIFT) //num_physpages=0x3fffe即物理内存的最大页帧>大于32M的页帧
-
slab_break_gfp_order = BREAK_GFP_ORDER_HI; //执行后slab_break_gfp_order=2
-
-
//cs_size={32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072}
-
//
-
do {
-
sprintf(name,"size-%Zd",sizes->cs_size);
-
//执行后sizes->cs_cachep=0xc210b080
-
if (!(sizes->cs_cachep = kmem_cache_create(name, sizes->cs_size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) {
-
BUG();
-
}
-
-
/* Inc off-slab bufctl limit until the ceiling is hit. */
-
if (!(OFF_SLAB(sizes->cs_cachep))) {
-
offslab_limit = sizes->cs_size-sizeof(slab_t); //执行后offslab_limit=4
-
offslab_limit /= 2; //执行后offslab_limit=2
-
}
-
sprintf(name, "size-%Zd(DMA)",sizes->cs_size); //下面开始对size-32(DMA)的slab进行初始化
-
sizes->cs_dmacachep = kmem_cache_create(name, sizes->cs_size, 0, SLAB_CACHE_DMA|SLAB_HWCACHE_ALIGN, NULL, NULL);
-
if (!sizes->cs_dmacachep)
-
BUG();
-
sizes++;
-
} while (sizes->cs_size);
-
}
在mm/slab.c中L592
kmem_cache_sizes_init-->kmem_cache_create
name="size-32", size=0x20, offset=0x0, flags=SLAB_HWCACHE_ALIGN=0x2000, ctor=NULL, dtor=NULL
-
kmem_cache_t * kmem_cache_create (const char *name, size_t size, size_t offset,
-
unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long),
-
void (*dtor)(void*, kmem_cache_t *, unsigned long))
-
{
-
const char *func_nm = KERN_ERR "kmem_create: ";
-
size_t left_over, align, slab_size;
-
kmem_cache_t *cachep = NULL;
-
-
... //省略一些判断
-
-
/* Get cache's description obj. */
-
cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL); //执行后cache0xc210b080
-
if (!cachep)
-
goto opps;
-
memset(cachep, 0, sizeof(kmem_cache_t));
-
-
/* Check that size is in terms of words. This is needed to avoid
-
* unaligned accesses for some archs when redzoning is used, and makes
-
* sure any on-slab bufctl's are also correctly aligned.
-
*/
-
if (size & (BYTES_PER_WORD-1)) {
-
size += (BYTES_PER_WORD-1);
-
size &= ~(BYTES_PER_WORD-1);
-
printk("%sForcing size word alignment - %s\n", func_nm, name);
-
}
-
-
align = BYTES_PER_WORD; //执行后align=4
-
if (flags & SLAB_HWCACHE_ALIGN)
-
align = L1_CACHE_BYTES; //执行后align=128=0x80
-
-
/* Determine if the slab management is 'on' or 'off' slab. */
-
if (size >= (PAGE_SIZE>>3)) //此时size=32
-
flags |= CFLGS_OFF_SLAB;
-
-
if (flags & SLAB_HWCACHE_ALIGN) {
-
while (size < align/2)
-
align /= 2; //原先align=32执行后align=64
-
size = (size+align-1)&(~(align-1)); //原先size=32执行后size=64
-
//这儿有点不太理解,为什么需要将32扩展为64,将4个放进一个cache中不行吗?为什么必须得是2个放进一个cache中?
-
}
-
//开启DEBUG_SLAB时,flags=0xC00, size=0x28=40 -->这儿不关心这种情况
-
//不开启DEBUG_SLAB时,flags=0x200,size=64,align=64
-
do {
-
unsigned int break_flag = 0;
-
cal_wastage:
-
//计算gfporder个page中,这儿是1个page可以放多少个obj
-
kmem_cache_estimate(cachep->gfporder, size, flags, &left_over, &cachep->num); //执行后left_over=128,cachep->num=58
-
if (break_flag)
-
break;
-
if (cachep->gfporder >= MAX_GFP_ORDER)
-
break;
-
if (!cachep->num)
-
goto next;
-
if (flags & CFLGS_OFF_SLAB && cachep->num > offslab_limit) {
-
/* Oops, this num of objs will cause problems. */
-
cachep->gfporder--;
-
break_flag++;
-
goto cal_wastage;
-
}
-
if (cachep->gfporder >= slab_break_gfp_order)
-
break;
-
-
if ((left_over*8) <= (PAGE_SIZE<<cachep->gfporder)) //left_over=112,如果内部碎片<(缓存)/8是可以接受的
-
break; /* Acceptable internal fragmentation. */
-
next:
-
cachep->gfporder++;
-
} while (1);
-
-
if (!cachep->num) {
-
printk("kmem_cache_create: couldn't create cache %s.\n", name);
-
kmem_cache_free(&cache_cache, cachep);
-
cachep = NULL;
-
goto opps;
-
}
-
slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(slab_t)); //slab_size=256
-
-
if (flags & CFLGS_OFF_SLAB && left_over >= slab_size) {
-
flags &= ~CFLGS_OFF_SLAB;
-
left_over -= slab_size;
-
}
-
-
/* Offset must be a multiple of the alignment. */
-
offset += (align-1); //执行后offset=63,align=64
-
offset &= ~(align-1); //执行后offset=0,align=64
-
if (!offset)
-
offset = L1_CACHE_BYTES; //执行后offset=128=0x80
-
cachep->colour_off = offset;
-
cachep->colour = left_over/offset; //left_over=128,offset=128,执行后cachep->colour=1
-
-
/* init remaining fields */
-
if (!cachep->gfporder && !(flags & CFLGS_OFF_SLAB))
-
flags |= CFLGS_OPTIMIZE;
-
-
cachep->flags = flags;
-
cachep->gfpflags = 0;
-
if (flags & SLAB_CACHE_DMA)
-
cachep->gfpflags |= GFP_DMA;
-
spin_lock_init(&cachep->spinlock);
-
cachep->objsize = size;
-
INIT_LIST_HEAD(&cachep->slabs_full);
-
INIT_LIST_HEAD(&cachep->slabs_partial);
-
INIT_LIST_HEAD(&cachep->slabs_free);
-
-
if (flags & CFLGS_OFF_SLAB)
-
cachep->slabp_cache = kmem_find_general_cachep(slab_size,0);
-
cachep->ctor = ctor;
-
cachep->dtor = dtor;
-
/* Copy name over so we don't have problems with unloaded modules */
-
strcpy(cachep->name, name);
-
-
#ifdef CONFIG_SMP
-
if (g_cpucache_up)
-
enable_cpucache(cachep);
-
#endif
-
/* Need the semaphore to access the chain. */
-
down(&cache_chain_sem);
-
{
-
struct list_head *p;
-
-
list_for_each(p, &cache_chain) {
-
kmem_cache_t *pc = list_entry(p, kmem_cache_t, next);
-
-
/* The name field is constant - no lock needed. */
-
if (!strcmp(pc->name, name))
-
BUG();
-
}
-
}
-
-
/* There is no reason to lock our new cache before we
-
* link it in - no one knows about it yet...
-
*/
-
list_add(&cachep->next, &cache_chain);
-
up(&cache_chain_sem);
-
opps:
-
return cachep;
-
}
执行后
-
(gdb) p *sizes->cs_cachep //0xc210b080
-
$3 = {slabs_full = {next = 0xc210b080, prev = 0xc210b080}, slabs_partial = {next = 0xc210b088, prev = 0xc210b088}, slabs_free = {next = 0xc210b090, prev = 0xc210b090},
-
objsize = 40, flags = 134144, num = 90, spinlock = {lock = 1, magic = 0xdead4ead}, batchcount = 0, gfporder = 0, gfpflags = 0, colour = 0, colour_off = 128, colour_next = 0,
-
slabp_cache = 0x0, growing = 0, dflags = 0, ctor = 0x0, dtor = 0x0, failures = 0, name = "size-32", '\000' <repeats 12 times>, next = {next = 0xc02d0630 <cache_cache+112>,
-
prev = 0xc210b210}, cpudata = {0x0 <repeats 32 times>}, num_active = 0, num_allocations = 0, high_mark = 0, grown = 0, reaped = 0, errors = 0, allochit = {counter = 0},
-
allocmiss = {counter = 0}, freehit = {counter = 0}, freemiss = {counter = 0}}
-
-
(gdb) p *sizes->cs_dmacachep //0xc210b1a0
-
$4 = {slabs_full = {next = 0xc210b1a0, prev = 0xc210b1a0}, slabs_partial = {next = 0xc210b1a8, prev = 0xc210b1a8}, slabs_free = {next = 0xc210b1b0, prev = 0xc210b1b0},
-
objsize = 40, flags = 150528, num = 90, spinlock = {lock = 1, magic = 0xdead4ead}, batchcount = 0, gfporder = 0, gfpflags = 1, colour = 0, colour_off = 128, colour_next = 0,
-
slabp_cache = 0x0, growing = 0, dflags = 0, ctor = 0x0, dtor = 0x0, failures = 0, name = "size-32(DMA)\000\000\000\000\000\000\000", next = {next = 0xc210b0f0,
-
prev = 0xc02d0630 <cache_cache+112>}, cpudata = {0x0 <repeats 32 times>}, num_active = 0, num_allocations = 0, high_mark = 0, grown = 0, reaped = 0, errors = 0, allochit = {
-
counter = 0}, allocmiss = {counter = 0}, freehit = {counter = 0}, freemiss = {counter = 0}}
-
(gdb) p *sizes->cs_cachep //0xc210b2c0
-
$6 = {slabs_full = {next = 0xc210b2c0, prev = 0xc210b2c0}, slabs_partial = {next = 0xc210b2c8, prev = 0xc210b2c8}, slabs_free = {next = 0xc210b2d0, prev = 0xc210b2d0},
-
objsize = 72, flags = 134144, num = 53, spinlock = {lock = 1, magic = 0xdead4ead}, batchcount = 0, gfporder = 0, gfpflags = 0, colour = 0, colour_off = 128, colour_next = 0,
-
slabp_cache = 0x0, growing = 0, dflags = 0, ctor = 0x0, dtor = 0x0, failures = 0, name = "size-64", '\000' <repeats 12 times>, next = {next = 0xc210b210, prev = 0xc210b450},
-
cpudata = {0x0 <repeats 32 times>}, num_active = 0, num_allocations = 0, high_mark = 0, grown = 0, reaped = 0, errors = 0, allochit = {counter = 0}, allocmiss = {counter = 0},
-
freehit = {counter = 0}, freemiss = {counter = 0}}
-
-
(gdb) p *sizes->cs_dmacachep //0xc210b3e0
-
$8 = {slabs_full = {next = 0xc210b3e0, prev = 0xc210b3e0}, slabs_partial = {next = 0xc210b3e8, prev = 0xc210b3e8}, slabs_free = {next = 0xc210b3f0, prev = 0xc210b3f0},
-
objsize = 72, flags = 150528, num = 53, spinlock = {lock = 1, magic = 0xdead4ead}, batchcount = 0, gfporder = 0, gfpflags = 1, colour = 0, colour_off = 128, colour_next = 0,
-
slabp_cache = 0x0, growing = 0, dflags = 0, ctor = 0x0, dtor = 0x0, failures = 0, name = "size-64(DMA)\000\000\000\000\000\000\000", next = {next = 0xc210b330,
-
prev = 0xc02d0630 <cache_cache+112>}, cpudata = {0x0 <repeats 32 times>}, num_active = 0, num_allocations = 0, high_mark = 0, grown = 0, reaped = 0, errors = 0, allochit = {
-
counter = 0}, allocmiss = {counter = 0}, freehit = {counter = 0}, freemiss = {counter = 0}}
-
(gdb) p *sizes->cs_cachep //0xc210b500
-
$11 = {slabs_full = {next = 0xc210b500, prev = 0xc210b500}, slabs_partial = {next = 0xc210b508, prev = 0xc210b508}, slabs_free = {next = 0xc210b510, prev = 0xc210b510},
-
objsize = 136, flags = 134144, num = 28, spinlock = {lock = 1, magic = 3735899821}, batchcount = 0, gfporder = 0, gfpflags = 0, colour = 0, colour_off = 128, colour_next = 0,
-
slabp_cache = 0x0, growing = 0, dflags = 0, ctor = 0x0, dtor = 0x0, failures = 0, name = "size-128", '\000' <repeats 11 times>, next = {next = 0xc210b450, prev = 0xc210b690},
-
cpudata = {0x0 <repeats 32 times>}, num_active = 0, num_allocations = 0, high_mark = 0, grown = 0, reaped = 0, errors = 0, allochit = {counter = 0}, allocmiss = {counter = 0},
-
freehit = {counter = 0}, freemiss = {counter = 0}}
-
-
(gdb) p *sizes->cs_dmacachep //0xc210b620
-
$13 = {slabs_full = {next = 0xc210b620, prev = 0xc210b620}, slabs_partial = {next = 0xc210b628, prev = 0xc210b628}, slabs_free = {next = 0xc210b630, prev = 0xc210b630},
-
objsize = 136, flags = 150528, num = 28, spinlock = {lock = 1, magic = 3735899821}, batchcount = 0, gfporder = 0, gfpflags = 1, colour = 0, colour_off = 128, colour_next = 0,
-
slabp_cache = 0x0, growing = 0, dflags = 0, ctor = 0x0, dtor = 0x0, failures = 0, name = "size-128(DMA)\000\000\000\000\000\000", next = {next = 0xc210b570,
-
prev = 0xc02d0630 <cache_cache+112>}, cpudata = {0x0 <repeats 32 times>}, num_active = 0, num_allocations = 0, high_mark = 0, grown = 0, reaped = 0, errors = 0, allochit = {
-
counter = 0}, allocmiss = {counter = 0}, freehit = {counter = 0}, freemiss = {counter = 0}}
三. kmem_cache_alloc的过程
调用:cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL);
-
flags=GFP_KERNEL=0x1F0
-
#define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
-
0x20 0x10 0x40 0x80 0x100
3.1 在mm/slab.c中
kmem_cache_sizes_init-->kmem_cache_create-->kmem_cache_alloc
-
void * kmem_cache_alloc (kmem_cache_t *cachep, int flags)
-
{
-
return __kmem_cache_alloc(cachep, flags);
-
}
只是封装了一下__kmem_cache_alloc而己
-
static inline void * __kmem_cache_alloc (kmem_cache_t *cachep, int flags)
-
{
-
unsigned long save_flags;
-
void* objp;
-
//检查标志位是不是合法
-
kmem_cache_alloc_head(cachep, flags); //3.2
-
try_again:
-
local_irq_save(save_flags);
-
#ifdef CONFIG_SMP
-
{
-
cpucache_t *cc = cc_data(cachep); //执行后cc=0x0
-
-
if (cc) {
-
if (cc->avail) {
-
STATS_INC_ALLOCHIT(cachep);
-
objp = cc_entry(cc)[--cc->avail];
-
} else {
-
STATS_INC_ALLOCMISS(cachep);
-
objp = kmem_cache_alloc_batch(cachep,cc,flags);
-
if (!objp)
-
goto alloc_new_slab_nolock;
-
}
-
} else {
-
spin_lock(&cachep->spinlock); //smp需要加锁了
-
objp = kmem_cache_alloc_one(cachep); //3.3如果从slab->free中分配不到slab就跳到alloc_new_slab
-
spin_unlock(&cachep->spinlock); //alloc_new_slab完之后事slab->free
-
}
-
}
-
#else
-
objp = kmem_cache_alloc_one(cachep);
-
#endif
-
local_irq_restore(save_flags);
-
return objp;
-
alloc_new_slab: //kmem_cache_alloc_one是一个宏定义,如果slabs->free中也没有就跳到这儿
-
#ifdef CONFIG_SMP
-
spin_unlock(&cachep->spinlock);
-
alloc_new_slab_nolock:
-
#endif
-
local_irq_restore(save_flags);
-
if (kmem_cache_grow(cachep, flags)) //3.4
-
goto try_again; //申请slab之后再跳回去,到上面的try_agin
-
return NULL;
-
}
3.2 只是检查flags是不是合法
kmem_cache_alloc_head(cachep, flags);
-
static inline void kmem_cache_alloc_head(kmem_cache_t *cachep, int flags)
-
{
-
if (flags & SLAB_DMA) { //flags=GFP_KERNEL=0x1F0, SLAB_DMA=0x01
-
if (!(cachep->gfpflags & GFP_DMA))
-
BUG();
-
} else {
-
if (cachep->gfpflags & GFP_DMA) //cachep->gfpflags=0x0
-
BUG();
-
}
-
}
3.3
这个函数要调用两次,第1次时因为slabs_free是空的,所以要goto alloc_new_slab
第2次时slabs_free不为空,可以分配到kmem_cache
-
#define kmem_cache_alloc_one(cachep)
-
({
-
struct list_head * slabs_partial, * entry;
-
slab_t *slabp;
-
slabs_partial = &(cachep)->slabs_partial; //取slabs_partial的头结点
-
entry = slabs_partial->next; //因为slabs_partial此时还为空,所以这个entry=NULL
-
if (unlikely(entry == slabs_partial)) { //判断slabs_partial的链表是否为空,这儿是空的
-
struct list_head * slabs_free;
-
slabs_free = &(cachep)->slabs_free; //取slabs_free的头结点
-
entry = slabs_free->next; //因为slabs_free此时还为空,所以这个entry=NULL
-
if (unlikely(entry == slabs_free)) //判断slabs_free的链表是否为空,这儿是空的
-
goto alloc_new_slab; //所以要跳到alloc_new_slab中
-
list_del(entry);
-
list_add(entry, slabs_partial);
-
}
-
-
slabp = list_entry(entry, slab_t, list);
-
kmem_cache_alloc_one_tail(cachep, slabp); //3.3.1
-
})
3.4
-
static int kmem_cache_grow (kmem_cache_t * cachep, int flags)
-
{
-
slab_t *slabp;
-
struct page *page;
-
void *objp;
-
size_t offset;
-
unsigned int i, local_flags;
-
unsigned long ctor_flags;
-
unsigned long save_flags;
-
-
... //省略一些判断
-
-
ctor_flags = SLAB_CTOR_CONSTRUCTOR; //执行后ctor_flags=0x1
-
local_flags = (flags & SLAB_LEVEL_MASK); //执行后local_flags=0x1f0
-
if (local_flags == SLAB_ATOMIC)
-
ctor_flags |= SLAB_CTOR_ATOMIC;
-
-
/* About to mess with non-constant members - lock. */
-
spin_lock_irqsave(&cachep->spinlock, save_flags);
-
-
/* Get colour for the slab, and cal the next value. */
-
offset = cachep->colour_next; //此时cachep->colour_next=0x0执行后offset=0x0
-
cachep->colour_next++; //执行后cachep->colour_next=0x1
-
if (cachep->colour_next >= cachep->colour) //此时colour_next=0x1, colour=0x1
-
cachep->colour_next = 0; //执行后cachep->colour_next=0x0
-
offset *= cachep->colour_off; //执行前offset=0x0,所以执行后offset=0x0
-
cachep->dflags |= DFLGS_GROWN; //执行后cachep->dflags=0x01
-
-
cachep->growing++; //执行前growing=0x0,所以执行后growing=0x1
-
spin_unlock_irqrestore(&cachep->spinlock, save_flags);
-
-
/* Get mem for the objs. */
-
if (!(objp = kmem_getpages(cachep, flags))) //从zone_normal处分配一页内存0xc210b000
-
goto failed;
-
-
//offset=0x0,local_flags=0x1f0
-
if (!(slabp = kmem_cache_slabmgmt(cachep, objp, offset, local_flags))) //3.4.1执行后slabp指向0xc210b000
-
goto opps1;
-
-
/* I hope this is OK. */
-
i = 1 << cachep->gfporder; //执行前cachep->gfporder=0x0,所以执行后i=0x1
-
page = virt_to_page(objp); //将虚地址objp转为mem_map中的管理page
-
do {
-
SET_PAGE_CACHE(page, cachep); //page->list.next=cachep
-
SET_PAGE_SLAB(page, slabp); //page->list.pre=slabp
-
PageSetSlab(page); //将page->flags设为PG_slab
-
page++;
-
} while (--i);
-
-
kmem_cache_init_objs(cachep, slabp, ctor_flags); //3.4.2
-
-
spin_lock_irqsave(&cachep->spinlock, save_flags);
-
cachep->growing--; //执行后cachep->growing=0x0
-
-
/* Make slab active. */
-
list_add_tail(&slabp->list, &cachep->slabs_free); //把申请到的slab加到slabs_frees中
-
STATS_INC_GROWN(cachep); //使cachep->grown++,执行后cachep->grown=0x01
-
cachep->failures = 0;
-
-
spin_unlock_irqrestore(&cachep->spinlock, save_flags);
-
return 1;
-
opps1:
-
kmem_freepages(cachep, objp);
-
failed:
-
spin_lock_irqsave(&cachep->spinlock, save_flags);
-
cachep->growing--;
-
spin_unlock_irqrestore(&cachep->spinlock, save_flags);
-
return 0;
-
}
3.4.1
参数说明: objp是刚从zone_normal中分配的一页内存的首地址0xc210b000
colour_off=0x0, local_flags=0x1F0=GFP_KERNEL
-
static inline slab_t * kmem_cache_slabmgmt (kmem_cache_t *cachep,
-
void *objp, int colour_off, int local_flags)
-
{
-
slab_t *slabp;
-
-
if (OFF_SLAB(cachep)) {
-
/* Slab management obj is off-slab. */
-
slabp = kmem_cache_alloc(cachep->slabp_cache, local_flags);
-
if (!slabp)
-
return NULL;
-
} else {
-
slabp = objp+colour_off; //执行前colour_off=0x0,执行后slabp是申请到的一页内存的首地址0xc210b000
-
colour_off += L1_CACHE_ALIGN(cachep->num * sizeof(kmem_bufctl_t) + sizeof(slab_t)); //执行后colour_off=0x80=128
-
}
-
slabp->inuse = 0;
-
slabp->colouroff = colour_off;
-
slabp->s_mem = objp+colour_off;
-
//执行后{list = {next = 0x0, prev = 0x0}, colouroff = 128, s_mem = 0xc210b080, inuse = 0, free = 0}
-
return slabp;
-
}
3.4.2
-
static inline void kmem_cache_init_objs (kmem_cache_t * cachep,
-
slab_t * slabp, unsigned long ctor_flags)
-
{
-
int i;
-
-
for (i = 0; i < cachep->num; i++) { //cachep->num=13
-
void* objp = slabp->s_mem+cachep->objsize*i; //0xc210b080
-
if (cachep->ctor)
-
cachep->ctor(objp, cachep, ctor_flags); //这儿不执行
-
slab_bufctl(slabp)[i] = i+1;
-
}
-
slab_bufctl(slabp)[i-1] = BUFCTL_END; //#define slab_bufctl(slabp) (kmem_bufctl_t *)(((slab_t*)slabp)+1))
-
slabp->free = 0;
-
}
执行后:
-
(gdb) p *slabp
$19 = {list = {next = 0x0, prev = 0x0}, colouroff = 128, s_mem = 0xc210b080, inuse = 0, free = 0}
-
-
(gdb) x /64wx slabp
-
0xc210b000: 0x00000000 0x00000000 0x00000080 0xc210b080
-
0xc210b010: 0x00000000 0x00000000 0x00000001 0x00000002
-
0xc210b020: 0x00000003 0x00000004 0x00000005 0x00000006
-
0xc210b030: 0x00000007 0x00000008 0x00000009 0x0000000a
-
0xc210b040: 0x0000000b 0x0000000c 0x0000000d 0x0000000e
-
0xc210b050: 0x0000000f 0xffffffff 0x00000000 0x00000000 //由原先的0x00000010-->0xFFFFFFFF代表是END
注意:slab_bufctl(slabp)中存的是下一项的值:
例如第0项存的是1,代表下一个是第1项; 第16项存的是0xFFFFFFFF代表结束
3.3.1
下面是第2次进入kmem_cache_alloc_one时会调用kmem_cache_alloc_one_tail
-
static inline void * kmem_cache_alloc_one_tail (kmem_cache_t *cachep, slab_t *slabp)
-
{
-
void *objp;
-
//slabp=0xc210b080
-
//里面的内容是 {list = {next = 0xc02d05c8 , prev = 0xc02d05c8 }, colouroff = 128, s_mem = 0xc210b080, inuse = 0, free = 0}
-
STATS_INC_ALLOCED(cachep);
-
STATS_INC_ACTIVE(cachep);
-
STATS_SET_HIGH(cachep);
-
-
slabp->inuse++; //执行后slabp->inuse=1
-
objp = slabp->s_mem + slabp->free*cachep->objsize; //目前slabp->free=0,所以执行后objp=0xc210b080
-
slabp->free=slab_bufctl(slabp)[slabp->free]; //执行后slabp->free=1,slab_bufctl(slabp)[slabp->free]是下一项的值
-
-
if (unlikely(slabp->free == BUFCTL_END)) { //如果slabp->free到头了,说明没有剩余的了,如果当前是第16项,即slab可以分配的最后一项
-
list_del(&slabp->list); //就把slabp->list清空,
-
list_add(&slabp->list, &cachep->slabs_full); //放到slabs_full中。然后下一次kmem_cache_alloc_one中知道slabs->free与slabs->part都为空。
-
}
-
return objp; //返回0xc210b080
-
}
-
解释kmem_cache_t的获取,即源码中的objp句,如下图所示:
四.总结
4.1 一个页面内的内容如下所示: 其中0xc210b000是从buddy中申请的一页内存
L1_CACHE_ALIGN=红色部分=slab+ slab_bufctl所占的内存共4*8*4=128个字节
slab占了24个字节,那么能表示slab_butctl的=(128-24)/4=26个
所以得出结论,L1_CACHE_ALIGN1内存最多能表示26个kmem_cache_t结构
但是kmem_cache_t本身占用248个字节,4096/248=16.5个,所以用不完。
4.3 kmem_cache_sizes_init结束后的cache_cache如下所示:
-
(gdb) p cache_cache
-
$4 = {slabs_full = {next = 0xc210b000, prev = 0xc210b000}, slabs_partial = {next = 0xc210f000, prev = 0xc210f000}, slabs_free = {next = 0xc02cf7d0 <cache_cache+16>,
-
prev = 0xc02cf7d0 <cache_cache+16>}, objsize = 248, flags = 4096, num = 16, spinlock = {lock = 1, magic = 3735899821}, batchcount = 0, gfporder = 0, gfpflags = 0, colour = 0,
-
colour_off = 128, colour_next = 0, slabp_cache = 0x0, growing = 0, dflags = 1, ctor = 0x0, dtor = 0x0, failures = 0, name = "kmem_cache\000\000\000\000\000\000\000\000\000",
-
next = {next = 0xc210f9a8, prev = 0xc210b0f0}, cpudata = {0x0 <repeats 32 times>}}
4.3 最终初始化结束后的内存结构如下所示:
slab_full上挂着第1次申请的1页内存,并且里面的kmem_cache_t结构体全部占用,
size-32, size-32(DMA) ------ size-4096, size-4096(DMA)
slab_partial上挂着第1次申请的1页内存,并且里面的kmem_cache_t结构体只有部分被占用
size-8192, size-8192(DMA) ------ size-131072, size-131072(DMA)
阅读(1663) | 评论(0) | 转发(0) |