vmalloc

函数调用流程

vmalloc()
    __vmalloc_node()
        __vmalloc_node_range()
            __get_vm_area_node()
            __vmalloc_area_node()
                kmalloc_node()
                vmap_pages_range()

vmalloc() 从 vmalloc 区域申请虚拟内存,并且从 buddy 分配器申请物理内存后,然后 调用 vmap_pages_range() 将物理内存映射到虚拟内存中,此虚拟内存空间不会出现 Page Fault

(x86_64) 如果进程 A 陷入内核空间,通过 vmalloc() 分配内存 memA,如上解释不会出现 Page Fault。 但是进程 B 后面再陷入内核空间,并且也访问内存 memA,这时候内核会发生 Page Fault 来同步内核页表, 而不是发生 Page Fault 来申请物理内存。

零散知识点

  • 为什么 vmalloc() 申请的虚拟内存大小 总是比 申请的物理内存小?

/proc/vmallocinfo 的 第二列 与 倒数第二列,如下:

# cat /proc/vmallocinfo
0x00000000d4d806e4-0x00000000e109dff2   20480 start_kernel+0x478/0x690 pages=4 vmalloc N0=4
0x00000000e109dff2-0x00000000caa5ddd3    8192 gicv2m_init_one+0xa8/0x224 phys=0x0000000008020000 ioremap
0x00000000fa4bd407-0x00000000777a02db   20480 kernel_clone+0x5c/0x3b8 pages=4 vmalloc N0=4
0x00000000777a02db-0x00000000802411ee    8192 bpf_prog_alloc_no_stats+0x3c/0x1b8 pages=1 vmalloc N0=1
0x00000000916f1123-0x000000007c459509 16187392 paging_init+0x130/0x60c phys=0x0000000040210000 vmap

因为由 vmalloc() 申请的虚拟内存默认会添加一页 Guard 页,如下:

mm/vmalloc.c

include/linux/vmalloc.h

static struct vm_struct *__get_vm_area_node(unsigned long size,
		unsigned long align, unsigned long shift, unsigned long flags,
		unsigned long start, unsigned long end, int node,
		gfp_t gfp_mask, const void *caller)
{
	...
	if (!(flags & VM_NO_GUARD))
		size += PAGE_SIZE;
	...
}

static inline size_t get_vm_area_size(const struct vm_struct *area)
{
	if (!(area->flags & VM_NO_GUARD))
		/* return actual size without guard page */
		return area->size - PAGE_SIZE;
	else
		return area->size;

}

Last updated

Was this helpful?