linux非连续内存,(转)linux高端内存管理之非连续内存区(分配和释放)

前面总结了非连续内存区域的内核描述,接着看看他的分配和释放。

一、非连续内存区的分配

不管是vmalloc()还是vmalloc_32()等系列的分配函数最后都会调用__vmalloc_node()函数实现,直接看这个函数的实现。

1.*  __vmalloc_node  -  allocate virtually contiguous memory

2.*  @size:      allocation size

3.*  @align:     desired alignment

4.*  @gfp_mask:  flagsforthe page level allocator

5.*  @prot:      protection maskforthe allocated pages

6.*  @node:      node to useforallocation or -1

7.*  @caller:    caller'sreturnaddress

8.*

9.*  Allocate enough pages to cover @size from the page level

10.*  allocator with @gfp_mask flags.  Map them into contiguous

11.*  kernelvirtualspace,usinga pagetable protection of @prot.

12.*/

13.staticvoid*__vmalloc_node(unsignedlongsize, unsignedlongalign,

14.gfp_t gfp_mask, pgprot_t prot,

15.intnode,void*caller)

16.{

17.structvm_struct *area;

18.void*addr;

19.unsignedlongreal_size = size;

20.

21.size = PAGE_ALIGN(size);

22.if(!size || (size >> PAGE_SHIFT) > totalram_pages)

23.returnNULL;

24./*分配相关的结构并对其初始化,在前面介绍过了*/

25.area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START,

26.VMALLOC_END, node, gfp_mask, caller);

27.

28.if(!area)

29.returnNULL;

30./*分配物理空间,建立页表映射*/

31.addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);

32.

33./*

34.* A ref_count = 3 is needed because the vm_struct and vmap_area

35.* structures allocated in the __get_vm_area_node() function contain

36.* references to the virtual address of the vmalloc'ed block.

37.*/

38./*调试用*/

39.kmemleak_alloc(addr, real_size, 3, gfp_mask);

40.

41.returnaddr;

42.}

static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,

pgprot_t prot, int node, void *caller)

1.structpage **pages;

2.unsignedintnr_pages, array_size, i;

3./*需要减去一个页面,因为在分配结构的时候指定了多一个页面*/

4.nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;

5./*页面指针所占空间大小*/

6.array_size = (nr_pages *sizeof(structpage *));

7.

8.area->nr_pages = nr_pages;

9./* Please note that the recursion is strictly bounded. */

