Ser*_*ASM 4 c deadlock module netfilter linux-kernel
我编写了内核模块,它执行nf_register_hook并使用字符设备机制将抓取的数据包通过设备读取挂钩获取到用户空间.我使用全局缓冲区和缓冲区变量,这就是为什么我需要在新数据包到来或用户阅读我的设备时锁定它.我使用了splinlock_irqsave和spin_unlock_irqrestore(&locker,flags),但是我的模块陷入死锁并且系统死机.
unsigned int main_hook(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int(*okfn)(struct sk_buff*)) {
unsigned long flags;
spin_lock_irqsave(&locker,flags);
...
spin_unlock_irqrestore(&locker,flags);
}
ssize_t sniffer_dev_read(struct file *filep, char *buff, size_t count, loff_t *offp) {
spin_lock_irqsave(&locker,flags);
...
spin_unlock_irqrestore(&locker,flags);
}
main_hook is registered in nf_register_hook()
sniffer_dev_read is registered in register_chrdev
Run Code Online (Sandbox Code Playgroud)
当用户从设备读取时,系统进入死锁状态.想法?或者可能是irq保存/恢复与netfiler hook/char设备读取不兼容,我必须在这里使用特殊锁定?
首先,您应该在启用锁定调试选项的情况下重新编译内核,然后再次尝试.他们可以帮助指出原因.
spin_lock_irqsave中存在死锁的几种可能原因.它可能是递归锁定(也就是说,您试图在锁定旋转锁定的代码部分内再次调用spin_lock_*).可能是你在旋转锁被锁定的情况下睡觉(不要这样做 - 对于你所持有的锁定所调用的每个功能,你必须知道它是否可以睡眠).它可能是一个AB/BA死锁(代码的一部分首先锁定A然后是B;另一部分首先锁定B然后锁定A;如果第一部分锁定A但不锁定B而第二部分锁定B但不锁定A你有一个僵局).等等.锁定调试选项可以检测并警告您其中的许多内容.
由于您锁定的是"全局缓冲区和缓冲区变量",因此请尝试将锁定区域减小到最小.不是锁定在函数顶部并在最后解锁,而是在锁定之外尽可能多地操作并且仅在操作缓冲区时锁定.理想情况下,锁定部分只是一些没有函数调用的指令.在这种情况下,僵局要困难得多.
现在我说了所有这些,我尝试进行通灵调试(即猜测问题出在哪里):你正在调用copy_to_user(可以睡觉)并保持旋转锁定.
| 归档时间: |
|
| 查看次数: |
1534 次 |
| 最近记录: |