前面总结了非连续内存区域的内核描述,接着看看他的分配和释放。
相关阅读:
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?
- * __vmalloc_node - allocate virtually contiguous memory * @size: allocation size
- * @align: desired alignment * @gfp_mask: flags for the page level allocator
- * @prot: protection mask for the allocated pages * @node: node to use for allocation or -1
- * @caller: caller's return address *
- * Allocate enough pages to cover @size from the page level * allocator with @gfp_mask flags. Map them into contiguous
- * kernel virtual space, using a pagetable protection of @prot. */
- static void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask, pgprot_t prot,
- int node, void *caller) {
- struct vm_struct *area; void *addr;
- unsigned long real_size = size;
- size = PAGE_ALIGN(size); if (!size || (size >> PAGE_SHIFT) > totalram_pages)
- return NULL; /*分配相关的结构并对其初始化,在前面介绍过了*/
- area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START, VMALLOC_END, node, gfp_mask, caller);
- if (!area)
- return NULL; /*分配物理空间,建立页表映射*/
- addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);
- /* * A ref_count = 3 is needed because the vm_struct and vmap_area
- * structures allocated in the __get_vm_area_node() function contain * references to the virtual address of the vmalloc'ed block.
- */ /*调试用*/
- kmemleak_alloc(addr, real_size, 3, gfp_mask);
- return addr; }
- struct page **pages; unsigned int nr_pages, array_size, i;
- /*需要减去一个页面,因为在分配结构的时候指定了多一个页面*/ nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
- /*页面指针所占空间大小*/ array_size = (nr_pages * sizeof(struct page *));
- area->nr_pages = nr_pages;
- /* Please note that the recursion is strictly bounded. */ if (array_size > PAGE_SIZE) {/*如果页面指针空间大于一个页面时,这个空间用非连续内存分配*/
- pages = __vmalloc_node(array_size, 1, gfp_mask | __GFP_ZERO, PAGE_KERNEL, node, caller);
- area->flags |= VM_VPAGES; } else {/*如果页面指针空间所占大小小于一个页面时,用slab机制分配这个空间*/
- pages = kmalloc_node(array_size, (gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO,
- node); }
- /*初始化area结构*/ area->pages = pages;
- area->caller = caller; if (!area->pages) {
- remove_vm_area(area->addr); kfree(area);
- return NULL; }
- /*对每个页面调用分配函数分配物理空间, 也就是每次分配一个页面*/
- for (i = 0; i < area->nr_pages; i++) { struct page *page;
- if (node < 0)/*分配物理页面空间*/
- page = alloc_page(gfp_mask); else
- page = alloc_pages_node(node, gfp_mask, 0);
- if (unlikely(!page)) { /* Successfully allocated i pages, free them in __vunmap() */
- area->nr_pages = i; goto fail;
- } area->pages[i] = page;/*初始化area中page数组*/
- } /*因为非连续区间没有建立页表机制,在这里需要建立他*/
- if (map_vm_area(area, prot, &pages)) goto fail;
- return area->addr;/*返回线性地址*/
- fail: vfree(area->addr);
- return NULL; }
其中map_vm_area()建立页表映射机制的实现就是依次对pgd、pud、pmd、pte的设置。
此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/57895.html