10.if(array_size > PAGE_SIZE) {/*如果页面指针空间大于一个页面时,这个空间用非连续内存分配*/

11.pages = __vmalloc_node(array_size, 1, gfp_mask | __GFP_ZERO,

12.PAGE_KERNEL, node, caller);

13.area->flags |= VM_VPAGES;

14.}else{/*如果页面指针空间所占大小小于一个页面时,用slab机制分配这个空间*/

15.pages = kmalloc_node(array_size,

16.(gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO,

17.node);

18.}

19./*初始化area结构*/

20.area->pages = pages;

21.area->caller = caller;

22.if(!area->pages) {

23.remove_vm_area(area->addr);

24.kfree(area);

25.returnNULL;

26.}

27./*对每个页面调用分配函数分配物理空间,

28.也就是每次分配一个页面*/

29.for(i = 0; i nr_pages; i++) {

30.structpage *page;

31.

32.if(node /*分配物理页面空间*/

33.page = alloc_page(gfp_mask);

34.else

35.page = alloc_pages_node(node, gfp_mask, 0);

36.

37.if(unlikely(!page)) {

38./* Successfully allocated i pages, free them in __vunmap() */

39.area->nr_pages = i;

40.gotofail;

41.}

42.area->pages[i] = page;/*初始化area中page数组*/

43.}

44./*因为非连续区间没有建立页表机制,在这里需要建立他*/

45.if(map_vm_area(area, prot, &pages))

46.gotofail;

47.returnarea->addr;/*返回线性地址*/

48.

49.fail:

50.vfree(area->addr);

51.returnNULL;

52.}

其中map_vm_area()建立页表映射机制的实现就是依次对pgd、pud、pmd、pte的设置。

二、非连续内存区的释放

调用vfree()函数实现

1./**

2.*  vfree  -  release memory allocated by vmalloc()

3.*  @addr:      memory base address

4.*

5.*  Free the virtually continuous memory area starting at @addr, as

6.*  obtained from vmalloc(), vmalloc_32() or __vmalloc(). If @addr is

7.*  NULL, no operation is performed.

8.*

9.*  Must not be called in interrupt context.

10.*/

11.voidvfree(constvoid*addr)

12.{

13.BUG_ON(in_interrupt());

14./*调试用*/

15.kmemleak_free(addr);

16./*释放工作*/

17.__vunmap(addr, 1);

18.}

1.staticvoid__vunmap(constvoid*addr,intdeallocate_pages)

2.{

3.structvm_struct *area;

4.

5.if(!addr)

6.return;

7.

8.if((PAGE_SIZE-1) & (unsignedlong)addr) {

9.WARN(1, KERN_ERR"Trying to vfree() bad address (%p)\n", addr);

10.return;

11.}

12./*从vlist链表和红黑树中移除指定地址的线性区间*/

13.area = remove_vm_area(addr);

14.if(unlikely(!area)) {

15.WARN(1, KERN_ERR"Trying to vfree() nonexistent vm area (%p)\n",

16.addr);

17.return;

18.}

19.

20.debug_check_no_locks_freed(addr, area->size);

21.debug_check_no_obj_freed(addr, area->size);

22.

23.if(deallocate_pages) {

24.inti;

25.

26.for(i = 0; i nr_pages; i++) {/*每次释放一个页面*/

27.structpage *page = area->pages[i];

28.

29.BUG_ON(!page);

30.__free_page(page);

31.}

32.

33.if(area->flags & VM_VPAGES)/*在创建非连续区间时,如果页面

34.指针所占的空间大于一个页面时,从非连续内存区间

35.中分配。所以这里也就从相应的释放*/

36.vfree(area->pages);

37.else

38.kfree(area->pages);/*从slab中释放*/

39.}

40.

41.kfree(area);/*释放area*/

42.return;

43.}

1./**

2.*  remove_vm_area  -  find and remove a continuous kernel virtual area

3.*  @addr:      base address

4.*

5.*  Search for the kernel VM area starting at @addr, and remove it.

6.*  This function returns the found VM area, but using it is NOT safe

7.*  on SMP machines, except for its size or flags.

8.*/

9.structvm_struct *remove_vm_area(constvoid*addr)

10.{

11.structvmap_area *va;

12./*从红黑树种查找而不是链表,为了效率起见*/

13.va = find_vmap_area((unsignedlong)addr);

14.if(va && va->flags & VM_VM_AREA) {

15.structvm_struct *vm = va->private;

16.structvm_struct *tmp, **p;

17./*

18.* remove from list and disallow access to this vm_struct

19.* before unmap. (address range confliction is maintained by

20.* vmap.)

21.*/

22.write_lock(&vmlist_lock);

23./*从链表中找到,然后删除*/

24.for(p = &vmlist; (tmp = *p) != vm; p = &tmp->next)

25.;

26.*p = tmp->next;

27.write_unlock(&vmlist_lock);

28./*调试用*/

29.vmap_debug_free_range(va->va_start, va->va_end);

30./*从红黑树中删除*/

31.free_unmap_vmap_area(va);

32.vm->size -= PAGE_SIZE;

33.

34.returnvm;

35.}

36.returnNULL;

37.}

总结:linux高端内存非连续区的整体描述以及其分配和释放基本就总结完了。总结的只是一个大概的原理框架,不过根据这个框架对细节的了解应该不难。另外,其中涉及到伙伴系统、slab机制等部分需要再做分析和总结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值