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    *  @size:      allocation size  
  2.  *  @align:     desired alignment    *  @gfp_mask:  flags for the page level allocator  
  3.  *  @prot:      protection mask for the allocated pages    *  @node:      node to use for allocation or -1  
  4.  *  @caller:    caller's return address    *  
  5.  *  Allocate enough pages to cover @size from the page level    *  allocator with @gfp_mask flags.  Map them into contiguous  
  6.  *  kernel virtual space, using a pagetable protection of @prot.    */  
  7. static void *__vmalloc_node(unsigned long size, unsigned long align,                   gfp_t gfp_mask, pgprot_t prot,  
  8.                 int node, void *caller)   {  
  9.     struct vm_struct *area;       void *addr;  
  10.     unsigned long real_size = size;     
  11.     size = PAGE_ALIGN(size);       if (!size || (size >> PAGE_SHIFT) > totalram_pages)  
  12.         return NULL;       /*分配相关的结构并对其初始化,在前面介绍过了*/  
  13.     area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START,                     VMALLOC_END, node, gfp_mask, caller);  
  14.        if (!area)  
  15.         return NULL;       /*分配物理空间,建立页表映射*/  
  16.     addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);     
  17.     /*       * A ref_count = 3 is needed because the vm_struct and vmap_area 
  18.      * structures allocated in the __get_vm_area_node() function contain       * references to the virtual address of the vmalloc'ed block. 
  19.      */        /*调试用*/  
  20.     kmemleak_alloc(addr, real_size, 3, gfp_mask);     
  21.     return addr;   }  
[cpp] view plaincopyprint?
  1.     struct page **pages;       unsigned int nr_pages, array_size, i;  
  2.     /*需要减去一个页面,因为在分配结构的时候指定了多一个页面*/       nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;  
  3.     /*页面指针所占空间大小*/       array_size = (nr_pages * sizeof(struct page *));  
  4.        area->nr_pages = nr_pages;  
  5.     /* Please note that the recursion is strictly bounded. */       if (array_size > PAGE_SIZE) {/*如果页面指针空间大于一个页面时,这个空间用非连续内存分配*/   
  6.         pages = __vmalloc_node(array_size, 1, gfp_mask | __GFP_ZERO,                   PAGE_KERNEL, node, caller);  
  7.         area->flags |= VM_VPAGES;       } else {/*如果页面指针空间所占大小小于一个页面时,用slab机制分配这个空间*/  
  8.         pages = kmalloc_node(array_size,                   (gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO,  
  9.                 node);       }  
  10.     /*初始化area结构*/       area->pages = pages;  
  11.     area->caller = caller;       if (!area->pages) {  
  12.         remove_vm_area(area->addr);           kfree(area);  
  13.         return NULL;       }  
  14.     /*对每个页面调用分配函数分配物理空间,      也就是每次分配一个页面*/  
  15.     for (i = 0; i < area->nr_pages; i++) {           struct page *page;  
  16.            if (node < 0)/*分配物理页面空间*/  
  17.             page = alloc_page(gfp_mask);           else  
  18.             page = alloc_pages_node(node, gfp_mask, 0);     
  19.         if (unlikely(!page)) {               /* Successfully allocated i pages, free them in __vunmap() */  
  20.             area->nr_pages = i;               goto fail;  
  21.         }           area->pages[i] = page;/*初始化area中page数组*/  
  22.     }       /*因为非连续区间没有建立页表机制,在这里需要建立他*/  
  23.     if (map_vm_area(area, prot, &pages))           goto fail;  
  24.     return area->addr;/*返回线性地址*/     
  25. fail:       vfree(area->addr);  
  26.     return NULL;   }  

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

此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/57895.html