Hoolev Linux, Network, Coding

KNI模块在32位系统的segfault问题

DPDK的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位系统中,由用户态分配的物理地址在内核态进行转换后出错。

##