soc: fsl: qe: refactor cpm_muram_alloc_common to prevent BUG on error path
If the kmalloc() fails, we try to undo the gen_pool allocation we've just done. Unfortunately, start has already been modified to subtract the GENPOOL_OFFSET bias, so we're freeing something that very likely doesn't exist in the gen_pool, meaning we hit the kernel BUG at lib/genalloc.c:399! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM ... [<803fd0e8>] (gen_pool_free) from [<80426bc8>] (cpm_muram_alloc_common+0xb0/0xc8) [<80426bc8>] (cpm_muram_alloc_common) from [<80426c28>] (cpm_muram_alloc+0x48/0x80) [<80426c28>] (cpm_muram_alloc) from [<80428214>] (ucc_slow_init+0x110/0x4f0) [<80428214>] (ucc_slow_init) from [<8044a718>] (qe_uart_request_port+0x3c/0x1d8) (this was tested by just injecting a random failure by adding "|| (get_random_int()&7) == 0" to the "if (!entry)" condition). Refactor the code so we do the kmalloc() first, meaning that's the thing that needs undoing in case gen_pool_alloc_algo() then fails. This allows a later cleanup to move the locking from the callers into the _common function, keeping the kmalloc() out of the critical region and then, hopefully (if all the muram_alloc callers allow) change it to a GFP_KERNEL allocation. Reviewed-by: Timur Tabi <timur@kernel.org> Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Li Yang <leoyang.li@nxp.com>
This commit is contained in:
parent
b6231ea2b3
commit
ec2058ac8f
|
@ -119,23 +119,21 @@ static s32 cpm_muram_alloc_common(unsigned long size,
|
||||||
struct muram_block *entry;
|
struct muram_block *entry;
|
||||||
s32 start;
|
s32 start;
|
||||||
|
|
||||||
start = gen_pool_alloc_algo(muram_pool, size, algo, data);
|
|
||||||
if (!start)
|
|
||||||
goto out2;
|
|
||||||
start = start - GENPOOL_OFFSET;
|
|
||||||
memset_io(cpm_muram_addr(start), 0, size);
|
|
||||||
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
||||||
if (!entry)
|
if (!entry)
|
||||||
goto out1;
|
return -ENOMEM;
|
||||||
|
start = gen_pool_alloc_algo(muram_pool, size, algo, data);
|
||||||
|
if (!start) {
|
||||||
|
kfree(entry);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
start = start - GENPOOL_OFFSET;
|
||||||
|
memset_io(cpm_muram_addr(start), 0, size);
|
||||||
entry->start = start;
|
entry->start = start;
|
||||||
entry->size = size;
|
entry->size = size;
|
||||||
list_add(&entry->head, &muram_block_list);
|
list_add(&entry->head, &muram_block_list);
|
||||||
|
|
||||||
return start;
|
return start;
|
||||||
out1:
|
|
||||||
gen_pool_free(muram_pool, start, size);
|
|
||||||
out2:
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue