Unverified Commit deffc1f2 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!10729 Backport vmalloc 2 bugfix

Merge Pull Request from: @ci-robot 
 
PR sync from: Peng Zhang <zhangpeng362@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/4YGAZOUQMAIWCWYCWPUQY3STB7IVCBLB/ 
From: ZhangPeng <zhangpeng362@huawei.com>

Backport vmalloc 2 bugfix for OLK-6.6.

Uladzislau Rezki (Sony) (1):
  mm: vmalloc: fix lockdep warning

rulinhuang (1):
  mm/vmalloc: eliminated the lock contention from twice to once


-- 
2.25.1
 
https://gitee.com/openeuler/kernel/issues/IAI0KD 
 
Link:https://gitee.com/openeuler/kernel/pulls/10729

 

Reviewed-by: default avatarKefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 9b4d28b3 0be7a82c
Loading
Loading
Loading
Loading
+65 −58
Original line number Diff line number Diff line
@@ -989,6 +989,27 @@ unsigned long vmalloc_nr_pages(void)
	return atomic_long_read(&nr_vmalloc_pages);
}

static struct vmap_area *__find_vmap_area(unsigned long addr, struct rb_root *root)
{
	struct rb_node *n = root->rb_node;

	addr = (unsigned long)kasan_reset_tag((void *)addr);

	while (n) {
		struct vmap_area *va;

		va = rb_entry(n, struct vmap_area, rb_node);
		if (addr < va->va_start)
			n = n->rb_left;
		else if (addr >= va->va_end)
			n = n->rb_right;
		else
			return va;
	}

	return NULL;
}

/* Look up the first VA which satisfies addr < va_end, NULL if none. */
static struct vmap_area *
__find_vmap_area_exceed_addr(unsigned long addr, struct rb_root *root)
@@ -1025,47 +1046,39 @@ __find_vmap_area_exceed_addr(unsigned long addr, struct rb_root *root)
static struct vmap_node *
find_vmap_area_exceed_addr_lock(unsigned long addr, struct vmap_area **va)
{
	struct vmap_node *vn, *va_node = NULL;
	struct vmap_area *va_lowest;
	unsigned long va_start_lowest;
	struct vmap_node *vn;
	int i;

	for (i = 0; i < nr_vmap_nodes; i++) {
repeat:
	for (i = 0, va_start_lowest = 0; i < nr_vmap_nodes; i++) {
		vn = &vmap_nodes[i];

		spin_lock(&vn->busy.lock);
		va_lowest = __find_vmap_area_exceed_addr(addr, &vn->busy.root);
		if (va_lowest) {
			if (!va_node || va_lowest->va_start < (*va)->va_start) {
				if (va_node)
					spin_unlock(&va_node->busy.lock);

				*va = va_lowest;
				va_node = vn;
				continue;
			}
		}
		spin_unlock(&vn->busy.lock);
	}
		*va = __find_vmap_area_exceed_addr(addr, &vn->busy.root);

	return va_node;
		if (*va)
			if (!va_start_lowest || (*va)->va_start < va_start_lowest)
				va_start_lowest = (*va)->va_start;
		spin_unlock(&vn->busy.lock);
	}

static struct vmap_area *__find_vmap_area(unsigned long addr, struct rb_root *root)
{
	struct rb_node *n = root->rb_node;
	/*
	 * Check if found VA exists, it might have gone away.  In this case we
	 * repeat the search because a VA has been removed concurrently and we
	 * need to proceed to the next one, which is a rare case.
	 */
	if (va_start_lowest) {
		vn = addr_to_node(va_start_lowest);

	addr = (unsigned long)kasan_reset_tag((void *)addr);
		spin_lock(&vn->busy.lock);
		*va = __find_vmap_area(va_start_lowest, &vn->busy.root);

	while (n) {
		struct vmap_area *va;
		if (*va)
			return vn;

		va = rb_entry(n, struct vmap_area, rb_node);
		if (addr < va->va_start)
			n = n->rb_left;
		else if (addr >= va->va_end)
			n = n->rb_right;
		else
			return va;
		spin_unlock(&vn->busy.lock);
		goto repeat;
	}

	return NULL;
@@ -1913,15 +1926,26 @@ node_alloc(unsigned long size, unsigned long align,
	return va;
}

static inline void setup_vmalloc_vm(struct vm_struct *vm,
	struct vmap_area *va, unsigned long flags, const void *caller)
{
	vm->flags = flags;
	vm->addr = (void *)va->va_start;
	vm->size = va->va_end - va->va_start;
	vm->caller = caller;
	va->vm = vm;
}

/*
 * Allocate a region of KVA of the specified size and alignment, within the
 * vstart and vend.
 * vstart and vend. If vm is passed in, the two will also be bound.
 */
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,
				unsigned long va_flags)
				unsigned long va_flags, struct vm_struct *vm,
				unsigned long flags, const void *caller)
{
	struct vmap_node *vn;
	struct vmap_area *va;
@@ -1984,6 +2008,9 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
	va->vm = NULL;
	va->flags = (va_flags | vn_id);

	if (vm)
		setup_vmalloc_vm(vm, va, flags, caller);

	vn = addr_to_node(va->va_start);

	spin_lock(&vn->busy.lock);
@@ -2570,7 +2597,8 @@ static void *new_vmap_block(unsigned int order, gfp_t gfp_mask)
	va = alloc_vmap_area(VMAP_BLOCK_SIZE, VMAP_BLOCK_SIZE,
					VMALLOC_START, VMALLOC_END,
					node, gfp_mask,
					VMAP_RAM|VMAP_BLOCK);
					VMAP_RAM|VMAP_BLOCK, NULL,
					0, NULL);
	if (IS_ERR(va)) {
		kfree(vb);
		return ERR_CAST(va);
@@ -2935,7 +2963,8 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node)
		struct vmap_area *va;
		va = alloc_vmap_area(size, PAGE_SIZE,
				VMALLOC_START, VMALLOC_END,
				node, GFP_KERNEL, VMAP_RAM);
				node, GFP_KERNEL, VMAP_RAM,
				NULL, 0, NULL);
		if (IS_ERR(va))
			return NULL;

