非连续内存区管理

伙伴算法系统、slab分配器都是要求物理页框连续。buddy 分配器并不能完全消除页外碎片问题,为了应付可能的情况(指总空闲空间大于请求 大小,但空闲空间却不连续,这种情况 buddy 分配器没有办法处理),Linux 提供了一种机 制,称 vmalloc 分配器。它允许将不连续的物理空间映射到连续的虚地址空间。这个虚地址空间的描述符:
struct vm_struct {
unsigned long flags;
void * addr;
unsigned long size;
struct vm_struct * next;
};
flags 标志
addr 起始虚地址
size 大小
next 下一个虚地址空间

vmalloc
    return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
        size = PAGE_ALIGN(size);
        area = get_vm_area(size, VM_ALLOC);
			return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);
				addr = ALIGN(start, align);//往上对齐
				area = kmalloc(sizeof(*area), GFP_KERNEL);
				size += PAGE_SIZE;
				for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next)
					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 <= (unsigned long)tmp->addr)
Goto found;
addr = ALIGN(tmp->size + (unsigned long)tmp->addr, align);
if (addr > end - size)
Goto out; //没有找到空闲的线性地址
Found:
找到空闲的线性地址,并将该部分线性地址插入到vmlist中
area->next = *p;
*p = area;
area->flags = flags;
area->addr = (void *)addr;
area->size = size;
return area;

        nr_pages = size >> PAGE_SHIFT;
        array_size = (nr_pages * sizeof(struct page *));
        
        area->nr_pages = nr_pages;
        if (array_size > PAGE_SIZE)
            pages = __vmalloc(array_size, gfp_mask, PAGE_KERNEL);
        else
			//不从高端内存区分配存储页描述符的物理页框
            pages = kmalloc(array_size, (gfp_mask & ~__GFP_HIGHMEM));
        area->pages = pages;
        memset(area->pages, 0, array_size);
        
		//优先从高端内存区分配物理页框
        for (i = 0; i < area->nr_pages; i++)
            area->pages[i] = alloc_page(gfp_mask);
            
        map_vm_area(area, prot, &pages)
			//开始的线性地址
            unsigned long address = (unsigned long) area->addr;
            unsigned long end = address + (area->size-PAGE_SIZE);
			//使用pgd_offset_k来获得主内核页全局目录中的目录项。
            pgd = pgd_offset_k(address);    
                pgd_offset(&init_mm, address)
                    ((mm)->pgd+pgd_index(address))
                        (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
			//建立虚拟地址到物理地址的页目录和页表
            for (i = pgd_index(address); i <= pgd_index(end-1); i++)
                pud_t *pud = pud_alloc(&init_mm, pgd, address);    
                next = (address + PGDIR_SIZE) & PGDIR_MASK;        
                map_area_pud(pud, address, next, prot, pages)
                    do {
                        pmd_t *pmd = pmd_alloc(&init_mm, pud, address);
                        map_area_pmd(pmd, address, end - address, prot, pages)
                            do
                                pte_t * pte = pte_alloc_kernel(&init_mm, pmd, base + address);
                                map_area_pte(pte, address, end - address, prot, pages)
                                    do
                                        struct page *page = **pages;
                                        set_pte(pte, mk_pte(page, prot));
                                        address += PAGE_SIZE;
                                        pte++;
                                        (*pages)++;       
                                    while (address < end);
                                address = (address + PMD_SIZE) & PMD_MASK;
                                pmd++;
                        address = (address + PUD_SIZE) & PUD_MASK;
                        pud++;
                    } while (address && address < end);                        
                address = next;
                pgd++;       

从上面可以看到vmalloc步骤
(1)从vmlist中找到一个满足大小要求的连续虚拟地址空间
(2)如果所需页描述符总大小大于页大小(4KB)就递归调用vmalloc申请页描述符的空间,否则调用kmalloc申请页描述符的空间
(3)调用alloc_page优先从高端内存区申请页框,alloc_page返回页框的页描述符地址
(4)调用map_vm_area建立从线性地址到物理页框地址的页目录、页表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值