From f2da5eb8e5166b49226d7a71a0bc3ce6fdd87c72 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 20 Dec 2013 13:17:19 -0800 Subject: [PATCH] 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 --- arch/arm/mm/mmu.c | 4 ++- include/linux/vmalloc.h | 6 ++++ mm/vmalloc.c | 71 ++++++++++++++++++++++++----------------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index a1a2e51e69f..669b10e16f7 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -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++; } } diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 7675a5c84f3..500421f6f0f 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -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 diff --git a/mm/vmalloc.c b/mm/vmalloc.c index e17469362b0..2e074aa3fb6 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -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;