首页 > 解决方案 > 内核:`什么会导致以前一直被读取的内存读取突然开始导致“无法处理内核分页请求”?

问题描述

我在使用基于 2.6.31.6 的内核的自定义板上的以太网控制器驱动程序遇到了一个奇怪的问题。内核包含许多专用于该板 SoC 的模块,这些模块是在 2010 年代初期在 NDA 下开发的。这使得更新到较新的内核版本变得非常困难,我会远离那个选项。我对这个问题做了很多挖掘,我真的很感激有人能带来任何见解。

问题

网络设备位于定制板上,用于以大约 20Mbps 24/7 的速度传输数据。有时,它可能会正常工作几分钟,有时甚至几天。但是,最终,它会触发内核 oops,并显示以下错误消息:

 Unable to handle kernel paging request at virtual address fd40101c

如果我分析 Kernel Oops 中的堆栈跟踪、PC 和 LR,我可以发现问题出在驱动程序 NAPI 轮询机制上。我可以确认分页请求是通过设置设备寄存器中打开物理中断的位的方法完成的。

分析

当该设备接收到表示数据存在的物理中断时,会在寄存器中设置一个位以关闭物理中断。然后,读取通过 DMA 传输到内存的缓冲数据,直到没有更多数据可用为止。当没有更多数据可用时,它读取包含配置以启用物理中断的寄存器,设置该位以再次启用物理中断,然后将值写入寄存器。该问题发生在重新启用物理中断之前的读取期间。

问题是,该内存是在驱动程序初始化时分配的,并且永远不会未分配。设备中有 24x4 字节的寄存器。正在读取的是偏移量 0x101c,计算如下:

(dmaBase + (reg_num << 2)) -> (0x1000 + (7 << 2)) == 0x101c.

这对应于触发 Oops 的读取地址,其中基地址为 0xfd400000,寄存器偏移量为 0x101c,最终地址为 0xfd40101c。

问题

正如我在启用中断的方法中添加的 printk 所证实的那样,该内存正在被非常频繁地读取和写入。那么,为什么它现在会引起问题,因为它是在驱动程序初始化时分配的,并且在驱动程序生命周期中从未被取消分配?

什么会导致对以前一直被读取的先前分配的寄存器的内存读取突然开始导致“无法处理内核分页请求”?

提前感谢您的任何见解!

标签: linux-kernelkernelkernel-module

解决方案


推荐阅读