Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3976901d authored by Laura Abbott's avatar Laura Abbott
Browse files

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: default avatarLaura Abbott <lauraa@codeaurora.org>
parent c4127fbe
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1612,6 +1612,7 @@ static void __init map_lowmem(void)
		vm->flags |= VM_ARM_MTYPE(type);
		vm->caller = map_lowmem;
		add_static_vm_early(svm++);
		mark_vmalloc_reserved_area(vm->addr, vm->size);
	}
}

+6 −0
Original line number Diff line number Diff line
@@ -148,6 +148,12 @@ extern struct list_head vmap_area_list;
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
+21 −21
Original line number Diff line number Diff line
@@ -283,33 +283,33 @@ static unsigned long cached_align;
static unsigned long vmap_area_pcpu_hole;

#ifdef CONFIG_ENABLE_VMALLOC_SAVING
int is_vmalloc_addr(const void *x)
#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)
{
	struct vmap_area *va;
	int ret = 0;
	unsigned long addr = (unsigned long)x;

	spin_lock(&vmap_area_lock);
	list_for_each_entry(va, &vmap_area_list, list) {
		if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEING))
			continue;
	bitmap_set(possible_areas, VMALLOC_TO_BIT(addr), size >> PAGE_SHIFT);
}

		if (!(va->flags & VM_VM_AREA))
			continue;
int is_vmalloc_addr(const void *x)
{
	unsigned long addr = (unsigned long)x;

		if (va->vm == NULL)
			continue;
	if (addr < POSSIBLE_VMALLOC_START || addr >= VMALLOC_END)
		return 0;

		if (va->vm->flags & VM_LOWMEM)
			continue;
	if (test_bit(VMALLOC_TO_BIT(addr), possible_areas))
		return 0;

		if ((unsigned long)x >= va->va_start &&
		    (unsigned long)x < va->va_end) {
			ret = 1;
			break;
		}
	}
	spin_unlock(&vmap_area_lock);
	return ret;
	return 1;
}
#else
int is_vmalloc_addr(const void *x)