参照元†
- unsigned long size
- unsigned long align
- unsigned long vstar
- unsigned long vend
- int node
- gfp_t gfp_mask
返り値†
/*
* Allocate a region of KVA of the specified size and alignment, within the
* vstart and vend.
*/
static struct vmap_area *alloc_vmap_area(unsigned long size,
unsigned long align,
unsigned long vstart, unsigned long vend,
int node, gfp_t gfp_mask)
{
struct vmap_area *va;
struct rb_node *n;
unsigned long addr;
int purged = 0;
BUG_ON(!size);
BUG_ON(size & ~PAGE_MASK);
- サイズが 0 だったり、ページサイズの境界に合っていない場合はバグ
va = kmalloc_node(sizeof(struct vmap_area),
gfp_mask & GFP_RECLAIM_MASK, node);
if (unlikely(!va))
return ERR_PTR(-ENOMEM);
retry:
addr = ALIGN(vstart, align);
spin_lock(&vmap_area_lock);
if (addr + size - 1 < addr)
goto overflow;
/* XXX: could have a last_hole cache */
n = vmap_area_root.rb_node;
if (n) {
struct vmap_area *first = NULL;
do {
struct vmap_area *tmp;
tmp = rb_entry(n, struct vmap_area, rb_node);
if (tmp->va_end >= addr) {
if (!first && tmp->va_start < addr + size)
first = tmp;
n = n->rb_left;
} else {
first = tmp;
n = n->rb_right;
}
} while (n);
if (!first)
goto found;
if (first->va_end < addr) {
n = rb_next(&first->rb_node);
if (n)
first = rb_entry(n, struct vmap_area, rb_node);
else
goto found;
}
while (addr + size > first->va_start && addr + size <= vend) {
addr = ALIGN(first->va_end + PAGE_SIZE, align);
if (addr + size - 1 < addr)
goto overflow;
n = rb_next(&first->rb_node);
if (n)
first = rb_entry(n, struct vmap_area, rb_node);
else
goto found;
}
}
found:
if (addr + size > vend) {
overflow:
spin_unlock(&vmap_area_lock);
if (!purged) {
purge_vmap_area_lazy();
purged = 1;
goto retry;
}
if (printk_ratelimit())
printk(KERN_WARNING
"vmap allocation for size %lu failed: "
"use vmalloc=<size> to increase size.\n", size);
kfree(va);
return ERR_PTR(-EBUSY);
}
BUG_ON(addr & (align-1));
va->va_start = addr;
va->va_end = addr + size;
va->flags = 0;
__insert_vmap_area(va);
spin_unlock(&vmap_area_lock);
return va;
}
コメント†