歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux高端內存管理之非連續內存區(分配和釋放)

Linux高端內存管理之非連續內存區(分配和釋放)

日期:2017/2/28 15:57:28   编辑:Linux教程

前面總結了非連續內存區域的內核描述,接著看看他的分配和釋放。

相關閱讀:

http://www.linuxidc.com/Linux/2012-02/53457.htm

http://www.linuxidc.com/Linux/2012-02/53458.htm

http://www.linuxidc.com/Linux/2012-02/53459.htm

http://www.linuxidc.com/Linux/2012-02/53460.htm

一、非連續內存區的分配

不管是vmalloc()還是vmalloc_32()等系列的分配函數最後都會調用__vmalloc_node()函數實現,直接看這個函數的實現。

[cpp] view plaincopyprint?

  1. * __vmalloc_node - allocate virtually contiguous memory
  2. * @size: allocation size
  3. * @align: desired alignment
  4. * @gfp_mask: flags for the page level allocator
  5. * @prot: protection mask for the allocated pages
  6. * @node: node to use for allocation or -1
  7. * @caller: caller's return address
  8. *
  9. * Allocate enough pages to cover @size from the page level
  10. * allocator with @gfp_mask flags. Map them into contiguous
  11. * kernel virtual space, using a pagetable protection of @prot.
  12. */
  13. static void *__vmalloc_node(unsigned long size, unsigned long align,
  14. gfp_t gfp_mask, pgprot_t prot,
  15. int node, void *caller)
  16. {
  17. struct vm_struct *area;
  18. void *addr;
  19. unsigned long real_size = size;
  20. size = PAGE_ALIGN(size);
  21. if (!size || (size >> PAGE_SHIFT) > totalram_pages)
  22. return NULL;
  23. /*分配相關的結構並對其初始化,在前面介紹過了*/
  24. area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START,
  25. VMALLOC_END, node, gfp_mask, caller);
  26. if (!area)
  27. return NULL;
  28. /*分配物理空間,建立頁表映射*/
  29. addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);
  30. /*
  31. * A ref_count = 3 is needed because the vm_struct and vmap_area
  32. * structures allocated in the __get_vm_area_node() function contain
  33. * references to the virtual address of the vmalloc'ed block.
  34. */
  35. /*調試用*/
  36. kmemleak_alloc(addr, real_size, 3, gfp_mask);
  37. return addr;
  38. }
[cpp] view plaincopyprint?
  1. struct page **pages;
  2. unsigned int nr_pages, array_size, i;
  3. /*需要減去一個頁面,因為在分配結構的時候指定了多一個頁面*/
  4. nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
  5. /*頁面指針所占空間大小*/
  6. array_size = (nr_pages * sizeof(struct page *));
  7. area->nr_pages = nr_pages;
  8. /* Please note that the recursion is strictly bounded. */
  9. if (array_size > PAGE_SIZE) {/*如果頁面指針空間大於一個頁面時,這個空間用非連續內存分配*/
  10. pages = __vmalloc_node(array_size, 1, gfp_mask | __GFP_ZERO,
  11. PAGE_KERNEL, node, caller);
  12. area->flags |= VM_VPAGES;
  13. } else {/*如果頁面指針空間所占大小��於一個頁面時,用slab機制分配這個空間*/
  14. pages = kmalloc_node(array_size,
  15. (gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO,
  16. node);
  17. }
  18. /*初始化area結構*/
  19. area->pages = pages;
  20. area->caller = caller;
  21. if (!area->pages) {
  22. remove_vm_area(area->addr);
  23. kfree(area);
  24. return NULL;
  25. }
  26. /*對每個頁面調用分配函數分配物理空間,
  27. 也就是每次分配一個頁面*/
  28. for (i = 0; i < area->nr_pages; i++) {
  29. struct page *page;
  30. if (node < 0)/*分配物理頁面空間*/
  31. page = alloc_page(gfp_mask);
  32. else
  33. page = alloc_pages_node(node, gfp_mask, 0);
  34. if (unlikely(!page)) {
  35. /* Successfully allocated i pages, free them in __vunmap() */
  36. area->nr_pages = i;
  37. goto fail;
  38. }
  39. area->pages[i] = page;/*初始化area中page數組*/
  40. }
  41. /*因為非連續區間沒有建立頁表機制,在這裡需要建立他*/
  42. if (map_vm_area(area, prot, &pages))
  43. goto fail;
  44. return area->addr;/*返回線性地址*/
  45. fail:
  46. vfree(area->addr);
  47. return NULL;
  48. }

其中map_vm_area()建立頁表映射機制的實現就是依次對pgd、pud、pmd、pte的設置。

Copyright © Linux教程網 All Rights Reserved