异常现场:
当你在SYS_KERNEL_LOG里看到如下log,那么就属于BUG at __get_vm_area_node一类问题了
[ 271.881362]<0>-0)Internal error: Oops: 96000045 [#1] PREEMPT SMP ...... [ 280.012666]<0>-0)PC is at __get_vm_area_node.isra.28+0x1d4/0x1ec [ 280.012672]<0>-0)LR is at get_vm_area_caller+0x2c/0x34 ...... [ 280.014883]<0>-0)Call trace: [ 280.014891]<0>-0)[<ffffffc00017df54>] __get_vm_area_node.isra.28+0x1d4/0x1ec [ 280.014898]<0>-0)[<ffffffc00017ea48>] get_vm_area_caller+0x28/0x34 [ 280.014909]<0>-0)[<ffffffc0000948c4>] __ioremap+0x64/0xe8 [ 280.014920]<0>-0)[<ffffffc0006e0f2c>] hal_dma_dump_reg+0xf0/0xa0c [ 280.014932]<0>-0)[<ffffffc0006d934c>] btif_bbs_write.constprop.24+0x2b0/0x2dc [ 280.014943]<0>-0)[<ffffffc0006db1f8>] btif_dma_rx_data_receiver+0x1c/0x4c [ 280.014950]<0>-0)[<ffffffc0006e0cf8>] hal_rx_dma_irq_handler+0x170/0x2b4 [ 280.014959]<0>-0)[<ffffffc0006d7c6c>] btif_rx_dma_irq_handler+0x64/0xec [ 280.014970]<0>-0)[<ffffffc00011ff08>] handle_irq_event_percpu+0x98/0x3c8 [ 280.014978]<0>-0)[<ffffffc000120280>] handle_irq_event+0x48/0x78 [ 280.014987]<0>-0)[<ffffffc0001230c4>] handle_fasteoi_irq+0xb0/0x150 [ 280.014996]<0>-0)[<ffffffc00011f784>] generic_handle_irq+0x30/0x4c [ 280.015005]<0>-0)[<ffffffc0000848e4>] handle_IRQ+0x94/0x1cc [ 280.015012]<0>-0)[<ffffffc000081608>] gic_handle_irq+0x3c/0x80 |
代码位置:
kernel-3.18/mm/vmalloc.c
static struct vm_struct *__get_vm_area_node(unsigned long size,
unsigned long align, unsigned long flags, unsigned long start,
unsigned long end, int node, gfp_t gfp_mask, const void *caller)
{
struct vmap_area *va;
struct vm_struct *area;
BUG_ON(in_interrupt());
......
}
问题解读:
BUG_ON放在这里意思是在不允许在中断里调用__get_vm_area_node()函数。
为什么呢?应该是设计时就不允许在中断里使用的,该函数使用了全局变量,用spin_lock保护,这种锁无法保护到中断上下文。如果在中断里使用__get_vm_area_node()可能会引起一系列问题。
哪些常用函数会调用到__get_vm_area_node()呢?
- vmalloc()系列函数
- ioremap()系列函数,包括of_iomap()函数
也即是说,这些函数禁止在中断里调用!
问题解决:
如果是在中断里调用ioremap()函数则可以考虑在初始化时就map好。比如上面的例子,就应该在初始化时就map好,在中断里直接用就行了。
如果是vmalloc(),可以考虑用kmalloc()替换。