6

动机

我正在努力提高我对Xwayland 中的 SIGBUS 错误的理解。自 2018 年 2 月 20 日左右以来,一些 Fedora Linux 用户已经看到了这种情况,使用Xwayland 1.19.6-5.fc27.x86_64Linux 内核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 测试时没有错误。不幸的是,我似乎很少有嫌疑人。最接近怀疑我有一个内核升级,我显然更愿意排除它;日期并不能完全证明这一点,但也不能完全排除。最接近日期的是今年的微码更新;这似乎更难确定。

次要页面错误的已知原因

  1. 从逻辑上讲,在为 MAP_PRIVATE 映射实现写时复制时,这听起来像是发生了轻微的页面错误。
  2. 它还应该包括 /dev/zero 或 MAP_ANONYMOUS 上的读取错误,假设内核没有它们实现为读取共享零页面并且没有实现它们以立即为整个映射分配页面。
  3. 但更一般地说,它可以是对页面的任何首次访问。这是因为似乎内存映射的页表通常是按需填充的。(这将由页面错误完成,如果文件页面已经在缓存中,则它只是一个次要的页面错误)。

    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
4

2 回答 2

4

我当然在内核中有一些错误,除非它是内核自测中的错误。

编辑:嗯,实际上似乎其他人最近也注意到了 GS 自测失败,但它已经存在于较旧的内核中,并且也出现在 AMD cpus 上。目前似乎还没有关于如何修复它的结论。 https://lkml.org/lkml/2018/1/26/436

所以它本身不是这个错误,尽管我不能排除这个 GS 错误在启用 PTI 或其他东西时会导致更明显的损坏。

$ uname -r
4.15.10-300.fc27.x86_64

$ git describe --all
heads/4.15.10
$ cat ./Documentation/x86/pti.txt
...
2. Run several copies of all of the tools/testing/selftests/x86/ tests
   (excluding MPX and protection_keys) in a loop on multiple CPUs for
   several minutes.  These tests frequently uncover corner cases in the
   kernel entry code.  In general, old kernels might cause these tests
   themselves to crash, but they should never crash the kernel.

$ cd tools/testing/selftests/x86
$ make
...

在 4x 终端中匹配我的 4x 硬件线程:

sh -c ' while true; do for i in *; do if test -x $i; then ./$i || exit; fi ; done; done '

故障很快出现:

[RUN]   ARCH_SET_GS(0x200000000), then schedule to 0x200000000
    Before schedule, set selector to 0x3
    other thread: ARCH_SET_GS(0x200000000) -- sel is 0x0
[FAIL]  GS/BASE changed from 0x3/0x0 to 0x0/0x0

[RUN]   Executing 6-argument 32-bit syscall via VDSO
[WARN]  Flags before=0000000000200ed7 id 0 00 o d i s z 0 a 0 p 1 c
[WARN]  Flags  after=0000000000200682 id 0 00 d i s 0 0 1 
[WARN]  Flags change=0000000000000855 0 00 o z 0 a 0 p 0 c
[OK]    Arguments are preserved across syscall
[NOTE]  R11 has changed:0000000000200682 - assuming clobbered by SYSRET insn
[OK]    R8..R15 did not leak kernel data
[RUN]   Executing 6-argument 32-bit syscall via INT 80
[OK]    Arguments are preserved across syscall
[OK]    R8..R15 did not leak kernel data
[RUN]   Running tests under ptrace
[RUN]   Executing 6-argument 32-bit syscall via VDSO
[WARN]  Flags before=0000000000200ed7 id 0 00 o d i s z 0 a 0 p 1 c
[WARN]  Flags  after=0000000000200686 id 0 00 d i s 0 0 p 1 
[WARN]  Flags change=0000000000000851 0 00 o z 0 a 0 0 c
[OK]    Arguments are preserved across syscall
[NOTE]  R11 has changed:0000000000200686 - assuming clobbered by SYSRET insn
[OK]    R8..R15 did not leak kernel data
[RUN]   Executing 6-argument 32-bit syscall via INT 80
[OK]    Arguments are preserved across syscall
[OK]    R8..R15 did not leak kernel data
Warning: failed to find getcpu in vDSO
[RUN]   Testing getcpu...
[OK]    CPU 0: syscall: cpu 0, node 0
[OK]    CPU 1: syscall: cpu 1, node 0
[OK]    CPU 2: syscall: cpu 2, node 0
[OK]    CPU 3: syscall: cpu 3, node 0
[RUN]   Testing getcpu...
[OK]    CPU 0: syscall: cpu 0, node 0 vdso: cpu 0, node 0 vsyscall: cpu 0, node 0
[OK]    CPU 1: syscall: cpu 1, node 0 vdso: cpu 1, node 0 vsyscall: cpu 1, node 0
[OK]    CPU 2: syscall: cpu 2, node 0 vdso: cpu 2, node 0 vsyscall: cpu 2, node 0
[OK]    CPU 3: syscall: cpu 3, node 0 vdso: cpu 3, node 0 vsyscall: cpu 3, node 0
[NOTE]  failed to find getcpu in vDSO
[RUN]   test gettimeofday()
    vDSO time offsets: 0.000006 0.000000
