vmalloc函数实现细节
来源:互联网 发布:变速箱 知乎 编辑:程序博客网 时间:2024/06/04 08:53
对于x86体系[luther.gliethttp] 高端物理地址的分配采用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当中删除掉对应的节点。然后将内存归还给伙伴系统
#define high_memory (-128UL << 20)等于0xf8000000
#define VMALLOC_OFFSET (8 * 1024 * 1024)
#define VMALLOC_START ((unsigned long)high_memory + VMALLOC_OFFSET)
#define VMALLOC_END (PKMAP_BASE - 2 * PAGE_SIZE)
#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE * (LAST_PKMAP + 1)) /
& PMD_MASK)
即vmalloc的起始地址为0xf8800000
---------------------------------------------------------------
以下转自:http://www.360doc.com/content/09/0525/21/36491_3650302.shtml
- vmalloc函数实现细节
- Linux vmalloc/vfree函数实现解读
- vmalloc 实现
- vmalloc 实现
- vmalloc内核函数分析。
- platform_get_resource函数实现细节
- 虚函数实现细节
- platform_get_resource函数实现细节
- Linux vmalloc的实现
- Vmalloc实现原理
- 变参函数实现细节
- Vmalloc
- vmalloc
- vmalloc
- vmalloc中物理地址重映射函数分析
- platform_get_resource函数实现细节------参数num
- 虚函数表的实现细节
- 虚函数表的实现细节
- JavaScript之‘联系我们’,‘收藏本站’,‘设为首页’
- 《浅析pc机上如何将vmlinuz- 2.6.31-14-generic解压出vmlinux》
- ADO操纵数据库封装类
- Common Subsequence 1458 pku
- 编写字符串复制函数strcpy及memcpy函数
- vmalloc函数实现细节
- .Access Insert Into 语法错误 集锦
- 康拓展开
- #include 用这个头文件之前还要做什么设置吗。。
- linux的highmem高端内存是如何被使用的
- 如何用SQL设置一张表中所有的字段允许为空值?
- Ruby on rails Mysql::Error: query: not connected
- freebsd+apache+mysql+php 拾遗
- 微软软件测试方法二