[オリジナル](XII)VMAPとvmallocのLinuxのメモリ管理

背景

  • Read the fucking source code! --By魯迅
  • A picture is worth a thousand words. --Byゴーリキー

説明:

  1. カーネルのバージョン:4.14
  2. ARM64プロセッサ、コンテックス-A53、二核
  3. ツールを使用してください:Source Insightは3.5、Visioの

1.概要

前シリーズでは、分析するBuddy Systemページフレーム割り当て、Slub分配器これらのアドレスは連続する物理メモリが割り当てられ、小さいメモリ・オブジェクトの割り当てを。メモリの断片化は、連続した物理メモリの割り当てが困難になった場合は、使用することができますvmapメカニズムがない連続した物理メモリページフレームが連続した仮想アドレス空間にマッピングされます。vmalloc割り当てが達成するために、このメカニズムに基づいています。

右下のこの絵を覚えていますか?

vmap/vmalloc面積はであるVMALLOC_START ~ VMALLOC_END間。

アドベンチャーは、それを開きます。

2.データ構造

2.1 vmap_area / vm_struct

二つのデータ構造が比較的単純で、コードに直接:

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構造体からの仮想アドレスを記述する領域をva_start/va_endも見ることができます。一方、によって構造の経験rb_nodeにより、赤黒木にぶら下がっlistリストにぶら下がっ。フィールドが仮想および物理アドレスのページとの間のマッピングを管理するための構造、あなたができるリンクリストを形成し、多段階のマッピングを維持します。
struct vmap_areavmstruct vm_structstruct vm_struct

下に示すように、関係:

2.2赤黒木

赤黒木は、それは検索、挿入、削除の効率を高めるために二分探索木、赤黒木の基礎に関連するプロパティを着色追加、本質的に二分探索木です。ノードが既にソートされている要素は右ノードされた後赤黒木において、各ノードの要素に対して、ノードの前に残っています。
赤黒木は、次の4つの規則を満たしている必要があります。

  1. 各ノードは赤ではない黒です。
  2. 赤黒ツリーの根は黒でなければなりません。
  3. レッドノードの子ノードが黒でなければなりません。
  4. ノードは、ブラック、ノードの数をカウントしながら、ノードから子ノードへの各パスがヌルポインタと考えることができ、黒のノードの同じ数を含みます。

これは次のように定義されます。

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

直接分析调用流程:

从过程中可以看出,vmallocvmap的操作,大部分的逻辑操作是一样的,比如从VMALLOC_START ~ VMALLOC_END区域之间查找并分配vmap_area, 比如对虚拟地址和物理页框进行映射关系的建立。不同之处,在于vmap建立映射时,page是函数传入进来的,而vmalloc是通过调用alloc_page接口向Buddy System申请分配的。

  • vmalloc VS kmalloc
    到现在,我们应该能清楚vmallockmalloc的差异了吧,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一致,不再赘述了。

おすすめ

転載: www.cnblogs.com/LoyenWang/p/11965787.html