[OK]    vDSO gettimeofday()'s timeval was okay
[RUN]   test time()
[FAIL]  vDSO returned the wrong time (1522063297 1522063296 1522063297)
于 2018-03-26T11:32:31.957 回答
1

感谢大家的支持。这确实是一个短暂的 IO 错误。看起来 SIGBUS 读取故障路径不一定会在内核日志中记录任何内容,这与我习惯于看到 IO 错误的情况不同。

https://marc.info/?l=linux-ide&m=152232081917215&w=2

v4.15 暂停/恢复时出现间歇性错误

对于任何等待其他节目放弃 SATA LPM 工作的人...

我发现了至少在同一区域的东西。两天前它在我的系统上触发了 fsck。有证据表明它发生在许多其他机器上。我觉得这足以让你注意了:)。

我检查了一下,我似乎没有在运行时启用 LPM,即使在使用电池运行时也是如此。我的错误都在暂停/恢复,所以也许这种行为同时改变了?

它并不总是显示在内核日志中。我首先注意到的是一个神秘的 SIGBUS,它会在从挂起状态恢复时杀死 Xwayland(以及整个 Gnome 会话)。令我惊讶的是,这种 SIGBUS 可以发生,而不会留下任何像我习惯在内核日志中看到的读取错误!

我的核心转储显示 SIGBUS 故障地址是在 Xwayland 程序代码中读取的指令。回溯沿着同一个调用链变化——共同的因素是它们总是在函数的第一条指令处。我认为它会根据当前不在核心的页面而有所不同,因此会触发失败的读取请求。

在这条相同的调用链上有数百条来自其他用户的回溯,它们会自动报告给 Fedora,看起来都一样。至少到目前为止,我们对它们没有更多的合理性。我承认 Xwayland 如此突出很有趣,而且我在其他进程中没有被 SIGBUS 淹没,但我支持这个分析。

这些崩溃是在 Fedora 升级到内核 v4.15 后的 24 小时内开始的。

Xwayland SIGBUS 的 Fedora 错误: https ://bugzilla.redhat.com/show_bug.cgi?id=1553979

我的重复错误我一直在向令人困惑的评论发送垃圾邮件: https ://bugzilla.redhat.com/show_bug.cgi?id=1557682

许多崩溃报告桶中最早和最大的:

EXT4 文件系统错误:

Mar 27 11:28:30 alan-laptop kernel: PM: suspend exit
...
Mar 27 11:28:30 alan-laptop kernel: EXT4-fs error (device dm-2):  ext4_find_entry:1436: inode #5514052: comm thunderbird: reading directory lblock 0
Mar 27 11:28:30 alan-laptop kernel: Buffer I/O error on dev dm-2, logical block 0, lost sync page write
(this marked the FS as needing fsck on next boot)

更频繁地,它会记录这些交换错误:

Mar 02 18:47:03 alan-laptop kernel: Restarting tasks ...
Mar 02 18:47:03 alan-laptop kernel: Read-error on swap-device (253:1:836184)
Mar 02 18:47:06 alan-laptop kernel: Read-error on swap-device (253:1:580280)

我的笔记本电脑 LPM 状态,即使在移除交流电源后:

$ head /sys/class/scsi_host/host*/link_power_management_policy
==> /sys/class/scsi_host/host0/link_power_management_policy <==
max_performance

==> /sys/class/scsi_host/host1/link_power_management_policy <==
max_performance

我的笔记本电脑是戴尔 Latitude E5450。CPU 是 i5-5300U(Broadwell)。

于 2018-03-29T11:04:49.437 回答