KNI模块在32位系统的segfault问题
03 Apr 2015DPDK的KNI模块是不支持32位的,这在config/defconfig_i686-native-linuxapp-gcc
中明确说明了。
DPDK Mailing Lists中的这篇文章只是说明了如何在32位系统中编译KNI,实践告诉我们运行时会遇到segfault错误。
错误分析
首先贴出错误日志
kernel: task: ed8e1570 ti: d4b84000 task.ti: d4b84000
kernel: EIP: 0060:[<f88a5aed>] EFLAGS: 00010202 CPU: 23
kernel: EIP is at kni_net_process_request+0x77/0x1e3 [rte_kni]
kernel: EAX: f21fea80 EBX: d2ac9d00 ECX: 2b024004 EDX: 00000001
kernel: ESI: 8a200b00 EDI: 2b024001 EBP: d4b85e44 ESP: d4b85e14
kernel: DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
kernel: CR0: 80050033 CR2: 9e28ea90 CR3: 2ac1f000 CR4: 001407f0
kernel: Stack:
kernel: d2ac9da0 00000000 d4b85e50 c075abb7 d4b85e64 0000000d d4b85e64 0000000d
kernel: d2ac9800 eb3a64c8 d2ac9800 d4b85e5c d4b85e68 f88a5d93 d2ac9d00 00000002
kernel: 00000001 00000000 d2ac9800 00000000 f88a8d10 d4b85e7c c06d4acd d2ac9800
kernel: Call Trace:
kernel: [<c075abb7>] ? notifier_call_chain+0x32/0x4b
kernel: [<f88a5d93>] kni_net_open+0x7f/0x8d [rte_kni]
kernel: [<c06d4acd>] __dev_open+0x80/0xdc
kernel: [<c06d4cea>] __dev_change_flags+0x98/0x10d
kernel: [<c06d4dd8>] dev_change_flags+0x18/0x44
kernel: [<c071b36f>] devinet_ioctl+0x209/0x4b4
kernel: [<c071be86>] inet_ioctl+0x81/0x9c
kernel: [<c06c169d>] sock_ioctl+0x1bd/0x1e5
kernel: [<c06c14e0>] ? sock_fasync+0x6e/0x6e
kernel: [<c050319c>] vfs_ioctl+0x20/0x2a
kernel: [<c0503a74>] do_vfs_ioctl+0x359/0x3fd
kernel: [<c0564258>] ? file_has_perm+0x4f/0x70
kernel: [<c04ff301>] ? generic_permission+0x1a1/0x1b5
kernel: [<c04ff488>] ? putname+0x22/0x25
kernel: [<c05668ae>] ? selinux_file_ioctl+0xa0/0xa3
kernel: [<c0503b62>] SyS_ioctl+0x4a/0x6c
kernel: [<c075d1c1>] sysenter_do_call+0x12/0x22
kernel: Code: 89 c7 f3 a5 8b 83 d8 00 00 00 8b 08 8b 50 08 8b 70 04 8d 79 01 4a 21 fa 39 f2 75 06 89 ca 31
c9 eb 11 8b b3 e4 00 00 00 83 c1 04 <89> 34 88 b9 01 00 00 00 85 c9 89 10 75 14 68 4f b9 8a f8 bb f0
kernel: EIP: [<f88a5aed>] kni_net_process_request+0x77/0x1e3 [rte_kni] SS:ESP 0068:d4b85e14
kernel: CR2: 000000009e28ea90
kernel: ---[ end trace 40e70890e616bbc6 ]---
kernel: kni[13104]: segfault at 10 ip 0805d98e sp bf8dae50 error 4 in kni[8048000+11b000]
注意这行:
kernel: EIP is at kni_net_process_request+0x77/0x1e3 [rte_kni]
,这告诉我们kni_net_process_request
函数有0x1e3这么大,segfault发生在0x77处。
这时既可以通过gdb调试来确定具体代码行,也可以通过加打印确定具体代码行,毕竟都已经知道具体函数名了。
通过调试得知程序挂在了memcpy(kni->sync_kva, req, sizeof(struct rte_kni_request));
kni->sync_kva
是一个地址,由用户空间地址转换而来。kni->sync_kva = phys_to_virt(dev_info.sync_phys);
在64位系统中KNI模块能够正常运行,而32位系统中不行,并且程序挂在了访问转换之后的地址上。 总所周知,64位系统与32位很大的不同是对内存的操作,因此我们怀疑32位系统中KNI模块segfault错误是由地址转换造成的。 即在32位系统中,由用户态分配的物理地址在内核态进行转换后出错。
##