ndo_start_xmit()
是从原子上下文中调用的(还是可以被调用的)?请提供文档参考。
更具体地说,禁止ndo_start_xmit()
直接执行以下任一操作:
kmalloc()
的情况下呼叫GFP_ATOMIC
?我做了一些简单的测试,至少前三个案例至少偶尔会失败。由涉及较少排队的网络操作驱动的对ndo_start_xmit()
的调用似乎更多地失败。如果我是通过工作队列间接进行上述操作的,则故障似乎消失。所有这些暗示可能ndo_start_xmit()
是从原子上下文调用的……但是没有文档表明我需要使用工作队列。 (为什么我要放弃250us的延迟?)
Others have also注意到ndo_start_xmit()的行为就像在原子上下文中被调用一样。但是,仅谷歌搜索它只会出现这些随机线程,而不是任何真实文档。
此外,在整个内核源代码中搜索注释时,我们只会听到声。
% grep -r -A 10 -B 10 -e netdev_ops -e ndo_start_xmit . --include '*.[ch]' | grep -i atomic
./net/l2tp/l2tp_eth.c- stats->tx_bytes = (unsigned long) atomic_long_read(&priv->tx_bytes);
./net/l2tp/l2tp_eth.c- stats->tx_packets = (unsigned long) atomic_long_read(&priv->tx_packets);
./net/l2tp/l2tp_eth.c- stats->tx_dropped = (unsigned long) atomic_long_read(&priv->tx_dropped);
./net/l2tp/l2tp_eth.c- stats->rx_bytes = (unsigned long) atomic_long_read(&priv->rx_bytes);
./net/l2tp/l2tp_eth.c- stats->rx_packets = (unsigned long) atomic_long_read(&priv->rx_packets);
./net/l2tp/l2tp_eth.c- stats->rx_errors = (unsigned long) atomic_long_read(&priv->rx_errors);
./net/core/neighbour.c- atomic_dec(&neigh->tbl->entries);
./net/core/dev.c- smp_mb__after_atomic(); /* Commit netif_running(). */
./net/core/dev.c- storage->rx_dropped += (unsigned long)atomic_long_read(&dev->rx_dropped);
./net/core/rtnetlink.c- skb = nlmsg_new(bridge_nlmsg_size(), GFP_ATOMIC);
./net/core/rtnetlink.c- rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
./drivers/net/can/usb/ems_usb.c- atomic_set(&dev->active_tx_urbs, 0);
./drivers/net/can/usb/usb_8dev.c- atomic_set(&priv->active_tx_urbs, 0);
./drivers/net/can/usb/peak_usb/pcan_usb_core.c- atomic_set(&dev->active_tx_urbs, 0);
./drivers/net/usb/sierra_net.c- dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter);
./drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c- if (!atomic_dec_and_test(&adapter->fcoe.refcnt))
./drivers/net/ethernet/toshiba/ps3_gelic_net.c- atomic_inc(&card->tx_timeout_task_counter);
./drivers/net/ethernet/toshiba/ps3_gelic_net.c- atomic_dec(&card->tx_timeout_task_counter);
./drivers/net/ethernet/toshiba/spider_net.c- atomic_dec(&card->tx_timeout_task_counter);
./drivers/net/thunderbolt.c- atomic_set(&net->command_id, 0);
./drivers/net/thunderbolt.c- atomic_set(&net->frame_id, 0);
./drivers/staging/octeon/ethernet.c- if (!atomic_read(&cvm_oct_poll_queue_stopping))
./drivers/staging/ks7010/ks_wlan_net.c- atomic_set(&update_phyinfo, 0);
./include/linux/netdevice.h- atomic_long_t rx_nohandler;
./include/linux/netdevice.h- atomic_t carrier_up_count;
./include/linux/netdevice.h- atomic_t carrier_down_count;
所以可以合理地得出一个结论,问题不是不是从原子上下文调用ndo_start_xmit()
,而是我正在使用损坏的API进行套接字,互斥,信号量和睡眠。但是在我开始无意间一次重写一个API之前,我们是否可以找到一些文档参考来说明ndo_start_xmit()
是(或可以)从原子上下文中调用的,以及采用哪种方式?
如果从原子上下文调用ndo_start_xmit()
,那么这被认为是好的软件设计吗?什么时候可以作为其他榜样的例子?