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


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

相关阅读:

一、非连续内存区的分配

不管是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()建立页表映射机制的实现就是依次对pgdpudpmdpte的设置。

  • 1
  • 2
  • 下一页

相关内容