【问题标题】:Fatal exception in interrupt in network driver polling网络驱动程序轮询中断中的致命异常
【发布时间】:2017-08-31 17:00:39
【问题描述】:

我正在为我的项目开发一个自定义网络设备驱动程序,与以太网驱动程序不同,我没有接收数据包的中断(设计限制)。因此,我对驱动程序的接收部分使用轮询。 我在 Linux 中使用 tasklet 实现了一种轮询机制(主要从 LDD3 的 jit.c 示例中借用),它将轮询函数重新调度 10000 次(有点随机数),以在每两次轮询之间产生延迟。它工作得很好,但我决定让它成为一个基于计时器的实现以避免额外的开销。我使用了 HRtimers、workqueues 和一个调用 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) 语句时,它停止工作并给我与上述相同的错误。这对我来说没有任何意义,因为小任务中没有竞争条件。另外,我知道 eth_type_trans 是唯一的罪魁祸首。当我删除它时它不会遇到任何错误(尽管数据包将被丢弃)。如果有人能给我一些线索为什么会发生这种情况,我将不胜感激。

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

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

【问题讨论】:

  • 错误Unable to handle kernel NULL pointer dereference at virtual address 00000000 很能说明问题。也许从字面上阅读会有所帮助?

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


【解决方案1】:

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

【讨论】:

  • 是的,我检查了所有的 NULL 指针。他们中的任何一个都没有任何问题。我最终将 eth_type trans() 函数复制到我的源代码中并给它起了一个不同的名称。然后,逐步检查功能,它开始工作了!
猜你喜欢
  • 2011-05-16
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-14
  • 2020-05-15
  • 1970-01-01
相关资源
最近更新 更多