动机
我正在努力提高我对Xwayland 中的 SIGBUS 错误的理解。自 2018 年 2 月 20 日左右以来,一些 Fedora Linux 用户已经看到了这种情况,使用Xwayland 1.19.6-5.fc27.x86_64
Linux 内核4.15.3-300.fc27.x86-64
。
遗憾的是,我没有内核“segfault”日志消息(或 SIGBUS 的等价物)。Xwayland 有一些毫无意义的代码可以捕获致命信号。但是我可以siginfo
通过调试 coredump 看到,这似乎几乎一样好。
定义
我了解当 RAM 中的一页虚拟内存不可用且必须从磁盘读取时,会发生“重大页面错误”。对于这个问题,我想我对由 ext4 文件系统支持的页面(例如,不能直接访问块设备)特别感兴趣。
因此,“次要页面错误”是指无需访问磁盘。我认为差异是相当明确的,因为 Linux 公开了主要和次要页面错误的计数器。
我的问题
如果内核发送一个程序 SIGBUS,我想知道我是否应该普遍认为这将是一个主要的页面错误。
根据 coredump 和反汇编,程序在接收到 SIGBUS 时是在读取内存,而不是在写入。中的故障地址位于siginfo->si_addr
映射的系统可执行文件中,用户不可写入,并且该地址似乎在当前文件长度的范围内。事实上,在调试 coredump 时,我已经从内存地址中读取了非常有说服力的值。看起来核心转储生成过程读取这个地址没有困难:-(。
我也有信心排除“无效地址对齐”情况(BUS_ADRALN),因为siginfo->si_code
是2,即BUS_ADRERR,“不存在的物理地址”。还因为我在 x86 上,在大多数情况下允许未对齐的访问,并且陷阱不在任何 SSE 扩展指令中。
我考虑了内核在处理它确定为“次要”的页面错误时通常负责的内容。我想小故障可能无法分配内存,因此会引发 SIGBUS。但是,我相信我会注意到这样的分配失败:
我有足够的免费交换空间来驱逐用户页面,我没有注意到当我的系统开始交换时通常会出现明显的减速。崩溃发生在将笔记本电脑从挂起状态唤醒到 ram 后几秒钟,即使在 ~100MB/s 的情况下,这也不足以填充 8GB 的交换空间。我也没有看到内核日志中出现可怕的内存不足 (OOM) 杀手,正如我所期望的,如果内核未能分配页框或页表。
是否存在其他一些可能导致轻微页面错误失败并导致 SIGBUS 的可能性?即在内核日志中查找错误时,是否有一些我不会注意到的原因?哪个可以快速发作?
同样,多个 coredump 将其显示为通过从文件系统上的映射文件读取而触发的页面错误。
不可告人的动机
我真的很想错过一个小页面错误的案例。因为这可怕的另一面是我不明白这个 SIGBUS 是如何由硬页面错误方面引起的。从几个月前开始,我们中的一些用户出现了看起来非常相似的错误。我的内核日志中没有 IO 错误。在正常操作期间,读取指示的文件时没有 IO 错误。rpm --verify --all
运行时或在 HDD 上运行扩展 SMART 测试时没有错误。不幸的是,我似乎很少有嫌疑人。最接近的怀疑我有一个内核升级,我显然更愿意排除它;日期并不能完全证明这一点,但也不能完全排除。最接近日期的是今年的微码更新;这似乎更难确定。
次要页面错误的已知原因
- 从逻辑上讲,在为 MAP_PRIVATE 映射实现写时复制时,这听起来像是发生了轻微的页面错误。
- 它还应该包括 /dev/zero 或 MAP_ANONYMOUS 上的读取错误,假设内核没有将它们实现为读取共享零页面并且没有实现它们以立即为整个映射分配页面。
但更一般地说,它可以是对页面的任何首次访问。这是因为似乎内存映射的页表通常是按需填充的。(这将由页面错误完成,如果文件页面已经在缓存中,则它只是一个次要的页面错误)。
MAP_NONBLOCK(自 Linux 2.5.46 起)
此标志仅与 MAP_POPULATE 一起有意义。不要执行预读:仅为已存在于 RAM 中的页面创建页表条目。从 Linux 2.6.23 开始,这个标志会导致 MAP_POPULATE 什么都不做。有一天,MAP_POPULATE 和 MAP_NONBLOCK 的组合可能会被重新实现。
编辑:进一步摘录详细说明上述内容
一位评论者要求提供更具体的细节,以澄清故障地址和说明。初始链接中有很多摘录https://bugzilla.redhat.com/show_bug.cgi?id=1557682
故障因错误链接中所述而异。以下是最近一个例子的新鲜摘录。
$ gdb 2018-03-21.core
...
Core was generated by `/usr/bin/Xwayland :0 -rootless -terminate -core -listen 4 -listen 5 -displayfd'.
Program terminated with signal SIGBUS, Bus error.
#0 _dl_fixup (l=0x7fc0be2e0130, reloc_arg=203) at ../elf/dl-runtime.c:73
73 const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
[Current thread is 1 (Thread 0x7fc0be29fa80 (LWP 1918))]
(gdb) p $_siginfo.si_signum
$1 = 7
(gdb) p $_siginfo.si_code
$2 = 2
(gdb) p $_siginfo._sifields._sigfault.si_addr
$3 = (void *) 0x41bd80
(gdb) disassemble
Dump of assembler code for function _dl_fixup:
0x00007fc0be0c8bd0 <+0>: push %rbx
0x00007fc0be0c8bd1 <+1>: mov %rdi,%r10
0x00007fc0be0c8bd4 <+4>: mov %esi,%esi
0x00007fc0be0c8bd6 <+6>: lea (%rsi,%rsi,2),%rdx
0x00007fc0be0c8bda <+10>: sub $0x10,%rsp
0x00007fc0be0c8bde <+14>: mov 0x68(%rdi),%rax
0x00007fc0be0c8be2 <+18>: mov 0x8(%rax),%rdi
0x00007fc0be0c8be6 <+22>: mov 0xf8(%r10),%rax
0x00007fc0be0c8bed <+29>: mov 0x8(%rax),%rax
0x00007fc0be0c8bf1 <+33>: lea (%rax,%rdx,8),%r8
0x00007fc0be0c8bf5 <+37>: mov 0x70(%r10),%rax
=> 0x00007fc0be0c8bf9 <+41>: mov 0x8(%r8),%rcx
(gdb) p/x $r8
$4 = 0x41bd78
(gdb) p/x $r8 + 8
$5 = 0x41bd80
reloc->r_info
请注意,此指令根据突出显示的源代码行获取值。
(gdb) p reloc
$6 = (const Elf64_Rela * const) 0x41bd78
(gdb) p &reloc->r_info
$7 = (Elf64_Xword *) 0x41bd80
(gdb) p *reloc
$8 = {r_offset = 8443504, r_info = 936302870535, r_addend = 0}
错误地址属于下面的文本映射(来自maps
捕获的文件abrtd
):
00400000-0060b000 r-xp 00000000 fd:00 1708508 /usr/bin/Xwayland
0080a000-0080d000 r--p 0020a000 fd:00 1708508 /usr/bin/Xwayland
0080d000-00817000 rw-p 0020d000 fd:00 1708508 /usr/bin/Xwayland
$ size -x /usr/bin/Xwayland
text data bss dec hex filename
0x209ffb 0xbe9d 0x1f3e0 2314872 235278 /usr/bin/Xwayland