linux内存管理之vmalloc

来源:互联网 发布:分形设计软件 编辑:程序博客网 时间:2024/06/08 04:55

vmalloc的两个数据结构也就是vm_struct和pages依赖于slab系统,pages指向的page依赖于buddy系统,另外修改页表重新映射依赖于maping

vmalloc    =>__vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);//丫的竟然用高端内存????,是的,在最高的128M        =>__vmalloc_node(size, gfp_mask, prot, -1);            =>size = PAGE_ALIGN(size); //size大小页对齐            =>area = get_vm_area_node(size, VM_ALLOC, node, gfp_mask);//struct vm_struct *area;                =>return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node, gfp_mask);//VMALLOC_START和VMALLOC_END分别是vmalloc的起始和终止区域                    =>area = kmalloc_node(sizeof(*area), gfp_mask & GFP_LEVEL_MASK, node);//vm_struct依赖于kmalloc,也就是slab系统                        =>return kmalloc(size, flags);                            =>return kmem_cache_alloc(malloc_sizes[i].cs_cachep, flags);//进入slab领域                    =>size += PAGE_SIZE; //We always allocate a guard page. 申请的时候加个栅栏                    =>for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next) { //在vmlist链表里面找到area合适的位置,把新分配的area插入到里面                        if ((unsigned long)tmp->addr < addr) {                            if((unsigned long)tmp->addr + tmp->size >= addr)                                addr = ALIGN(tmp->size +                                          (unsigned long)tmp->addr, align);                            continue;                        }                        if ((size + addr) < addr)                            goto out;                        if (size + addr <= (unsigned long)tmp->addr)                            goto found;                        addr = ALIGN(tmp->size + (unsigned long)tmp->addr, align);                        if (addr > end - size)                            goto out;                    }                    =>                  found: //一旦找到合适的地方就初始化                    area->next = *p;  //这两句话是将area加入到vm_struct链表中                    *p = area;                    area->flags = flags;                    area->addr = (void *)addr;//addr作为内容,area作为载体                    area->size = size;                    area->pages = NULL;                    area->nr_pages = 0;                    area->phys_addr = 0;            =>return __vmalloc_area_node(area, gfp_mask, prot, node);                =>nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT; //真正申请的时候取消栅栏,递归的时候也做递减的作用                array_size = (nr_pages * sizeof(struct page *));                area->nr_pages = nr_pages;                =>if (array_size > PAGE_SIZE) {//为pages分配空间,如果pages正常占用的字节有限,但是如果超过一个页框大小,也就是4KB,需要递归调用,关于pages的详细描述详见“参考”里面的第一章节最后一张图片,很形象                    pages = __vmalloc_node(array_size, gfp_mask | __GFP_ZERO,                                PAGE_KERNEL, node);//页面大小超过1个页                    area->flags |= VM_VPAGES;                } else {//                    pages = kmalloc_node(array_size,                            (gfp_mask & GFP_LEVEL_MASK) | __GFP_ZERO,                            node);//页面大小没有超过1个页,递归递减1个页框,最终会调用的这个地方                }                area->pages = pages;                =>for (i = 0; i < area->nr_pages; i++) { ////好多页面物理不连续,但是虚拟地址连续                    if (node < 0)                        area->pages[i] = alloc_page(gfp_mask);                    else                        area->pages[i] = alloc_pages_node(node, gfp_mask, 0);                    if (unlikely(!area->pages[i])) {                        /* Successfully allocated i pages, free them in __vunmap() */                        area->nr_pages = i;                        goto fail;                    }                }                =>if (map_vm_area(area, prot, &pages))//页表映射修改                =>return area->addr;

参考
高端内存映射之vmalloc分配内存中不连续的页–Linux内存管理(十九)
http://blog.csdn.net/gatieme/article/details/52705111