分类: LINUX
2008-12-11 11:04:46
在内核中的一些地方,内存的分配不允许失败,为了确保内存的成功分配,内核开发者创建了一个叫做内存池的东西.
内存池的类型为struct mempool_s详细定义如下:
typedef struct mempool_s {
spinlock_t lock;
int min_nr; /* nr of elements at *elements */
int curr_nr; /* Current nr of elements at *elements */
void **elements;
void *pool_data;
mempool_alloc_t *alloc;
mempool_free_t *free;
wait_queue_head_t wait;
} mempool_t;
创建一个内存池需要一个mempool_t *mempool_create()
跟踪代码可以知道,其实该函数是调用mempool_create_node(min_nr,alloc_fn,free_fn, pool_data,-1)来实现内存池的创建.
mempool_create_node()的工作流程如下:
1、通过kmalloc向pool->kmalloc_node分配内存,失败则清空pool,返回null
2、开启pool->lock的自旋锁,给pool->min_nr、pool->pool_data分别赋值为min_nr和pool_data
3、初始化pool->wait等待队列,将pool->alloc 和 pool->free 的值设置成free_fn和 alloc_fn
4、当pool->curr_nr小于pool->min_nr时,循环将pool->alloc的值交给element,当pool->alloc分配失败时释放掉当前的内存池,返回null,把刚得到的element加入pool中。
5、返回最终得到的内存池
mempool_alloc负责分配创建得到的内存池分配
1、查看gfp的标志是否允许睡眠
2、设置gfp标志为__GFP_NOMEMALLOC(不分配紧急储备),__GFP_NORETRY(不在__alloc_pages中循环使用),__GFP_NOWARN(取消警告信息)
3、将当前gfp标志并上__GFP_WAIT与__GFP_IO的补码,设置成一个临时变量gfp_temp
4、把pool->alloc分配得到的mempool_alloc_t交给element,如果分配成功,返回element
5、Pool->alloc获得自旋锁,并在此之前禁止中断
6、如果pool->curr_nrb不为0时,将pool->element[curr_nr-1]在减除自旋锁之后返回
7、解除自旋锁
8、如果gfp没有__GFP_WAIT标志,返回null
9、把gfp_mask在此赋值给gfp_temp
10、 初始化等待队列wait,并将其加入pool->wait
11、 加入内存屏障
12、 如果pool->curr_nr为0时,设置5秒的读写调度超时,
13、 删除wait中的等待队列,再次从第四步开始重新分配
在当前内存池的大小不合适的情况下,可以采用mempool_resize()来重新设置min_nr的值
1、开启自旋锁pool->lock,并且在开启之前禁止中断
2、如果新的min_nr小于等于当前的min_nr时,释放pool->element的最后一个元素后退出,中间有个关闭开启自旋锁的过程,重新设置min_nr的值之后释放自旋锁退出
3、释放掉自旋锁
4、重新调用kmalloc分配内存交给new_element,分配失败时,返回-ENOMEM
5、开启自旋锁
6、当新min_nr大于min_nr时,释放掉刚分配的内存返回0
7、关闭自旋锁,允许内存池增加
8、将pool->element大小为pool->curr_nr * sizeof(*new_elements)的复制到new_element,也就是全部的复制
9、释放掉以前的pool->element
10、 将new_element设置成pool->element,将new_min_nr的值赋值给pool->min_nr
11、 当curr_nr小于min_nr时,循环执行:
a) 释放自旋锁
b) pool->alloc新分配空间交给element,失败则返回0;
c) 加上自旋锁,当curr_nr小于min_nr时,加入element到pool否则,解除自旋锁,释放掉刚申请的element,返回0