O_TRUNC 写入 /proc 文件系统时被忽略

O_TRUNC ignored when writing to the /proc filesystem

尝试通过使用
清除/proc/sys/kernel/core_pattern来摆脱Ubuntu的apport sh -c ': > /proc/sys/kernel/core_pattern' 无效。

看起来 O_TRUNC 标志在写入 /proc 文件系统时被忽略了:

echo nonsense >| /proc/sys/kernel/core_pattern
strace sh -c ': > /proc/sys/kernel/core_pattern  # do not call apport'
...
openat(AT_FDCWD, "/proc/sys/kernel/core_pattern", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
...
close(3)                                = 0

cat /proc/sys/kernel/core_pattern
nonsense

在常规文件系统而不是 /proc 文件系统中执行此操作时,我得到一个空文件。

这是内核错误还是功能,甚至可能是有文档记录的错误?

编辑: 通过 sysctl 清除此设置不起作用:

sysctl kernel.core_pattern=""
sysctl: malformed setting "kernel.core_pattern="

似乎 sysctl 程序无法清除任何内核参数,而 man core 明确描述了使用空值来禁用该机制。

是的,echo >| /proc/sys/kernel/core_pattern 可以代替,但是这个问题的目的是找出这是否是内核错误,而不是寻找解决方法。

这是因为 open* 系列系统调用的 O_TRUNC 标志仅更新与打开的文件关联的 inode 的大小。此更改是在找到 inode 之后和最终确定由任何内核 module/driver/subsystem(例如 sysctl 子系统)实现的 struct file that is then used by the kernel for any actual operation on the opened file. Truncation is performed before the call to any ->open() file_operations 处理程序之前执行的,因此对处理程序是透明的。

换句话说,虚拟 sysctl files (e.g. /proc/sys/kernel/*) merely see a file with a 0 (zero) size (->i_size field of struct inode) 的 file_operations 处理程序不知道这是截断的结果还是“正常”open,也不知道他们应该需要这样的信息。

由于 sysctl 文件(就像几乎所有的 procfs 文件一样)出于可以理解的原因并没有真正打扰跟踪大小,它们的功能仅根据 readwrite 系统调用(也不会以任何方式更新大小)。

确实,使用: > PATH只会做open + close,而简单的echo > PATH会在打开后write一个换行符,因此你观察两种不同的结果。您会观察到与使用 truncate -s 0 PATH : > PATH 相同的行为,尽管这次截断是在通过 ftruncate 打开后明确完成的(至少在我的系统上是这样)。

man core explicitly describes that an empty value is used to disable the mechanism

[...]

Is that a kernel bug or a feature, perhaps even a documented one?

procfs 下的人类 readable/writable 文件通常被设计为以面向行的方式工作,所以我假设这里的术语“空”仅仅意味着选项的值因此为空向文件写入一个空行。如果有的话,我会将其称为未记录的功能而不是错误。


这是我系统上的一些示例跟踪:

root@xxx:~# cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P %E
root@xxx:~# strace -f -e openat,write,close,dup2 sh -c ': > /proc/sys/kernel/core_pattern'
...
openat(AT_FDCWD, "/proc/sys/kernel/core_pattern", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
close(1)                                = 0
dup2(3, 1)                              = 1
close(3)                                = 0
...
+++ exited with 0 +++
root@xxx:~# cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P %E
root@xxx:~#
root@xxx:~# cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P %E
root@xxx:~# strace -f -e openat,write,close,dup2 sh -c 'echo > /proc/sys/kernel/core_pattern'
...
openat(AT_FDCWD, "/proc/sys/kernel/core_pattern", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
close(1)                                = 0
dup2(3, 1)                              = 1
close(3)                                = 0
write(1, "\n", 1)                       = 1
...
+++ exited with 0 +++
root@xxx:~# cat /proc/sys/kernel/core_pattern

root@xxx:~#

如果您想查看 sysfs 文件的 open/read/write/close 的实际实现,您可以查看 /kernel/sysctl.c. There are different tables present for different sysctl facilities e.g. kernel, vm,等等