内存管理2get_vm_area
2012-05-06 08:18
435 查看
今天开始linux驱动27---内存管理2get_vm_area
2010-06-04 16:53:03| 分类:个人日记 | 标签:
|字号大中小
订阅
周三
struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
{
return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);
}
同样,是一层封装加了一些参数,起始地址和结束地址。其中起始地址用来找第一次对齐地址。结束地址作为越界标志。
我们先来看一个重要的数据结构,vm_struct
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;//链表下一级地址
};
#define IOREMAP_MAX_ORDER (7 + PAGE_SHIFT) /* 128 pages */
struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end)
{
struct vm_struct **p, *tmp, *area;//申请内存块指针和2级指针做链表循环用
unsigned long align = 1;
unsigned long addr;
if (flags & VM_IOREMAP) {//如果是内存映射则按照申请大小对齐
int bit = fls(size);//计算size中第一个非0的位的位数
if (bit > IOREMAP_MAX_ORDER)//把大小定位在内存映射对齐地址范围之内
bit = IOREMAP_MAX_ORDER;//page——shift到 page-shift+7吧
else if (bit < PAGE_SHIFT)
bit = PAGE_SHIFT;
align = 1ul << bit;
}
addr = ALIGN(start, align);//按照内存映射大小取第一个可以对齐的地址,起始地址是start
area = kmalloc(sizeof(*area), GFP_KERNEL);//申请一个vm struct结构体大小内存,用作建立链表
if (unlikely(!area))
return NULL;
/*
* We always allocate a guard page.
*/
size += PAGE_SIZE;//申请内存的大小额外加一页的大小,用作越界处理的判断
if (unlikely(!size)) {
kfree (area);
return NULL;
}
write_lock(&vmlist_lock);
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;
}
found:
area->next = *p;//该空闲内存加入链表当中。临时也指向下一个
*p = area;//当前的next指向临时结构
area->flags = flags;//flags ioremap已经指定
area->addr = (void *)addr;//空闲内存首地址肯定是每次对齐最后留下的
area->size = size;//大小赋值
area->pages = NULL;
area->nr_pages = 0;
area->phys_addr = 0;
write_unlock(&vmlist_lock);
return area;
out:
write_unlock(&vmlist_lock);
kfree(area);
if (printk_ratelimit())
printk(KERN_WARNING "allocation failed: out of vmalloc space - use vmalloc=<size> to increase size.\n");
return NULL;
}
//对应的释放某快映射内存的代码如下
/**
* remove_vm_area - find and remove a contingous kernel virtual area
*
* @addr: base address
*
* Search for the kernel VM area starting at @addr, and remove it.
* This function returns the found VM area, but using it is NOT safe
* on SMP machines.
*/
struct vm_struct *remove_vm_area(void *addr)
{
struct vm_struct **p, *tmp;//仍然是临时结构体
write_lock(&vmlist_lock);
for (p = &vmlist ; (tmp = *p) != NULL ;p = &tmp->next) {//仍然是循环查找。二级指针指向next地址
//tmp指向下一块
if (tmp->addr == addr)//直接找到地址
goto found;
}
write_unlock(&vmlist_lock);
return NULL;
found:
unmap_vm_area(tmp);
*p = tmp->next;//上一块的地址指向下一块的地址,从链表上抽下来tmp
write_unlock(&vmlist_lock);
return tmp;
}
//umap的代码
void unmap_vm_area(struct vm_struct *area)
{
unsigned long address = (unsigned long) area->addr;
unsigned long end = (address + area->size);
pgd_t *dir;
dir = pgd_offset_k(address);
flush_cache_vunmap(address, end);
do {
unmap_area_pmd(dir, address, end - address);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
flush_tlb_kernel_range((unsigned long) area->addr, end);
}
这里的内存池的代码很干练,值得多看看,只用了一个链表就能把空闲和使用的内存统统记录,虽然链表本身记录的是使用的内存,但是未使用的内存就自动标记并可以合并了很好很强大
相关文章推荐
- 内存管理API之get_vm_area_size
- 内存管理API之__get_vm_area
- 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现
- 22、 BUG at __get_vm_area_node()
- 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现
- 内存管理API之alloc_vm_area
- 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现
- linux2.4.19下__ioremap和get_vm_area的粗略理解
- 内存管理API之get_unmapped_area
- 内存管理API之free_vm_area
- 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现
- MRC内存管理(四)set、get方法
- 内存管理GetMemory
- Get Integer sided triangles for which the area/perimeter ratio is integral
- Compiler - Python VM Get Python25_d.dll Python25_d.lib
- 内存管理第一篇--HotSpotVM-内存管理介绍
- 内存管理API之__get_free_pages
- vm_area_struct
- Get Integer sided triangles for which the area/perimeter ratio is integral
- Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析