background
Read the fucking source code!
--By Lu XunA picture is worth a thousand words.
--By Gorky
Description:
- Kernel Version: 4.14
- ARM64 processor, Contex-A53, binuclear
- Use tools: Source Insight 3.5, Visio
1 Overview
In the previous series, to analyze the Buddy System
page frame allocation, Slub分配器
the small memory object allocation, these addresses are assigned contiguous physical memory. When the memory fragmentation, contiguous physical memory allocation becomes difficult, you can use the vmap
mechanism will not contiguous physical memory page frames mapped into contiguous virtual address space. vmalloc
The allocation is based on this mechanism to achieve.
Remember this picture below right?
vmap/vmalloc
The area is in VMALLOC_START ~ VMALLOC_END
between.
Adventure open it.
2. Data Structure
2.1 vmap_area/vm_struct
The two data structure is relatively simple, direct on the code:
struct vm_struct {
struct vm_struct *next;
void *addr;
unsigned long size;
unsigned long flags;
struct page **pages;
unsigned int nr_pages;
phys_addr_t phys_addr;
const void *caller;
};
struct vmap_area {
unsigned long va_start;
unsigned long va_end;
unsigned long flags;
struct rb_node rb_node; /* address sorted rbtree */
struct list_head list; /* address sorted list */
struct llist_node purge_list; /* "lazy purge" list */
struct vm_struct *vm;
struct rcu_head rcu_head;
};
struct vmap_area
A region that describes a virtual address from the structural body va_start/va_end
can also be seen. Meanwhile, the structure experience by rb_node
hanging on a red-black tree, by list
hanging on the list.
struct vmap_area
The vm
field is a struct vm_struct
structure for managing the mapping between the virtual and physical address page, you can struct vm_struct
form a linked list, maintain multi-stage mapping.
Relationship as shown below:
2.2 red-black tree
Red-black tree, is essentially a binary search tree, it adds coloring properties related to the basis of the binary search tree, red-black trees to enhance the search, insert, delete efficiency. In the red-black tree, the node is already sorted, for the elements of each node are left before the node, after the elements are right node.
Red-black tree must satisfy the following four rules:
- Each node is not red is black;
- Red-black tree roots must be black;
- Red node child node must be black;
- Each path from the node to the child nodes contain the same number of black nodes, while the node count the number of black, black nodes can be considered a null pointer;
It is defined as follows:
struct rb_node {
unsigned long __rb_parent_color;
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
/* The alignment might seem pointless, but allegedly CRIS needs it */
由于内核会频繁的进行vmap_area
的查找,红黑树的引入就是为了解决当查找数量非常多时效率低下的问题,在红黑树中,搜索元素,插入,删除等操作,都会变得非常高效。至于红黑树的算法操作,本文就不再深入分析,知道它的用途即可。
3. vmap/vunmap分析
3.1 vmap
vmap
函数,完成的工作是,在vmalloc
虚拟地址空间中找到一个空闲区域,然后将page页面数组
对应的物理内存映射到该区域,最终返回映射的虚拟起始地址。
整体流程如下:
操作流程比较简单,来一个样例分析,就清晰明了了:
vmap
调用中,关键函数为alloc_vmap_area
,它先通过vmap_area_root
二叉树来查找第一个区域first vm_area
,然后根据这个first vm_area
去查找vmap_area_list
链表中满足大小的空间区域。
在alloc_vmap_area
函数中,有几个全局的变量:
static struct rb_node *free_vmap_cache;
static unsigned long cached_hole_size;
static unsigned long cached_vstart;
static unsigned long cached_align;
用于缓存上一次分配成功的vmap_area
,其中cached_hole_size
用于记录缓存vmap_area
对应区域之前的空洞的大小。缓存机制当然也是为了提高分配的效率。
3.2 vunmap
vunmap
执行的是跟vmap
相反的过程:从vmap_area_root/vmap_area_list
中查找vmap_area
区域,取消页表映射,再从vmap_area_root/vmap_area_list
中删除掉vmap_area
,页面返还给伙伴系统等。由于映射关系有改动,因此还需要进行TLB的刷新,频繁的TLB刷新会降低性能,因此将其延迟进行处理,因此称为lazy tlb
。
来看看逆过程的流程:
4. vmalloc/vfree分析
4.1 vmalloc
vmalloc
用于分配一个大的连续虚拟地址空间,该空间在物理上不连续的,因此也就不能用作DMA缓冲区。vmalloc
分配的线性地址区域,在文章开头的图片中也描述了:VMALLOC_START ~ VMALLOC_END
。
直接分析调用流程:
从过程中可以看出,vmalloc
和vmap
的操作,大部分的逻辑操作是一样的,比如从VMALLOC_START ~ VMALLOC_END
区域之间查找并分配vmap_area
, 比如对虚拟地址和物理页框进行映射关系的建立。不同之处,在于vmap
建立映射时,page
是函数传入进来的,而vmalloc
是通过调用alloc_page
接口向Buddy System申请分配的。
vmalloc VS kmalloc
到现在,我们应该能清楚vmalloc
和kmalloc
的差异了吧,kmalloc
会根据申请的大小来选择基于slub分配器
或者基于Buddy System
来申请连续的物理内存。而vmalloc
则是通过alloc_page
申请order = 0
的页面,再映射到连续的虚拟空间中,物理地址不连续,此外vmalloc
可以休眠,不应在中断处理程序中使用。
与vmalloc
相比,kmalloc
使用ZONE_DMA和ZONE_NORMAL
空间,性能更快,缺点是连续物理内存空间的分配容易带来碎片问题,让碎片的管理变得困难。
4.2 vfree
直接上代码:
void vfree(const void *addr)
{
BUG_ON(in_nmi());
kmemleak_free(addr);
if (!addr)
return;
if (unlikely(in_interrupt()))
__vfree_deferred(addr);
else
__vunmap(addr, 1);
}
如果在中断上下文中,则推迟释放,否则直接调用__vunmap
,所以它的逻辑基本和vunmap
一致,不再赘述了。