歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

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.   
  21.     size = PAGE_ALIGN(size);  
  22.     if (!size || (size >> PAGE_SHIFT) > totalram_pages)  
  23.         return NULL;  
  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.         return NULL;  
  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.     return addr;  
  42. }  
[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.   
  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.         return NULL;  
  26.     }  
  27.     /*對每個頁面調用分配函數分配物理空間, 
  28.     也就是每次分配一個頁面*/  
  29.     for (i = 0; i < area->nr_pages; i++) {  
  30.         struct page *page;  
  31.   
  32.         if (node < 0)/*分配物理頁面空間*/  
  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.             goto fail;  
  41.         }  
  42.         area->pages[i] = page;/*初始化area中page數組*/  
  43.     }  
  44.     /*因為非連續區間沒有建立頁表機制,在這裡需要建立他*/  
  45.     if (map_vm_area(area, prot, &pages))  
  46.         goto fail;  
  47.     return area->addr;/*返回線性地址*/  
  48.   
  49. fail:  
  50.     vfree(area->addr);  
  51.     return NULL;  
  52. }  

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

Copyright © Linux教程網 All Rights Reserved