//运行到这里的时候,已经断开了一个页目录所表示的线性地址,而每个页目录表示的线性地址//大小为PGDIR_SIZE

address = (address + PGDIR_SIZE) & PGDIR_MASK;

dir++;

} while (address && (address < end));

//当到达末尾时结束循环

flush_tlb_kernel_range((unsigned long) area->addr, end);

}

//断开线性地址区间所在的pmd的映射

static void unmap_area_pmd(pgd_t *dir, unsigned long address,

unsigned long size)

{

unsigned long end;

pmd_t *pmd;

if (pgd_none(*dir))

return;

if (pgd_bad(*dir)) {

pgd_ERROR(*dir);

pgd_clear(dir);

return;

}

pmd = pmd_offset(dir, address);

address &= ~PGDIR_MASK;

end = address + size;

if (end > PGDIR_SIZE)

end = PGDIR_SIZE;

do {

//断开线性地址所在的pte的映射关系

unmap_area_pte(pmd, address, end - address);

address = (address + PMD_SIZE) & PMD_MASK;

pmd++;

} while (address < end);

}

static void unmap_area_pte(pmd_t *pmd, unsigned long address,

unsigned long size)

{

unsigned long end;

pte_t *pte;

if (pmd_none(*pmd))

return;

if (pmd_bad(*pmd)) {

pmd_ERROR(*pmd);

pmd_clear(pmd);

return;

}

pte = pte_offset_kernel(pmd, address);

address &= ~PMD_MASK;

end = address + size;

if (end > PMD_SIZE)

end = PMD_SIZE;

do {

pte_t page;

//清除pte的对应映射关系

page = ptep_get_and_clear(pte);

address += PAGE_SIZE;

pte++;

if (pte_none(page))

continue;

if (pte_present(page))

continue;

printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n");

} while (address < end);

}

经过这几个过程之后,实际上,它只是找到线性地址所对应的pte,然后断开pte的映射.值得注意的是:为了效率起见,这里只是断开了pte的映射,即只是将pte置为none,表示pte末映射内存.并末断开pmd和pgd的映射
三:vmalloc的实现:

void *vmalloc(unsigned long size)

{

return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);

}

实际上调用__vmalloc:

void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot)

{

struct vm_struct *area;

struct page **pages;

unsigned int nr_pages, array_size, i;

//使请求的大小与页框对齐

size = PAGE_ALIGN(size);

//有效性检查

if (!size || (size >> PAGE_SHIFT) > num_physpages)

return NULL;


相关内容