全部博文(2005)
分类:
2010-05-12 12:02:10
高端物理地址的分配 采用vmalloc/vfree这组函数进行,什么是高端物理内存呢?我们知道Linux给内核预留了一部分虚拟地址空间,这部分虚拟地址如果能全部直接映射到物理地址空间就不存在高端内 存。如果这部分内存有一部分不能直接映射到地址空间,那么这部分虚拟地址空间称为高端内存。因此,高端内存是虚拟地址空间中的概念。举个例子:如果你的物 理内存为512M, 那么就不存在高端内存的分配,如果你的物理地址为2G,那么有1G+128M(预留给VMALLOC区)是属于高端内存的。高端内存的分配即便是逻辑上连续,也不要求物理上是连续的。
下面我们介绍一下高端内存的分配。分配高端内存是通过调用vmalloc函数。我们来解读一下该函数的 分配过程。
首先介绍一下这部分内存管理所需要 的数据结构:
struct vm_struct {
void *addr; // 虚拟地址的开始
unsigned long size; // 分配大小
unsigned long flags; // 标志位
struct page **pages; // 对应的页面
unsigned int nr_pages; // 页面数量
unsigned long phys_addr; // 物理地址
struct vm_struct *next; // 单链表,指向下一个vm节点
};
1. 首先检查请求分配的内存大小有没有超过最大的物理页面数。如果超过返回0,表示分配失败。
size = PAGE_ALIGN(size);
if (!size || (size >> PAGE_SHIFT) > num_physpages)
return NULL;
2. 使用kmalloc在slab中,分配vm_struct数据结构。
area = kmalloc_node(sizeof(*area), GFP_KERNEL, node);
3. 在单链表vmlist中查找适合的位置,并将新的vm节点插入到单链表中。
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) < 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; // 地址越界
}
// 插入新的vm节点到vmlist中去。
area->next = *p;
*p = area;
// 初始化新结点
area->flags = flags;
area->addr = (void *)addr;
area->size = size;
// 物理内存还未分配。
area->pages = NULL;
area->nr_pages = 0;
area->phys_addr = 0;
4. 接下来初始化vm_struct结构中的pages和nr_pages字段。
a) 初始化nr_pages字段
nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
b) 初始化pages数组
计算数组大小
array_size = (nr_pages * sizeof(struct page *));
如果数组大小大于1个页面,在非连续区进行分配,否则在连续区 进行分配
if (array_size > PAGE_SIZE)
pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);
else
pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node);
area->pages = pages;
5. 从伙伴系统中进行物理内存页面的分配
for (i = 0; i < area->nr_pages; i++) {
if (node < 0)
area->pages[i] = alloc_page(gfp_mask); // 针对UMA
else
area->pages[i] = alloc_pages_node(node, gfp_mask, 0); // 针对NUMA
if (unlikely(!area->pages[i])) {
/* Successfully allocated i pages, free them in __vunmap() */
area->nr_pages = i;
goto fail;
}
}
6. 将刚申请的页面映射到页表中。
if (map_vm_area(area, prot, &pages))
释放内存部分很简单,就是从vmlist当中删除掉对应的节点。然后将 内存归还给伙伴系统
chinaunix网友2010-06-17 23:14:00
disocuntMBT Shoes on sale! Welcome to our online store! www.my-cheapshoes.com. MBT Shoes stands for Masai Barefoot Technology. The uniquely-designed, multi-layered, cured sole is designed to simulate walking in sand. If you love MBT Shoes, please come to our store. We offer Wome
gliethttp2010-05-13 11:16:14
是的,我也同意你的理解,默认0xf8800000-0xffffxxxx之间的内核线性虚拟地址空间是预留给vmalloc使用的,从虚拟地址空间角度出发,0xf8800000-0xffffffff这段内核线性虚拟地址空间应该理解为内存映射区,至于0xf8800000-0xffffffff内核虚拟地址空间最终映射到物理内存的哪一段,有这样一个原则,如果物理内存超过1G,那么vmalloc将优先从1G-128M之后的未被映射到内核线性空间的物理内存一个page一个page的获取page,如果物理内存小于1G,比如512M,那么vmalloc因为没有high_memory高端内存而从512M的物理内存中获取物理page页,在物理内存超过1G的时候,vmalloc的分配内核线性虚拟地址映射到内存物理地址的方式有些类似mips处理器的remap0-remap7内存映射寄存器中描述的物理地址空间的分段映射物理地址方式
chinaunix网友2010-05-12 12:35:49
高端内存是物理内存存在缘故吧,linux分配的虚拟内存只是为了使得这部分物理内存由线性地址而进行访问~,文章出讲高端内存的概念有些不准确吧~