mm: make is_vmalloc_addr lockless

is_vmalloc_addr currently takes the vmap_area_lock and walks
the list of vmalloc areas to determine if an address is actually
a vmalloc address. Unfortunately, the current locking structure
with vmap_area_lock does not disable irqs which means that it may
be possible to recusively take the vmap_area_lock if an irq occurs
while walking the tree list. Considering the list of possible
vmalloc vs. not vmalloc ranges is not going to change after bootup,
skip the tree walking and just keep a bitmap of which virtual
addresses are set aside for vmalloc and which are not.

Change-Id: I0c159e09dc17b5c6641d08dcf630e6116b991cd5
CRs-Fixed: 591797
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
This commit is contained in:
Laura Abbott
2013-12-26 14:33:32 -08:00
committed by Olav Haugan
parent 2101ee7dfa
commit f2da5eb8e5
3 changed files with 50 additions and 31 deletions
+3 -1
View File
@@ -1500,7 +1500,9 @@ static void __init map_lowmem(void)
vm->flags = VM_LOWMEM | VM_ARM_STATIC_MAPPING;
vm->flags |= VM_ARM_MTYPE(type);
vm->caller = map_lowmem;
vm_area_add_early(vm++);
vm_area_add_early(vm);
mark_vmalloc_reserved_area(vm->addr, vm->size);
vm++;
}
}
+6
View File
@@ -136,6 +136,12 @@ extern struct vm_struct *vmlist;
extern __init void vm_area_add_early(struct vm_struct *vm);
extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
extern __init int vm_area_check_early(struct vm_struct *vm);
#ifdef CONFIG_ENABLE_VMALLOC_SAVING
extern void mark_vmalloc_reserved_area(void *addr, unsigned long size);
#else
static inline void mark_vmalloc_reserved_area(void *addr, unsigned long size)
{ };
#endif
#ifdef CONFIG_SMP
# ifdef CONFIG_MMU
+41 -30
View File
@@ -184,36 +184,6 @@ static int vmap_page_range(unsigned long start, unsigned long end,
return ret;
}
#ifdef ENABLE_VMALLOC_SAVING
int is_vmalloc_addr(const void *x)
{
struct rb_node *n;
struct vmap_area *va;
int ret = 0;
spin_lock(&vmap_area_lock);
for (n = rb_first(vmap_area_root); n; rb_next(n)) {
va = rb_entry(n, struct vmap_area, rb_node);
if (x >= va->va_start && x < va->va_end) {
ret = 1;
break;
}
}
spin_unlock(&vmap_area_lock);
return ret;
}
#else
int is_vmalloc_addr(const void *x)
{
unsigned long addr = (unsigned long)x;
return addr >= VMALLOC_START && addr < VMALLOC_END;
}
#endif
EXPORT_SYMBOL(is_vmalloc_addr);
int is_vmalloc_or_module_addr(const void *x)
{
/*
@@ -302,6 +272,47 @@ static unsigned long cached_align;
static unsigned long vmap_area_pcpu_hole;
#ifdef CONFIG_ENABLE_VMALLOC_SAVING
#define POSSIBLE_VMALLOC_START PAGE_OFFSET
#define VMALLOC_BITMAP_SIZE ((VMALLOC_END - PAGE_OFFSET) >> \
PAGE_SHIFT)
#define VMALLOC_TO_BIT(addr) ((addr - PAGE_OFFSET) >> PAGE_SHIFT)
#define BIT_TO_VMALLOC(i) (PAGE_OFFSET + i * PAGE_SIZE)
DECLARE_BITMAP(possible_areas, VMALLOC_BITMAP_SIZE);
void mark_vmalloc_reserved_area(void *x, unsigned long size)
{
unsigned long addr = (unsigned long)x;
bitmap_set(possible_areas, VMALLOC_TO_BIT(addr), size >> PAGE_SHIFT);
}
int is_vmalloc_addr(const void *x)
{
unsigned long addr = (unsigned long)x;
if (addr < POSSIBLE_VMALLOC_START || addr >= VMALLOC_END)
return 0;
if (test_bit(VMALLOC_TO_BIT(addr), possible_areas))
return 0;
return 1;
}
#else
int is_vmalloc_addr(const void *x)
{
unsigned long addr = (unsigned long)x;
return addr >= VMALLOC_START && addr < VMALLOC_END;
}
#endif
EXPORT_SYMBOL(is_vmalloc_addr);
static struct vmap_area *__find_vmap_area(unsigned long addr)
{
struct rb_node *n = vmap_area_root.rb_node;