网络驱动程序轮询中的致命异常
我正在为我的项目开发自定义网络设备驱动程序,其中与以太网驱动程序不同,我没有用于接收数据包的中断(设计限制)。所以,我使用轮询来接收司机的接收部分。 我在Linux中使用tasklet实现了一个轮询机制(主要从LDD3的jit.c示例中借用),它重新调度轮询函数10000次(稍微随机一个数字),以便在两个轮询之间进行延迟。它工作正常,但我决定将其作为基于计时器的实现来避免额外的开销。我用HRtimers,工作队列和定时器调用一个tasklet但他们都面临这个错误网络驱动程序轮询中的致命异常
内核恐慌 - 不同步:致命异常在中断
在eth_type_trans功能。以下是恐慌的错误细节,我得到:
[ 5031.345599] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 5031.346090] pgd = ffffffc07cf7f000
[ 5031.346471] [00000000] *pgd=0000000000000000
[ 5031.346988] Internal error: Oops: 96000005 [#1] PREEMPT SMP
[ 5031.347383] Modules linked in: alex_mcn(O)
[ 5031.348144] CPU: 0 PID: 601 Comm: systemd-journal Tainted: G O 3.16.0-rc6 #1
[ 5031.348744] task: ffffffc07cff5c40 ti: ffffffc07cf64000 task.ti: ffffffc07cf64000
[ 5031.349303] PC is at eth_type_trans+0x5c/0x164
[ 5031.349913] LR is at polling_tasklet_fn+0x84/0x144 [alex_mcn]
,然后它给我的堆栈跟踪:
[ 5031.406316] Call trace:
[ 5031.406798] [<ffffffc00045d604>] eth_type_trans+0x5c/0x164
[ 5031.407482] [<ffffffbffc000310>] polling_tasklet_fn+0x80/0x144 [alex_mcn]
[ 5031.408114] [<ffffffc000099198>] tasklet_hi_action+0xc4/0x198
[ 5031.408716] [<ffffffc0000995bc>] __do_softirq+0x10c/0x220
[ 5031.409304] [<ffffffc00009993c>] irq_exit+0x8c/0xc0
[ 5031.409882] [<ffffffc000084514>] handle_IRQ+0x6c/0xe0
[ 5031.410440] [<ffffffc000081290>] gic_handle_irq+0x3c/0x80
我的作品最初的代码是:
static int alex_mcn_single_rx(void){
struct sk_buff *skb;
...
skb = netdev_alloc_skb(net_dev, pktLen+5);
...
skb->protocol = eth_type_trans(skb, net_dev);
skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
if(netif_rx(skb) == NET_RX_SUCCESS){
net_dev->stats.rx_packets++;
}
else{
printk("!!! Failure in receiving the packet\n");
return 1;
}
return 0;
}
static void polling_tasklet_fn(unsigned long arg)
{
polling_data->count++;
if(polling_data->loops){
if((polling_data->count)%10000==0)
{
alex_mcn_single_rx();
}
}
tasklet_schedule(&polling_data->tlet);
}
static void init_polling_tasklet(char * buf){
polling_data->count = 0;
polling_data->loops = 1;
/* register the tasklet */
tasklet_init(&polling_data->tlet, polling_tasklet_fn, 0);
tasklet_hi_schedule(&polling_data->tlet);
}
此代码工作,但是当我删除if(polling_data-> loops)语句时,它停止工作,并给我提供了与上述相同的错误。这对我来说没有任何意义,因为在tasklets中没有竞争条件。另外,我知道eth_type_trans是唯一的罪魁祸首。当我删除它时,它不会遇到任何错误(尽管数据包将被删除)。如果有人能够告诉我为什么会发生这种情况,我将不胜感激。
p.s:我正在使用gem5模拟器和ARMv8 arch。测试我的设计。
解决:我结束了复制eth_type_trans()函数我的设备驱动程序,并与printks调试问题。比重建内核更容易调试它(模拟器需要很多时间)。在将eth_trans_type()函数复制到我的代码并开始在我的设备驱动程序中调试它之后,该功能开始正常工作
如何获取net_dev?点占位符(...)看起来很模糊。 我认为,netdev_alloc_skb()不会在net_dev = NULL上崩溃,因为它不取消引用它,但是eth_type_trans()需要一个正确的net_dev指针。在调用eth_type_trans()时,你有没有合适的net_dev?
是的,我检查了所有的NULL指针。没有任何问题与他们中的任何一个有关。我最终将eth_type trans()函数复制到我的源代码中,并给它一个不同的名称。然后,逐步检查功能并开始工作! –
错误“无法处理虚拟地址00000000处的内核NULL指针解引用”非常明显。也许从字面上阅读会有所帮助? –