Linux高端内存管理之非连续内存区(分配和释放)
Linux高端内存管理之非连续内存区(分配和释放)
前面总结了非连续内存区域的内核描述,接着看看他的分配和释放。
相关阅读:
一、非连续内存区的分配
不管是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的设置。
|
评论暂时关闭