lar*_*sks 60 fedora kernel inotify
在最近升级到 Fedora 15 后,我发现许多工具失败并出现以下错误:
tail: inotify resources exhausted
tail: inotify cannot be used, reverting to polling
Run Code Online (Sandbox Code Playgroud)
这不仅仅是tail报告 inotify 的问题。有没有办法询问内核以找出正在消耗 inotify 资源的进程?当前与 inotify 相关的sysctl设置如下所示:
fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.inotify.max_queued_events = 16384
Run Code Online (Sandbox Code Playgroud)
Pet*_*zel 44
似乎如果进程通过 inotify_init() 创建 inotify 实例,则在 /proc 文件系统中表示文件描述符的结果文件是(不存在的)“anon_inode:inotify”文件的符号链接。
$ cd /proc/5317/fd
$ ls -l
total 0
lrwx------ 1 puzel users 64 Jun 24 10:36 0 -> /dev/pts/25
lrwx------ 1 puzel users 64 Jun 24 10:36 1 -> /dev/pts/25
lrwx------ 1 puzel users 64 Jun 24 10:36 2 -> /dev/pts/25
lr-x------ 1 puzel users 64 Jun 24 10:36 3 -> anon_inode:inotify
lr-x------ 1 puzel users 64 Jun 24 10:36 4 -> anon_inode:inotify
Run Code Online (Sandbox Code Playgroud)
除非我误解了这个概念,否则以下命令应该显示进程列表(它们在 /proc 中的表示),按它们使用的 inotify 实例的数量排序。
$ for foo in /proc/*/fd/*; do readlink -f $foo; done | grep inotify | sort | uniq -c | sort -nr
Run Code Online (Sandbox Code Playgroud)
通过@markkcowan下面的评论提到了这一点:
$ find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -exec sh -c 'cat $(dirname {})/../cmdline; echo ""' \; 2>/dev/null
Run Code Online (Sandbox Code Playgroud)
oli*_*ren 31
正如@Jonathan Kamens 所说,您的手表可能快用完了。我有一个预制脚本, inotify-consumers,它为您列出了最严重的罪犯(较新的版本还列出了拥有该进程的用户名,见下文):
$ time inotify-consumers
INOTIFY
WATCHER
COUNT PID CMD
----------------------------------------
6688 27262 /home/dvlpr/apps/WebStorm-2018.3.4/WebStorm-183.5429.34/bin/fsnotifier64
411 27581 node /home/dvlpr/dev/kiwi-frontend/node_modules/.bin/webpack --config config/webpack.dev.js
79 1541 /usr/lib/gnome-settings-daemon/gsd-xsettings
30 1664 /usr/lib/gvfs/gvfsd-trash --spawner :1.22 /org/gtk/gvfs/exec_spaw/0
14 1630 /usr/bin/gnome-software --gapplication-service
....
7489 watches TOTAL COUNT
real 0m0.099s
user 0m0.042s
sys 0m0.062s
Run Code Online (Sandbox Code Playgroud)
在这里你很快就会明白为什么 8K 手表的默认限制在开发机器上太少了,因为当遇到一个node_modules包含数千个文件夹的文件夹时,WebStorm 实例很快就会达到最大值。添加一个 webpack watcher 来保证问题......
尽管它比我最初制作时的其他替代方案快得多,但 Simon Matter 为重载的 Big Iron Linux(数百个内核)添加了一些速度增强功能,极大地加快了速度,将其从 10 分钟(!)减少到 15 分钟在他的怪物装备上的几秒钟。
inotify-consumers --help 为了得到它你的机器上,只需要复制该脚本的内容并把它放在你的$PATH一样/usr/local/bin。或者,如果您信任网络上的这个陌生人,您可以避免复制它并通过 http 将其通过管道传输到 bash:
$ curl -s https://raw.githubusercontent.com/fatso83/dotfiles/master/utils/scripts/inotify-consumers | bash
INOTIFY
WATCHER
COUNT PID USER COMMAND
--------------------------------------
3044 3933 myuser node /usr/local/bin/tsserver
2965 3941 myuser /usr/local/bin/node /home/myuser/.config/coc/extensions/node_modules/coc-tsserver/bin/tsserverForkStart /hom
979 3954 myuser /usr/local/bin/node /home/myuser/.config/coc/extensions/node_modules/coc-tsserver/node_modules/typescript/li
1 7473 myuser /usr/local/bin/node --no-warnings /home/myuser/dev/dotfiles/common-setup/vim/dotvim/plugged/coc.nvim/build/i
1 3899 myuser /usr/local/bin/node --no-warnings /home/myuser/dev/dotfiles/common-setup/vim/dotvim/plugged/coc.nvim/build/i
6990 watches TOTAL COUNT
Run Code Online (Sandbox Code Playgroud)
作为参考,脚本的主要内容就是这个(灵感来自这个答案)
find /proc/*/fd \
-lname anon_inode:inotify \
-printf '%hinfo/%f\n' 2>/dev/null \
\
| xargs grep -c '^inotify' \
| sort -n -t: -k2 -r
Run Code Online (Sandbox Code Playgroud)
如果您想知道如何增加限制
$ inotify-consumers --limits
Current limits
-------------
fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 524288
Changing settings permanently
-----------------------------
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p # re-read config
Run Code Online (Sandbox Code Playgroud)
小智 27
您可能用完了 inotify手表而不是实例。要找出谁制造了大量手表:
$ echo 1 > /sys/kernel/debug/tracing/events/syscalls/sys_exit_inotify_add_watch/enable`
Run Code Online (Sandbox Code Playgroud)
tracing_ons 为 1:$ cat /sys/kernel/debug/tracing/tracing_on
0
$ echo 1 > /sys/kernel/debug/tracing/tracing_on
Run Code Online (Sandbox Code Playgroud)
$ cat /sys/kernel/debug/tracing/current_tracer
nop
$ cat /sys/kernel/debug/tracing/set_ftrace_filter
#### all functions enabled ####
$ echo function > /sys/kernel/debug/tracing/current_tracer
$ echo SyS_inotify_add_watch > /sys/kernel/debug/tracing/set_ftrace_filter
Run Code Online (Sandbox Code Playgroud)
/sys/kernel/debug/tracing/trace以查看创建了多少个监视以及由哪些进程创建。完成后,请确保echo 0进入启用文件(以及如果您必须启用该文件,则还包括 trace_on 文件)以关闭跟踪,这样您就不会因继续跟踪而导致性能下降。
注意:在旧版本的 Linux 内核中,/sys端点曾经被称为tracing_enabled,但现在称为tracing_on。如果您发现您使用的是较旧版本的内核,请更改/sys/kernel/debug/tracing/tracing_on为/sys/kernel/debug/tracing/tracing_enabled.
小智 13
刚刚编写了一个 C++ 应用程序来帮助跟踪 inotify 信息。应该能够显示摘要信息以及监视的文件和目录。
https://github.com/mikesart/inotify-info
希望能够帮助找出限制是什么以及在哪里受到限制。
小智 6
要跟踪哪个进程占用inotify的手表(没有实例),你可以使用内核的动态ftrace功能,如果它在你的内核中启用。
您需要的内核选项是CONFIG_DYNAMIC_FTRACE.
如果尚未安装,请先安装 debugfs 文件系统。
mount -t debugfs nodev /sys/kernel/debug
Run Code Online (Sandbox Code Playgroud)
转到tracing这个 debugfs 目录的子目录下
cd /sys/kernel/debug/tracing
Run Code Online (Sandbox Code Playgroud)
启用函数调用跟踪
echo function > current_tracer
Run Code Online (Sandbox Code Playgroud)
仅过滤SyS_inotify_add_watch系统调用
echo SyS_inotify_add_watch > set_ftrace_filter
Run Code Online (Sandbox Code Playgroud)
如果不为空,则清除跟踪环缓冲区
echo > trace
Run Code Online (Sandbox Code Playgroud)
如果尚未启用,请启用跟踪
echo 1 > tracing_on
Run Code Online (Sandbox Code Playgroud)
重新启动可疑进程(在我的情况下它是 crashplan,一个备份应用程序)
观察 inotify_watch 耗尽
wc -l trace
cat trace
Run Code Online (Sandbox Code Playgroud)
完毕
我遇到了这个问题,这些答案都没有给你“每个进程当前使用多少个手表?”的答案。one-liners 都会告诉你有多少实例打开,这只是故事的一部分,trace 的东西只对看到新手表打开有用。
TL;DR:这将为您提供一个文件,其中包含打开的inotify实例列表和它们拥有的监视数量,以及产生它们的 pid 和二进制文件,按监视计数降序排序:
sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); exe=$(sudo readlink $(dirname $(dirname $fdi))/exe); echo -e $count"\t"$fdi"\t"$exe; done | sort -nr > watches
Run Code Online (Sandbox Code Playgroud)
这是一团乱麻,所以这就是我到达那里的方式。首先,我运行了tail一个测试文件,并查看了它打开的文件:
joel@gladstone:~$ tail -f test > /dev/null &
[3] 22734
joel@opx1:~$ ls -ahltr /proc/22734/fd
total 0
dr-xr-xr-x 9 joel joel 0 Feb 22 22:34 ..
dr-x------ 2 joel joel 0 Feb 22 22:34 .
lr-x------ 1 joel joel 64 Feb 22 22:35 4 -> anon_inode:inotify
lr-x------ 1 joel joel 64 Feb 22 22:35 3 -> /home/joel/test
lrwx------ 1 joel joel 64 Feb 22 22:35 2 -> /dev/pts/2
l-wx------ 1 joel joel 64 Feb 22 22:35 1 -> /dev/null
lrwx------ 1 joel joel 64 Feb 22 22:35 0 -> /dev/pts/2
Run Code Online (Sandbox Code Playgroud)
所以,4 是我们要调查的 fd。让我们看看里面有什么fdinfo:
joel@opx1:~$ cat /proc/22734/fdinfo/4
pos: 0
flags: 00
mnt_id: 11
inotify wd:1 ino:15f51d sdev:ca00003 mask:c06 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:1df51500a75e538c
Run Code Online (Sandbox Code Playgroud)
这看起来像是底部手表的条目!
让我们用更多的手表尝试一些东西,这次是使用inotifywait实用程序,只看里面的内容/tmp:
joel@gladstone:~$ inotifywait /tmp/* &
[4] 27862
joel@gladstone:~$ Setting up watches.
Watches established.
joel@gladstone:~$ ls -ahtlr /proc/27862/fd | grep inotify
lr-x------ 1 joel joel 64 Feb 22 22:41 3 -> anon_inode:inotify
joel@gladstone:~$ cat /proc/27862/fdinfo/3
pos: 0
flags: 00
mnt_id: 11
inotify wd:6 ino:7fdc sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:dc7f0000551e9d88
inotify wd:5 ino:7fcb sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:cb7f00005b1f9d88
inotify wd:4 ino:7fcc sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:cc7f00006a1d9d88
inotify wd:3 ino:7fc6 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:c67f00005d1d9d88
inotify wd:2 ino:7fc7 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:c77f0000461d9d88
inotify wd:1 ino:7fd7 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:d77f00000053c98b
Run Code Online (Sandbox Code Playgroud)
啊哈!更多条目!所以我们应该有六件事/tmp:
joel@opx1:~$ ls /tmp/ | wc -l
6
Run Code Online (Sandbox Code Playgroud)
优秀。我的新产品在其列表中inotifywait有一个条目fd(这是这里的其他 one-liners 正在计算的),但在其fdinfo文件中有六个条目。因此,我们可以通过查阅其fdinfo文件来确定给定进程的给定 fd 使用了多少个监视。现在把它和上面的一些放在一起来获取一个打开通知手表的进程列表,并使用它来计算每个fdinfo. 这与上面类似,所以我将在这里丢弃单行:
sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); echo -e $count"\t"$fdi; done
Run Code Online (Sandbox Code Playgroud)
这里有一些厚的东西,但基本的是我用来从输出awk构建fdinfo路径lsof,获取 pid 和 fd 编号,从后者中剥离 u/r/w 标志。然后对于每个构建的fdinfo路径,我计算行数inotify并输出计数和 pid。
如果我在同一个地方有这些 pid 代表什么进程就好了,对吧?我是这么想的。因此,在一个特别凌乱一点,我定居在呼吁dirname上两次fdinfo获得包到路径/proc/<pid>,加入/exe到它,然后运行readlink上是获得进程的exe文件名。把它也扔进去,按手表的数量排序,然后将它重定向到一个文件以安全保存,我们得到:
sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); exe=$(sudo readlink $(dirname $(dirname $fdi))/exe); echo -e $count"\t"$fdi"\t"$exe; done | sort -n > watches
Run Code Online (Sandbox Code Playgroud)
在没有sudo 的情况下运行它以显示我在上面启动的进程,我得到:
joel@gladstone:~$ cat watches
6 /proc/4906/fdinfo/3 /usr/bin/inotifywait
1 /proc/22734/fdinfo/4 /usr/bin/tail
Run Code Online (Sandbox Code Playgroud)
完美的!进程列表、fd 以及每个正在使用的手表数量,这正是我所需要的。
| 归档时间: |
|
| 查看次数: |
33887 次 |
| 最近记录: |