@@ -3038,26 +3067,6 @@ void __init vm_area_register_early(struct vm_struct *vm, size_t align)
	kasan_populate_early_vm_area_shadow(vm->addr, vm->size);
}

static inline void setup_vmalloc_vm_locked(struct vm_struct *vm,
	struct vmap_area *va, unsigned long flags, const void *caller)
{
	vm->flags = flags;
	vm->addr = (void *)va->va_start;
	vm->size = va->va_end - va->va_start;
	vm->caller = caller;
	va->vm = vm;
}

static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
			      unsigned long flags, const void *caller)
{
	struct vmap_node *vn = addr_to_node(va->va_start);

	spin_lock(&vn->busy.lock);
	setup_vmalloc_vm_locked(vm, va, flags, caller);
	spin_unlock(&vn->busy.lock);
}

static void clear_vm_uninitialized_flag(struct vm_struct *vm)
{
	/*
@@ -3094,14 +3103,12 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
	if (!(flags & VM_NO_GUARD))
		size += PAGE_SIZE;

	va = alloc_vmap_area(size, align, start, end, node, gfp_mask, 0);
	va = alloc_vmap_area(size, align, start, end, node, gfp_mask, 0, area, flags, caller);
	if (IS_ERR(va)) {
		kfree(area);
		return NULL;
	}

	setup_vmalloc_vm(area, va, flags, caller);

	/*
	 * Mark pages for non-VM_ALLOC mappings as accessible. Do it now as a
	 * best-effort approach, as they can be mapped outside of vmalloc code.
@@ -4680,7 +4687,7 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,

		spin_lock(&vn->busy.lock);
		insert_vmap_area(vas[area], &vn->busy.root, &vn->busy.head);
		setup_vmalloc_vm_locked(vms[area], vas[area], VM_ALLOC,
		setup_vmalloc_vm(vms[area], vas[area], VM_ALLOC,
				 pcpu_get_vm_areas);
		spin_unlock(&vn->busy.lock);
	}