【问题标题】:O_TRUNC ignored when writing to the /proc filesystem写入 /proc 文件系统时忽略 O_TRUNC
【发布时间】:2021-10-18 16:51:45
【问题描述】:

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

看起来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 可以代替,但这个问题的目的是找出这是否是内核错误,而不是找到解决方法。

【问题讨论】:

  • 尝试将零长度缓冲区写入文件。如果这不起作用,请尝试只写一个换行符。
  • 顺便说一句,修改/proc/sys/文件的常用方法是使用sysctl命令。例如。 sudo sysctl kernel.core_pattern=.
  • /proc 上的文件有点奇怪,因为它们的内容是动态生成的,它们的大小被列为 0。
  • @IanAbbott,刚刚编辑了问题以表明 sysctl 在这里不起作用。但这无论如何都不是问题的对象。
  • 可以说,由于文件的大小为 0(如 stat 所示),因此无法截断。

标签: linux-kernel system-calls procfs sysctl


【解决方案1】:

这是因为open* 系列系统调用的O_TRUNC 标志仅更新与打开的文件关联的inode 的大小。此更改在找到 inode 之后和最终确定 struct file 之前执行,然后内核将使用该 struct file 对打开的文件进行任何实际操作。截断是在调用任何内核模块/驱动程序/子系统(例如 sysctl 子系统)实现的任何 ->open() file_operations 处理程序之前执行的,因此对处理程序是透明的。

换句话说,虚拟sysctl files(例如/proc/sys/kernel/*)的file_operations处理程序只看到一个大小为0(零)的文件(->i_size字段struct inode),他们不知道这是截断的结果还是“正常”open 的结果,他们也不应该需要此类信息。

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

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

man core 明确描述了使用空值来禁用该机制

[...]

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

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


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

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:~#

如果你想看看open/read/write/close sysfs 文件的实际实现,你可以查看/kernel/sysctl.c。不同的 sysctl 设施有不同的表,例如kernelvm

【讨论】:

  • 所以我断定这是man core 中的一个文档错误:空意味着空行,而不是空文件。干得好,顺便说一句。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-20
  • 2020-11-22
  • 2019-04-07
相关资源
最近更新 更多