void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask)从形参pool中申请内存
其源码分析如下:
void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask)
{
void *element;
unsigned long flags;
wait_queue_entry_t wait;
gfp_t gfp_temp;
#形参gfp_mast 中不能包含__GFP_ZERO 标志
VM_WARN_ON_ONCE(gfp_mask & __GFP_ZERO);
#如果包含__GFP_DIRECT_RECLAIM 的话,可能会导致sleep,这些就会打印callstack
might_sleep_if(gfp_mask & __GFP_DIRECT_RECLAIM);
#添加上这三个flag
gfp_mask |= __GFP_NOMEMALLOC; /* don't allocate emergency reserves */
gfp_mask |= __GFP_NORETRY; /* don't loop in __alloc_pages */
gfp_mask |= __GFP_NOWARN; /* failures are OK */
gfp_temp = gfp_mask & ~(__GFP_DIRECT_RECLAIM|__GFP_IO);
repeat_alloc:
#通过形参pool 来申请memory,正常情况下不会返归NULL
element = pool->alloc(gfp_temp, pool->pool_data);
if (likely(element != NULL))
return element;
spin_lock_irqsave(&pool->lock, flags);
if (likely(pool->curr_nr)) {
#如果pool->curr_nr 不为null的话,则肯定可以从pool中申请到memory。
element = remove_element(pool, gfp_temp);
spin_unlock_irqrestore(&pool->lock, flags);
/* paired with rmb in mempool_free(), read comment there */
smp_wmb();
/*
* Update the allocation stack trace as this is more useful
* for debugging.
*/
#由于这里肯定可以申请到内存,所以这里不检查element 是否为null,所以这里直接返回
kmemleak_update_trace(element);
return element;
}
/*
* We use gfp mask w/o direct reclaim or IO for the first round. If
* alloc failed with that and @pool was empty, retry immediately.
*/
#如果修改后的gfp_temp不等于形参gfp_mask,则用形参gfp_mask 赋值
if (gfp_temp != gfp_mask) {
spin_unlock_irqrestore(&pool->lock, flags);
gfp_temp = gfp_mask;
goto repeat_alloc;
}
/* We must not sleep if !__GFP_DIRECT_RECLAIM */
if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) {
spin_unlock_irqrestore(&pool->lock, flags);
return NULL;
}
#如果跑到这里的话,确实是没有内存申请,这里先sleep 5s后再继续尝试
/* Let's wait for someone else to return an element to @pool */
#初始化等待队列
init_wait(&wait);
#准备开始等待
prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
spin_unlock_irqrestore(&pool->lock, flags);
/*
* FIXME: this should be io_schedule(). The timeout is there as a
* workaround for some DM problems in 2.6.18.
*/
#睡眠5s
io_schedule_timeout(5*HZ);
#完成等待
finish_wait(&pool->wait, &wait);
goto repeat_alloc;
}