struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,unsigned long start, unsigned long end)
用于查找从start开始到end结束的线性地址区域,并从该区域中穿件size 字节大小的内核虚拟区间.
其源码分析如下:
struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end)
{
#第二个形参表示1个字节对齐,同时这里通过__builtin_return_address(0) 来得到调用__get_vm_area的函数指针。
#这样可以很容易通过printf的%pF 来打印这个指针对应的symbol
return __get_vm_area_node(size, 1, flags, start, end, NUMA_NO_NODE,
GFP_KERNEL, __builtin_return_address(0));
}
static struct vm_struct *__get_vm_area_node(unsigned long size,
unsigned long align, unsigned long flags, unsigned long start,
unsigned long end, int node, gfp_t gfp_mask, const void *caller)
{
struct vmap_area *va;
struct vm_struct *area;
#不能在中断函数中调用这个函数
BUG_ON(in_interrupt());
#可见虽然指定1个byte对齐,但是这里其实还是按page size 对齐的.
size = PAGE_ALIGN(size);
#这里用unlikely修饰说明size 为0 是小概率事件.
if (unlikely(!size))
return NULL;
# 如果是io 空间的话,需要指定一个align
if (flags & VM_IOREMAP)
align = 1ul << clamp_t(int, get_count_order_long(size),
PAGE_SHIFT, IOREMAP_MAX_ORDER);
#申请一个struct vm_struct *area; 最后将这个结构体返回给用户,说明kernel中用这个
#结构体表示一段虚拟空间
area = kzalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
if (unlikely(!area))
return NULL;
#flags中没有包含VM_NO_GUARD的话。申请的size上在增加一个page size
if (!(flags & VM_NO_GUARD))
size += PAGE_SIZE;
#真正申请一段struct vmap_area *va;
va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
if (IS_ERR(va)) {
kfree(area);
return NULL;
}
#将va的值赋值给area
setup_vmalloc_vm(area, va, flags, caller);
return area;
}
内存管理API之__get_vm_area
最新推荐文章于 2024-04-09 10:09:40 发布