资讯详情

内核paging request崩溃排查:从日志证据链区分内存故障与驱动bug

📅 2026/10/11 21:32:25 | 华诺云谱 👁 阅读
内核paging request崩溃排查:从日志证据链区分内存故障与驱动bug
凌晨一点四十手机连续三条告警弹出来核心业务服务器宕机重启。登录进系统翻看内核日志第一眼就是那句几乎每个运维都见过的报错BUG: unable to handle kernel paging request at ffff9f...。这时候绝大多数人的第一反应和我当年一模一样内存条坏了拆机换硬件。但真实故障现场里这行报错既可能是物理内存粒子的劣化也可能是某个驱动访问了非法地址还可能是固件与内核版本之间的兼容性冲突。这篇内容想分享的正是当这个报错出现在生产服务器日志里时怎样依靠日志证据链快速划分责任范围而不是上来就换内存换完一轮再换CPU折腾几个通宵后问题照旧。1. 内核在崩溃前经历了什么paging request到底在表达什么1.1 一次访存请求是如何失败并引爆panic的要理解这个报错先得把CPU访存机制说清楚。程序代码里操作的地址都是虚拟地址CPU拿到指令后要经过MMU内存管理单元去查页表才能换算成物理内存地址。MMU查页表时如果发现这一项地址映射根本不存在页表项里的present位是0或者这一项被标记成了无效状态又或者权限不匹配比如往只读页里写数据就会抛出一个page fault也就是缺页异常。用户态程序发生page fault常见结局是进程被内核发送SIGSEGV信号干掉也就是我们常说的段错误进程死了系统还活着。但同样的fault如果发生内核态性质就完全不同了。内核代码访问了一个无法通过MMU校验的地址这意味着内核自己维护的内存视图出了问题系统已经无法保证接下来还能安全运行于是直接触发panic服务器就地死给你看。unable to handle kernel paging request就是内核态发生这种致命page fault时打印出来的核心告警。注意这里的关键词是kernel——它划定了一个范围这次崩溃不是某个进程的普通段错误而是操作系统内核自身的访存异常内核模块、驱动回调、中断处理函数、内存分配路径上的代码都有可能是肇事者。1.2 日志里那些神秘数字到底怎么读真实崩溃日志看起来往往一团糟但其实每一段都有明确含义。摘一段典型输出举个例子BUG: unable to handle kernel paging request at ffff9f10c001d000 Oops: 0000 [#1] SMP KASAN PTI RIP: 0010:some_driver_do_io0x4a/0x100 [some_driver] Call Trace: some_driver_poll0x2e/0x80 [some_driver] net_rx_action0x1f4/0x5a0 __do_softirq0xdb/0x1f0 ... Modules linked in: some_driver(OE) nvme vfio_iommu_type1 ...第一行at后面的地址是CPU想要访问的那个虚拟地址这个地址本身就能告诉我们不少信息。比如落在ffff...高位区间说明是内核态地址区域如果这个地址是0xffffffffffffffff之类的异常值那基本可以断定是某个指针被赋了非法值而不是内存粒子的物理损坏。Oops: 0000后面的0000是page fault的错误码。这个数字要按二进制位拆开读每位各有含义第0位页是否存在。0表示页不存在1表示页存在但被拒绝访问第1位访问类型。0为读取1为写入第2位触发来源。0为内核态1为用户态第3位页表保留位是否被置位。置位意味着页表内容本身可能已经损坏第4位是否是取指操作按这个规则三种最常见的组合值得单独记忆错误码二进制含义常见指向0x00内核态读取一个不存在的页空指针、悬空指针、地址被破坏0x02内核态写入一个不存在的页越界写、释放后再写use-after-free0x08页表保留位违规页表内容异常硬件/内存位翻转的嫌疑上升RIP字段指向的是出问题的那一行代码。如果符号落在某个具体模块名后面比如上面例子里的some_driver_do_io0x4a [some_driver]驱动模块就成了头号嫌疑对象。Call Trace则展示调用链告诉我们是哪个执行路径把系统带到了这里。1.3 为什么内存故障和驱动bug会走向同一个报错物理内存出问题比如某个内存颗粒发生位翻转可能直接把页表项里的数据改掉了。MMU拿着被改坏的页表项去翻译地址发现保留位被置位、地址映射不存在立刻抛异常。这是一种情况。驱动出问题则是另一条路径。内核驱动代码出现野指针、释放了内存后又被设备DMA写回、传给内核的内存地址参数本身就是错的、固件与驱动对寄存器或缓冲区的理解不一致……这些软件层面的错误最终都会表现为内核态访问了一个无法解析的地址。两条完全不同的起因在MMU这一关汇合成了同一个报错。这就是为什么单看unable to handle kernel paging request这行字根本无法区分内存故障和驱动问题——深入排查既不能跳过日志证据直接拆机也不能只看一眼就认定是驱动背锅。后面要做的是一层一层剥开日志里的线索。2. 日志先行把崩溃现场的六个高价值字段全部提取出来2.1 收集现场证据的正确姿势遇到panic第一件事不是重启业务而是把崩溃现场尽可能地保存下来。先看系统日志。多数Linux发行版会把内核日志写到/var/log/messages或者/var/log/kern.log使用systemd的环境还可以用journalctl -k查看内核专用日志。注意panic之后系统通常会自动重启当时刻的日志会落在上一个启动周期里查日志时要带-b -1参数指定上一个bootjournalctl -k -b -1 --no-pager panic_last_boot.log比日志更值钱的是vmcore也就是内核崩溃转储。如果提前配好了kdump机制系统panic时会把崩溃瞬间的内存镜像保存下来这份镜像记录了RIP处所有寄存器的值、内核栈、模块列表是定位软件问题的一手证据。很多生产环境没开kdump崩溃后自动重启现场直接被抹掉排查只能靠外围线索难度陡增。所以下面的内容我会反复强调无论如何都要把kdump开起来。另外sosreport这类系统信息收集工具可以一次性打包内核版本、驱动模块列表、固件信息、日志归档是远程排查时的标准动作建议第一时间运行。2.2 六条信息按顺序读证据自然浮出水面我的习惯是严格按固定顺序读日志先看panic地址和RIP符号再看fault code接着看Call Trace尾部然后搜索同一次崩溃前有没有MCE机器检查记录继续搜索PCIe AER错误最后把BMC侧的硬件事件日志调出来对照。每一步都对应一种排除方向读取步骤内容排除方向1panic地址、RIP符号先确认崩溃代码大致归属2fault code判断是空指针类还是页表损坏类3Call Trace看是哪条内核路径触发的崩溃4MCE/EDAC记录判断内存/CPU硬件是否报错5PCIe AER记录判断总线或端点设备是否异常6BMC SEL/内存DIMM事件排除物理硬件事件这个顺序的核心逻辑是先用日志把软件证据看完再用硬件错误记录去交叉验证。日志如果显示RIP在某个驱动模块里且没有硬件错误记录那么先把它当软件问题排查日志如果伴随大量MCE和EDAC错误记录则硬件嫌疑大幅上升。2.3 用命令快速筛查关键词在拿到完整日志后我会先用一组命令快速筛查高价值字段dmesg -T | grep -i -E paging request|Oops|panic|general protection fault dmesg -T | grep -i -E mce|edac|corrected|uncorrected error dmesg -T | grep -i -E AER|PCIe Bus Error|timeout|link down第一条找崩溃本体第二条找内存硬件错误记录第三条找PCIe总线错误。三条结果叠加基本能画出故障的全景。如果机器的崩溃发生在历史记录里而不是当场复现对应的journalctl -k -b -N也要同样筛查一遍。这里要说一个重要的经验硬件错误不一定要在panic那一刻才出现。很多时候内存颗粒早就开始报可纠正错误比如MCE记录里的CEcorrectable error一直在缓慢增长但系统带着这些错误还能继续跑直到某一天某个不可纠正事件彻底引爆panic。所以筛查日志时时间跨度要拉长到崩溃前几周甚至几个月单纯看panic前后几十行的日志很容易漏掉真正的早期指纹。2.4 日志里的两个关键分水岭读日志时脑子里要一直绷着两根弦我管它们叫分水岭。第一个分水岭有没有MCE或者EDAC记录。x86体系里的CPU带Machine Check Exception机制专门用来报告处理器和内存相关硬件错误。内存颗粒出现位翻转时如果用了ECC内存通常会产生一条MCE记录可纠正的错误记为CE不可纠正的错误记为UE。Linux内核日志中出现mce: [Hardware Error]字样或者EDAC驱动的错误计数持续增长就是内存硬件问题的实锤。反过来日志里干干净净找不出任何MCE、EDAC记录却直接蹦出一个paging request panic那软件问题的概率会明显提高。第二个分水岭有没有PCIe AER记录。AER是PCIe总线的高级错误报告机制报错时会在dmesg里打印类似PCIe Bus Error: severityUncorrected (Non-Fatal)的信息同时给出memAddr和device字段。出现这类错误说明PCIe链路上某个设备或端点出过问题比如NVMe固态硬盘、网卡、RAID卡。它和内核的paging request往往存在因果链设备的DMA访问到了一个本不该访问的内存区域或者设备驱动在处理DMA缓冲区时用了已被释放的地址最终在内核态触发panic。这个分水岭一旦出现排查重心就要从内存条转移到总线和设备驱动。3. 内存嫌疑的实锤验证从日志怀疑到拆机换条的完整链路3.1 mcelog和EDAC日志究竟怎么读当你发现日志里确实有MCE记录接下来的动作就明确多了定位错误发生在哪一条内存然后把它换掉。mcelog是Linux上解析MCE记录的常用工具它会把错误记录解析成可读文本并且能按时间归档。查看历史记录可以这样mcelog --client ls /var/log/mcelog/ cat /var/log/mcelog/previous一条典型的内存MCE记录会标注socket、channel、DIMM编号还会给出物理地址范围。高端服务器一般单颗CPU集成了多个内存控制器每个控制器管理若干通道每个通道挂若干DIMM所以channel和DIMM字段非常关键可以直接定位到具体槽位。然后是Linux内核的EDAC子系统。加载了对应内存控制器的EDAC驱动后系统会在/sys/devices/system/edac/mc/目录下暴露内存控制器的统计信息grep . /sys/devices/system/edac/mc/mc*/ce_count grep . /sys/devices/system/edac/mc/mc*/ue_countue_count每增加一次都意味着一次不可纠正错误这种错误通常会直接导致进程崩溃甚至系统panic。ce_count增加表示可纠正错误虽然不影响运行但持续增长的ce_count是内存颗粒老化的重要信号。我见过一台服务器一个月内ce_count从0涨到几万当时没在意第二个月就连续panic了三次。修这种问题最划算的时机其实是看到ce_count异常增长的那一刻。3.2 软件层面先做交叉验证不是所有带MCE的paging request都能直接锁定内存条需要交叉验证一下。观察panic地址的规律如果多次崩溃里panic地址都落在同一段物理映射区间且mcelog记录的错误物理地址也在相近范围两个证据指向同一区域那基本可以认定是那一条内存的问题。反过来如果panic地址每次都不同但崩溃的代码路径完全一致比如每次RIP都在同一个驱动的同一个函数里那软件bug的嫌疑会显著上升。另一个值得注意的细节内存故障通常会伴随一系列周边症状比如在同一台机器上其他业务进程也频繁出现段错误、数据库校验和不一致、文件系统ext4报错、容器随机被kill。这些都是内存位翻转在系统其他部位的投影。如果一台机器既panic又到处出幺蛾子内存硬件故障的概率很高如果一台机器别的都好好的就唯独每次panic都指向同一个驱动函数那就更像软件问题。3.3 内存专项测试的完整规程不是跑一圈就完事日志证据再充分最终确认还是要靠内存测试工具。推荐用memtest86这类开源内存完整性测试工具做成启动U盘后从U盘引导运行。注意这类测试必须在系统内存没有其它任务干扰的裸机环境下跑在操作系统内部拿stress压测内存是没有办法测出页表级硬件问题的因为操作系统本身已经掩盖了大量低级错误。我的做法是遵循一套固定规程先把服务器外设尽量拔掉只保留CPU、主板、一条测试内存、电源用最小系统跑测试将待测内存插到A1槽第一通道第一个槽位运行完整测试至少连续跑4轮也就是约1到2小时全部通过后关机把这条内存换到另一个槽位再跑4轮如果测试报错记录报错时的模式和地址报错地址随着内存条走就是内存颗粒坏了如果报错在换位后跟着槽位规律变化则要怀疑内存插槽或主板这套方法有个好处它不仅验证内存条本身同时验证插槽和内存控制器通道。我遇到过内存条明明没问题但固定某个槽位一插上去就报错的情况最后查出来是插槽针脚氧化这就不属于内存颗粒故障而是槽位问题。3.4 服务器品牌特有的远程管理手段BMC和SEL服务器不是台式机别只会拆开机箱看灯。带外管理通道是排查内存故障的利器。几乎所有服务器厂商都提供BMC基板管理控制器或类似的带外管理模块通过IPMI或Web管理界面可以查看SEL系统事件日志。SEL里通常记录了DIMM相关的硬件事件包括内存温度越限、电压异常、CE/UE事件。有些服务器还会把内存条的具体槽位编号直接写在事件描述里。登录BMC看一眼SEL可能比拆机箱更早知道答案。近几代数据中心平台还有ADDDC自适应动态内存重复部署这类内存纠错特性当某个内存颗粒频繁出错时内存控制器会自动把数据重新映射到备用行同时产生一条记录。遇到这类事件就说明这条内存虽然还能坚持运行但已经被硬件层标记成了老弱病残尽早安排更换比较稳妥。4. 驱动与固件背锅怎么证明不是硬件的错4.1 用RIP归属先圈定嫌疑范围排除内存之后就要把目光落到驱动和固件上。判断的第一步是看RIP符号落在哪。RIP如果直接显示在内核通用函数上比如do_anonymous_page、__alloc_pages_nodemask这类内存管理路径的通用函数并不能说明内存管理代码有问题更合理的解释是某个上层调用方传入了错误的参数或者访问了非法指针。这时候必须往上翻Call Trace找到真正发起调用的那个函数。Call Trace里只要出现带[某个模块]后缀的符号那个模块就是接下来重点关注对象。RIP如果直接标在某个驱动模块的函数上比如某个驱动模块的xxx0x4a [某个驱动模块]事情就简单多了嫌疑范围直接收敛到这个驱动。此时可以做三件事modinfo查看驱动模块的版本、作者、依赖、加载参数lsmod -v查看当前加载的驱动参数和模块间依赖关系/proc/modules看模块加载基地址跟崩溃日志里的地址做对照如果驱动来源是厂商自己打包的、和内核版本搭配也是厂商测试过的仍然发生崩溃那就优先怀疑固件与驱动版本不匹配。4.2 用crash工具解剖vmcore把犯罪现场还原出来保存了vmcore的情况下需要用crash这个工具做深入分析。它的全称是Linux内核崩溃转储分析工具可以读取vmcore和匹配的vmlinux调试符号文件。基本操作crash vmlinux-xxx vmcore进入交互式命令行后我通常按固定顺序执行bt查看崩溃任务的内核栈即调用链log把崩溃时刻内核环形缓冲区的日志完整倒出来mod -S加载模块符号让反汇编输出可读的模块函数名dis -l RIP地址反汇编RIP附近的代码rd 寄存器名读取寄存器值检查RIP对应的参数是否正常反汇编这一步特别有意思。有一次我处理某个网络驱动的panic反汇编出来发现RIP之前一步是把rdi指向的地址赋给某个寄存器然后从那个地址读取数据。再查寄存器rdi里存的竟是一个早已被释放的内存页地址。这种模块代码访问已释放内存的模式就是典型的use-after-free bug根因基本锁定在这个驱动上。没有vmcore也能排查但深度会差很远。没有vmcore时把RIP符号、模块版本、内核版本放在一起再去比对厂商的已知问题说明也常常能找到匹配的历史Bug记录。不过效率远不如直接拿crash看现场来得直接。4.3 驱动和固件升级的完整路径试、验、备回滚确认是驱动或固件问题的方向后实操路径一般是更新验证两步走。先记录当前基线版本lspci -k查看设备驱动版本ethtool -i查看网卡固件版本smartctl或控制器的管理工具查看NVMe固态硬盘和RAID卡的固件版本dmidecode查看BIOS版本。把所有版本号整理成表格然后去对应的发布说明里搜索崩溃日志中的模块名称和异常模式关键词。升级顺序建议先软件后固件同一设备先升级内核或驱动到目标版本观察是否复现如果无效再升级固件。固件升级存在风险尤其BIOS升级过程中断电会导致灾难性后果所以固件升级必须走维护窗口并且在带外管理界面监控。验证驱动的关键点不是在测试机上能启动就算过而是复现崩溃的触发条件。比如之前每次都在高并发网络收包时panic升级后就要用压测工具把流量打满跑48小时之前都在磁盘IO密集扫描时panic就专门跑IO风暴。让触发条件充分复现三五天内不出现原报错才能算阶段性验证通过。4.4 这些驱动类型最容易出鬼值得优先怀疑长期处理这类问题后我对几个类型的驱动保有高度警惕网卡驱动尤其开了多队列、硬件卸载特性、RDMA功能的网卡。这类驱动管理着复杂的环形缓冲区释放和重建队列时一旦指针错乱收包或发包路径随时可能触发paging requestNVMe控制器驱动现代NVMe设备有APST电源状态管理特性设备进入低功耗状态后如果固件和驱动的状态机不一致IO恢复时容易返回异常地址RAID/HBA卡驱动直通和透传模式下的DMA映射逻辑最复杂固件与驱动版本不匹配时会出现DMA地址失效GPU和加速卡驱动大块显存映射、pin page操作频繁驱动bug的触发率很高虚拟化直通设备设备通过vfio-pci直通给虚拟机后热迁移、设备复位路径上如果存在兼容性问题宿主机的panic只是时间问题遇到这些类型设备相关的paging request我的第一反应都不是内存坏了而是先把驱动版本、固件版本、触发场景三者对照起来找规律。5. 三个真实案例复盘从报警到最终结论我们到底做了什么5.1 数据库服务器的半夜panicPCIe AER与NVMe固件冲突案例背景某企业核心数据库服务器规格很高配置了多块NVMe固态硬盘。现象很规律每周大约一次panic时间窗口固定在凌晨备份任务IO高峰期。第一轮排查团队按惯例准备换内存。拆机、跑内存测试工具两轮全部通过换了备用内存条下一周照旧panic。这时才静下心翻完整日志发现两个关键线索崩溃日志里多次出现PCIe Bus Error: severityCorrected的AER记录同时panic的Call Trace尾部有NVMe相关模块符号。于是调整方向登录BMC查看SEL没有DIMM硬件事件再看PCIe AER记录报错设备号对应到某块NVMe固态硬盘。随后查该型号固态硬盘的固件发布说明在已知问题里找到一条与本服务器内核版本驱动组合高度吻合的描述。按建议升级NVMe固件和内核驱动后持续观察三周panic未再出现。这个案例的启示很直接出现paging request不等于内存故障PCIe AER先兆是硬件链路层的重要风向标。5.2 大数据集群节点的随机重启这次真的坏了一条内存案例背景某大数据集群多台节点偶发死机迁移任务频繁中断还有业务进程随机报段错误。这轮日志证据非常典型journalctl -k里MCE记录几乎每次重启都有EDAC的ce_count在几天内从几百涨到几万并且错误集中在同一个内存控制器的同一个通道。再叠加另一些细节同一节点上多个容器被kill时各业务日志里分散着校验和不一致的问题类似症状同时在多台上出现这是内存位翻转在多进程投影的典型表现。定级为内存硬件故障后按最小系统规程跑内存测试工具果然在对应通道的DIMM上报错。A/B插换验证后错误始终跟随其中一条内存条换掉它之后一个月内无复现CE计数归零。值得强调的是这台机器并不是突然panic才坏事此前已有一周左右的慢性症状比如偶发段错误、任务失败率上升。如果日常巡检中注意EDAC计数变化完全可以提前一天完成替换把故障窗口缩到最小。5.3 虚拟化宿主机的怪事热迁移后直通设备panic案例背景某虚拟化宿主机配置了GPU直通虚拟化把GPU通过vfio-pci直通给虚拟机使用。故障现象比较奇怪日常运行一切正常但每次对特定虚拟机执行热迁移操作后宿主机就有概率panic报错内容是paging requestRIP位于直通设备复位相关的路径附近。日志排查结果无MCE、无EDAC记录、无PCIe AER报错BMC SEL干净。但崩溃触发点的规律性极强每次都发生在热迁移动作后可复现概率高。这种有明确操作才能触发的特征基本排除了硬件问题指向虚拟化层与内核版本之间的兼容性bug。接着做了三件事在测试机上复现同样操作确认必现把内核版本回退到上一个发布版本热迁移后不再panic随后将虚拟化平台软件和内核一起升级到修复版本压测多轮后故障消失。这属于典型的软件兼容性问题靠换硬件永远解决不了。6. 长期对策把半夜的panic变成一次普通工单6.1 开好kdump让崩溃现场永远留底所有经验里最想敲黑板的就是把kdump配置好。没有vmcore一切深入分析都是盲人摸象。配置要点也很简单预留一块crashkernel内存、指定转储文件保存路径、确保目录有足够磁盘空间。配置完成后可以用echo c /proc/sysrq-trigger触发一次内核panic来验证转储是否成功不过这个操作会把机器搞重启务必选择维护窗口执行。另外建议开启网络日志转发把内核日志实时发到集中日志服务器。这样即使本机磁盘损坏日志也不丢。6.2 建立系统健康基线和巡检习惯不要等机器panic了才去查日志。每周巡检一次如下指标能赶在硬件故障造成严重后果前发现苗头grepdmesg里MCE、EDAC相关记录数量检查/sys/devices/system/edac/mc/mc*/ce_count的变化幅度检查dmesg里PCIe AER错误是否增长用存储管理工具查看NVMe设备错误计数把这些数字记录下来形成基线和上周比和上月比趋势比绝对数值更有预警价值。一台机器weekly ce_count从个位数跳到四位数不用等panic出现直接可以开硬件报修单了。6.3 变更管理驱动固件升级的操练顺序驱动和固件不是不能动而是要有纪律地动。我的建议顺序是先在测试机上升级并用触发条件复现验证再在低峰期灰度一台生产机观察48小时确认无异常后全量发布。每一次变更都要记录新旧版本号和验证结果方便未来做反向对照。不要在没有回滚方案的前提下动BIOS这类底层固件尤其不要在远程运维且无人值守的深夜窗口动它。6.4 备件与应急处置的最小清单机房至少准备一条与主力机器相同规格的内存条、一块备用的NVMe/SSD、一条网卡以及必要的SFP模块和光纤。故障处理遵循一次只换一个变量的铁律换了一根内存只测内存换了驱动只测驱动不要同时把内存、CPU、主板一起全换掉。否则如果问题复现你根本不知道是哪一项改动起了作用。我在处理过二十余起同类panic之后做了个简单统计真正由内存硬件直接导致的比例大约六成剩余四成里绝大多数是驱动或固件兼容性问题。但有趣的是前期处理时间最长的恰恰是那些一开始就默认内存故障的case。最深的体会是unable to handle kernel paging request这行报错更像一封邀请函邀请你把日志读完整再动手。养成三个习惯保存vmcore、完整读一遍dmesg、坚持每月记录硬件健康基线这个报错就会从灾难退回为普通工单。最后分享一个小技巧跑内存测试工具前把网络、磁盘、加速卡等外设尽量拔掉用最小系统先跑一轮往往能直接跳过大量干扰因素节省至少半天的排查时间。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