内存管理API之mempool_create

本文详细解析了mempool缓存池创建函数mempool_create的工作原理及内部实现流程,包括内存分配、初始化等关键步骤。
mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,mempool_free_t *free_fn, void *pool_data)
函数的功能是新建一个缓存池。
其源码分析如下:
mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
				mempool_free_t *free_fn, void *pool_data)
{
			#在形参中添加新建缓存的标志GFP_kernel ,   且不指明是在哪个node上.
	return mempool_create_node(min_nr,alloc_fn,free_fn, pool_data,
				   GFP_KERNEL, NUMA_NO_NODE);
}
EXPORT_SYMBOL(mempool_create);

mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn,
			       mempool_free_t *free_fn, void *pool_data,
			       gfp_t gfp_mask, int node_id)
{
	mempool_t *pool;
	#申请保存mempool自身结构的内存
	pool = kzalloc_node(sizeof(*pool), gfp_mask, node_id);
	if (!pool)
		return NULL;
	#申请最少min_nr 个byte 保存在缓存中,这样保证及时在内存紧张时至少可以申请min_nr个byte的内存
	pool->elements = kmalloc_array_node(min_nr, sizeof(void *),
				      gfp_mask, node_id);
	#如果能保证的最小内存都申请失败,则退出新建的缓存池,从这里也可以看出缓存池必要保证最小的内存输出
	if (!pool->elements) {
		kfree(pool);
		return NULL;
	}
	#初始化pool中的自旋锁
	spin_lock_init(&pool->lock);
	#保存最小可以从缓存中申请到的内存
	pool->min_nr = min_nr;
	pool->pool_data = pool_data;
	#初始化等待队列
	init_waitqueue_head(&pool->wait);
	#分别给从内存池中申请内存和释放内存的指针赋值,可以看到缓存池中最小内存不是由这个函数指针保证的。
	pool->alloc = alloc_fn;
	pool->free = free_fn;

	/*
	 * First pre-allocate the guaranteed number of buffers.
	 */
	 #除了前面通过kmalloc_array_node 预留内存池最小输出内存外,这里也通过alloc函数申请一份最小的可输出内存
	while (pool->curr_nr < pool->min_nr) {
		void *element;

		element = pool->alloc(gfp_mask, pool->pool_data);
		if (unlikely(!element)) {
			mempool_destroy(pool);
			return NULL;
		}
		#将通过alloc函数之神申请到的最小内存保存在list中
		add_element(pool, element);
	}
	return pool;
}

/** 365 * mempool_alloc - allocate an element from a specific memory pool 366 * @pool: pointer to the memory pool which was allocated via 367 * mempool_create(). 368 * @gfp_mask: the usual allocation bitmask. 369 * 370 * this function only sleeps if the alloc_fn() function sleeps or 371 * returns NULL. Note that due to preallocation, this function 372 * *never* fails when called from process contexts. (it might 373 * fail if called from an IRQ context.) 374 * Note: using __GFP_ZERO is not supported. 375 * 376 * Return: pointer to the allocated element or %NULL on error. 377 */ 378 void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask) 379 { 380 void *element; 381 unsigned long flags; 382 wait_queue_entry_t wait; 383 gfp_t gfp_temp; 384 385 VM_WARN_ON_ONCE(gfp_mask & __GFP_ZERO); 386 might_sleep_if(gfp_mask & __GFP_DIRECT_RECLAIM); 387 388 gfp_mask |= __GFP_NOMEMALLOC; /* don't allocate emergency reserves */ 389 gfp_mask |= __GFP_NORETRY; /* don't loop in __alloc_pages */ 390 gfp_mask |= __GFP_NOWARN; /* failures are OK */ 391 392 gfp_temp = gfp_mask & ~(__GFP_DIRECT_RECLAIM|__GFP_IO); 393 394 repeat_alloc: 395 396 element = pool->alloc(gfp_temp, pool->pool_data); 397 if (likely(element != NULL)) 398 return element; 399 400 spin_lock_irqsave(&pool->lock, flags); 401 if (likely(pool->curr_nr)) { 402 element = remove_element(pool); 403 spin_unlock_irqrestore(&pool->lock, flags); 404 /* paired with rmb in mempool_free(), read comment there */ 405 smp_wmb(); 406 /* 407 * Update the allocation stack trace as this is more useful 408 * for debugging. 409 */ 410 kmemleak_update_trace(element); 411 return element; 412 } 413 414 /* 415 * We use gfp mask w/o direct reclaim or IO for the first round. If 416 * alloc failed with that and @pool was empty, retry immediately. 417 */ 418 if (gfp_temp != gfp_mask) { 419 spin_unlock_irqrestore(&pool->lock, flags); 420 gfp_temp = gfp_mask; 421 goto repeat_alloc; 422 } 423 424 /* We must not sleep if !__GFP_DIRECT_RECLAIM */ 425 if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) { 426 spin_unlock_irqrestore(&pool->lock, flags); 427 return NULL; 428 } 429 430 /* Let's wait for someone else to return an element to @pool */ 431 init_wait(&wait); 432 prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE); 433 434 spin_unlock_irqrestore(&pool->lock, flags); 435 436 /* 437 * FIXME: this should be io_schedule(). The timeout is there as a 438 * workaround for some DM problems in 2.6.18. 439 */ 440 io_schedule_timeout(5*HZ); 441 442 finish_wait(&pool->wait, &wait); 443 goto repeat_alloc; 444 } 445 EXPORT_SYMBOL(mempool_alloc); 这个函数有什么作用,加入程序运行在这个函数中进入了D状态,会是什么原因造成的
09-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值