网络驱动程序轮询中的致命异常

时间:2017-08-31 17:00:40

标签: linux linux-kernel linux-device-driver

我正在为我的项目开发一个自定义网络设备驱动程序,其中与以太网驱动程序不同,我没有接收数据包的中断(设计限制)。所以,我使用轮询来获取驱动程序的接收部分。 我已经在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-&gt;循环)语句时,它会停止工作并给出与上面提到的相同的错误。这对我没有任何意义,因为在tasklet中没有竞争条件。另外,我知道eth_type_trans是唯一的罪魁祸首。我删除它时没有遇到任何错误(虽然数据包将被删除)。如果有人能给我一些线索,为什么会发生这种情况,我将不胜感激。

p.s:我正在使用带有ARMv8 arch的gem5模拟器。测试我的设计。

解决了:我最终将 eth_type_trans()函数复制到我的设备驱动程序并使用printks调试问题。以这种方式调试它比重建内核更容易(模拟器需要花费很多时间)。将eth_trans_type()函数复制到我的代码并开始在我的设备驱动程序中调试之后,该函数开始正常工作

1 个答案:

答案 0 :(得分:0)

你如何获得 net_dev ?点占位符(...)看起来很模糊。 我认为,netdev_alloc_skb()不会在 net_dev = NULL 上崩溃,因为它不会取消引用它,但eth_type_trans()需要一个正确的 net_dev 指针。在调用eth_type_trans()时,你有一个正确的 net_dev 吗?