2017-08-31 263 views
0

我正在为我的项目开发自定义网络设备驱动程序,其中与以太网驱动程序不同,我没有用于接收数据包的中断(设计限制)。所以,我使用轮询来接收司机的接收部分。 我在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()函数复制到我的代码并开始在我的设备驱动程序中调试它之后,该功能开始正常工作

+0

错误“无法处理虚拟地址00000000处的内核NULL指针解引用”非常明显。也许从字面上阅读会有所帮助? –

回答

0

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

+0

是的,我检查了所有的NULL指针。没有任何问题与他们中的任何一个有关。我最终将eth_type trans()函数复制到我的源代码中,并给它一个不同的名称。然后,逐步检查功能并开始工作! –