[内核内存] linux内核态中常见的内存分配函数

1 alloc_pages

alloc_pages用于申请一块2^order的连续物理内存块,适用于分配较大量的连续物理内存.详情参考以前的文章:arm64 Linux内核内存伙伴系统4—alloc_pages(内存块分配)

2 vmalloc

vmalloc是一个接口函数, 内核代码使用它来分配在虚拟内存中连续但在物理内存中不一定连续的内存。比如在模块加载时,由于内核模块数据一般比较多,linux系统中往往无法为其提供如此大块的连续内存块,就可以用vmalloc函数为其分配物理地址不连续的内存块。

函数调用

__vmalloc_node_range----------------vmalloc的核心函数
    __get_vm_area_node--------------找到符合大小的空闲vmalloc区域
        alloc_vmap_area-------------从vmap_area_root中找到合适的hole,填充vmap_area结构体,并插入到vmap_area_root红黑树中
        setup_vmalloc_vm------------将vmap_area的参数填入vm_struct
    __vmalloc_area_node-------------计算需要的页面数,分配页面,并创建页表映射关系
        alloc_page------------------分配页面
        map_vm_area-----------------建立PGD/PTE页表映射关系

/**
 *	vmalloc  -  allocate virtually contiguous memory
 *	@size:		allocation size
 *	Allocate enough pages to cover @size from the page level
 *	allocator and map them into contiguous kernel virtual space.
 *
 *	For tight control over page level allocator and protection flags
 *	use __vmalloc() instead.
 */
void *vmalloc(unsigned long size)
{
	return __vmalloc_node_flags(size, NUMA_NO_NODE,
				    GFP_KERNEL | __GFP_HIGHMEM);
}
EXPORT_SYMBOL(vmalloc);

static inline void *__vmalloc_node_flags(unsigned long size,
					int node, gfp_t flags)
{
	return __vmalloc_node(size, 1, flags, PAGE_KERNEL,
					node, __builtin_return_address(0));
}

/**
 *	__vmalloc_node  -  allocate virtually contiguous memory
 *	@size:		allocation size
 *	@align:		desired alignment
 *	@gfp_mask:	flags for the page level allocator
 *	@prot:		protection mask for the allocated pages
 *	@node:		node to use for allocation or NUMA_NO_NODE
 *	@caller:	caller's return address
 *
 *	Allocate enough pages to cover @size from the page level
 *	allocator with @gfp_mask flags.  Map them into contiguous
 *	kernel virtual space, using a pagetable protection of @prot.
 */
static void *__vmalloc_node(unsigned long size, unsigned long align,
			    gfp_t gfp_mask, pgprot_t prot,
			    int node, const void *caller)
{
	return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
				gfp_mask, prot, 0, node, caller);
}

/**
 *	__vmalloc_node_range  -  allocate virtually contiguous memory
 *	@size:		allocation size
 *	@align:		desired alignment
 *	@start:		vm area range start
 *	@end:		vm area range end
 *	@gfp_mask:	flags for the page level allocator
 *	@prot:		protection mask for the allocated pages
 *	@vm_flags:	additional vm area flags (e.g. %VM_NO_GUARD)
 *	@node:		node to use for allocation or NUMA_NO_NODE
 *	@caller:	caller's return address
 *
 *	Allocate enough pages to cover @size from the page level
 *	allocator with @gfp_mask flags.  Map them into contiguous
 *	kernel virtual space, using a pagetable protection of @prot.
 */
void *__vmalloc_node_range(unsigned long size, unsigned long align,
			unsigned long start, unsigned long end, gfp_t gfp_mask,
			pgprot_t prot, unsigned long vm_flags, int node,
			const void *caller)
{
	struct vm_struct *area;
	void *addr;
	unsigned long real_size = size;

	size = PAGE_ALIGN(size);
	if (!size || (size >> PAGE_SHIFT) > totalram_pages)
		goto fail;

	area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNINITIALIZED |
				vm_flags, start, end, node, gfp_mask, caller);
	if (!area)
		goto fail;

	addr = __vmalloc_area_node(area, gfp_mask, prot, node);
	if (!addr)
		return NULL;

	/*
	 * In this function, newly allocated vm_struct has VM_UNINITIALIZED
	 * flag. It means that vm_struct is not fully initialized.
	 * Now, it is fully initialized, so remove this flag here.
	 */
	clear_vm_uninitialized_flag(area);

	/*
	 * A ref_count = 2 is needed because vm_struct allocated in
	 * __get_vm_area_node() contains a reference to the virtual address of
	 * the vmalloc'ed block.
	 */
	kmemleak_alloc(addr, real_size, 2, gfp_mask);

	return addr;

fail:
	warn_alloc(gfp_mask,
			  "vmalloc: allocation failure: %lu bytes", real_size);
	return NULL;
}

vmalloc使用详情可参考:https://www.cnblogs.com/arnoldlu/p/8251333.html

3 kmem_cache_alloc

kmem_cache_alloc函数是linux内核基于slab机制实现的内存分配函数,该函数利用创建的slab cache描述符给对应结构体分配内存空间.

kmem_cache_alloc函数的实现详情可参考以前的文章:arm64 linux内核内存slab分配器2—slab系统初始化中的第3小节(slab系统中特殊结构体内存分配)

4 kmalloc

kmalloc内核内存分配函数是基于kmem_cache_alloc实现的,kmalloc函数是slab系统中传统意义上的内存分配函数,通过传入要申请内存空间的大小Size,就可以返回一个按字节对齐的内存空间给调用者使用,不会涉及到slab cache描述符的创建等操作。这有点类似于用户空间的malloc函数。例如向slab系统分配一个大小为15字节的内存空间,则可以用kmalloc(15,GFP_KERNEL)来实现,它会返回一个16字节大小的内存空间(slab obj)给调用者。

kmalloc函数实现详情可参考以前的文章::arm64 linux内核内存slab分配器2—slab系统初始化中的第4小节(slab系统通用内存分配)

5 dma_alloc_coherent

dma_alloc_coherent该函数用于DMA操作,基于伙伴系统的__alloc_pages函数实现。该函数接触较少后续有机会会做详细的分析。

6 ioremap

ioremap函数是在内存空间物理地址和大小已知的情况下,将已知物理地址空间段映射到内核的虚拟地址空间中去,最后返回虚拟地址空间首地址。该内存分配函数多用于设备驱动中的内存分配,可以让CPU直接访问外部设备的IO空间.

void * ioremap (unsigned long offset,unsigned long size):
PARAM:
	1. offset:指定物理内存空间的起始物理地址.
	2. size  :指定物理内存空间段的内存大小.
RETURN:
	指定物理内存空间映射的虚拟地址空间的首地址.

ioremap函数页接触较少,后续有机会会进行详细分析.

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值