Inotify:目录创建的奇怪行为

时间:2017-12-05 07:31:41

标签: inotify

我有一个inotify / kernel问题。我正在使用" inotify" Python项目是为了进行观察,但是我的问题仍然是核心inotify内核实现

Python inotify 项目处理递归的inotify监视。它提供了一个很好的生成器,允许您循环事件。它通过识别目录创建事件并在产生事件之前自动添加这些监视来实现递归监视。

我注意到了一些奇怪的行为" mkdir -p"调用。虽然我可以快速,逐步创建单个目录并从事件循环中查看它们," mkdir -p"永远不会为子目录的子目录或在该子目录中创建的文件生成事件。

有没有人有任何想法?

工作:" mkdir aa&& mkdir aa / bb&&触摸aa / bb / filename":

(_INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], '/tmp/tmpt3MlIQ', u'aa')
(_INOTIFY_EVENT(wd=2, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], u'/tmp/tmpt3MlIQ/aa', u'bb')
(_INOTIFY_EVENT(wd=3, mask=256, cookie=0, len=16), ['IN_CREATE'], u'/tmp/tmpt3MlIQ/aa/bb', u'filename')
(_INOTIFY_EVENT(wd=3, mask=32, cookie=0, len=16), ['IN_OPEN'], u'/tmp/tmpt3MlIQ/aa/bb', u'filename')
(_INOTIFY_EVENT(wd=3, mask=4, cookie=0, len=16), ['IN_ATTRIB'], u'/tmp/tmpt3MlIQ/aa/bb', u'filename')
(_INOTIFY_EVENT(wd=3, mask=8, cookie=0, len=16), ['IN_CLOSE_WRITE'], u'/tmp/tmpt3MlIQ/aa/bb', u'filename')

DOESN' WORK:" mkdir -p aa / bb&&触摸aa / bb / filename":

(_INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], '/tmp/tmpuTSxYl', u'aa')
(_INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], '/tmp/tmpuTSxYl', u'aa')
(_INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], '/tmp/tmpuTSxYl', u'aa')

当然,我做了下一个我能想到的明显无脑的事情并添加了" -p"标志着" mkdir aa&& mkdir aa / bb",只是为了确保没有任何" -p"特定的异常,但它并没有产生任何影响。

" mkdir -p"的GNU实现只是在路径中从分隔符迭代到分隔符。没有魔法。 os.makedirs(相同功能)的Python实现也只是拆分路径并枚举部分。然而,GNU并不起作用,但Python的确如此。这似乎意味着一种竞争条件,除了无论我操纵条件如何,结果都是相同的。我甚至开始在epoll上使用一个微不足道/微不足道的超时来读取事件(读取:如果原始超时值有任何延迟,那么它不再是工厂)。几乎就像内核中的inotify似乎完全错过了" mkdir -p"中的后续创作。

我确定我错过了一些东西。

供参考,GNU实现中涉及的调用:

  1. http://code.metager.de/source/xref/gnu/coreutils/src/mkdir.c

  2. http://code.metager.de/source/xref/gnu/octave/gnulib-hg/lib/mkdir-p.c#85

  3. http://code.metager.de/source/xref/gnu/octave/gnulib-hg/lib/mkancesdirs.c#67

  4. 请注意,我们从GNU" coreutils"开始并且显然进入GNU Octave以实现" mkdir -p"。它是OpenGrok提供的唯一参考。我无法解释这一点,而且我处于陌生的领域。

    Python的实现:

    https://github.com/python/cpython/blob/master/Lib/os.py#L196

    我是否忽略了inotify行为的一些细节?

2 个答案:

答案 0 :(得分:2)

一个非常有趣的抓住你到达那里!

不,本机内核inotify库完全符合documentation所说的内容。 GNU mkdir -p也完全没问题。

  

我注意到了一些奇怪的行为" mkdir -p"调用。我可以   快速,逐步创建单个目录并从中查看它们   事件循环," mkdir -p"永远不会为子目录生成事件   在该子目录中创建的子目录或文件。

您必须尝试使用​​其他inotify实现来声明PyInotify递归监视的可信度。仅凭流行的Python实现这一事实并不能赢得我的信任!

我做出以下声明,假设您没有搞砸您为参考而生成的示例Python输出。 PyInotify执行是松散的,我会说, 而不是很擅长它

对于我们这里的推测,让我们分开流程并从创建dirs开始,然后再考虑创建文件。

您是否注意到即使您的第一个方案{d} IN_CREATE

aa
(_INOTIFY_EVENT(wd=1, mask=1073742080, cookie=0, len=16), ['IN_ISDIR', 'IN_CREATE'], '/tmp/tmpt3MlIQ', u'aa')

没有对应的 IN_OPENIN_CLOSE_NOWRITE事件,由于某些奇怪的原因似乎在第二种情况中出现,但操作只是mkdir

(_INOTIFY_EVENT(wd=1, mask=1073741856, cookie=0, len=16), ['IN_ISDIR', 'IN_OPEN'], '/tmp/tmpuTSxYl', u'aa')
(_INOTIFY_EVENT(wd=1, mask=1073741840, cookie=0, len=16), ['IN_ISDIR', 'IN_CLOSE_NOWRITE'], '/tmp/tmpuTSxYl', u'aa')

这显然有些可疑。绝对不一致。

我还没有看过PyInotify的实现,我也不打算浪费时间。但是,我使用本机inotify接口非常紧密地保证其准确性!它从未错过报告单个事件,也就是说,如果它发生的话。

现在让我们转到文件创建部分,这似乎是您的主要关注点 - mkdir -p永远不会为子目录的子目录生成事件或在该子目录中创建的文件。 始终不是这样;取决于实施的糟糕程度。

我已经使用a better inotify implementation复制了您已执行过的同一组操作。是的,只是为了证明我的主张。

请注意事件流程明显比PyInotify报告更准确吗?

Reproduction

案例1: mkdir aa && mkdir aa/bb && touch aa/bb/filename

root@six-k:/opt/test# ls -la
total 8
drwxr-xr-x  2 root root 4096 Mar 18 13:55 .
drwxr-xr-x 20 root root 4096 Mar 18 13:53 ..
root@six-k:/opt/test# fluffyctl -w ./
root@six-k:/opt/test# mkdir aa && mkdir aa/bb && touch aa/bb/filename

发生的事件:

root@six-k:/home/lab/fluffy# fluffy
event:  CREATE, ISDIR, 
path:   /opt/test/aa

event:  ACCESS, ISDIR, 
path:   /opt/test/aa

event:  ACCESS, ISDIR, 
path:   /opt/test/aa

event:  CLOSE_NOWRITE, ISDIR, 
path:   /opt/test/aa

event:  CREATE, ISDIR, 
path:   /opt/test/aa/bb

event:  ACCESS, ISDIR, 
path:   /opt/test/aa/bb

event:  ACCESS, ISDIR, 
path:   /opt/test/aa/bb

event:  CLOSE_NOWRITE, ISDIR, 
path:   /opt/test/aa/bb

event:  CREATE, 
path:   /opt/test/aa/bb/filename

event:  OPEN, 
path:   /opt/test/aa/bb/filename

event:  ATTRIB, 
path:   /opt/test/aa/bb/filename

event:  CLOSE_WRITE, 
path:   /opt/test/aa/bb/filename

案例2: mkdir -p aa/bb && touch aa/bb/filename

root@six-k:/opt/test# cd ../
root@six-k:/opt# mkdir test2
root@six-k:/opt# cd test2/
root@six-k:/opt/test2# fluffyctl -w ./
root@six-k:/opt/test2# mkdir -p aa/bb && touch aa/bb/filename
root@six-k:/opt/test2#

发生的事件:

root@six-k:/home/lab/fluffy# fluffy
event:  CREATE, ISDIR, 
path:   /opt/test2/aa

event:  ACCESS, ISDIR, 
path:   /opt/test2/aa

event:  ACCESS, ISDIR, 
path:   /opt/test2/aa/bb

event:  ACCESS, ISDIR, 
path:   /opt/test2/aa/bb

event:  CLOSE_NOWRITE, ISDIR, 
path:   /opt/test2/aa/bb

event:  ACCESS, ISDIR, 
path:   /opt/test2/aa

event:  CLOSE_NOWRITE, ISDIR, 
path:   /opt/test2/aa

event:  CREATE, 
path:   /opt/test2/aa/bb/filename

event:  OPEN, 
path:   /opt/test2/aa/bb/filename

event:  ATTRIB, 
path:   /opt/test2/aa/bb/filename

event:  CLOSE_WRITE, 
path:   /opt/test2/aa/bb/filename

你去,子目录上的事件和其中的文件。

答案越来越长了!

Neverthless,没有递归实现构建在本机inotify库之上可以保证所有事件。 它不可行!如果是,那么would have been rather simple为那些创作inotify的内核人本身引入了递归手表。

<强>陷阱:

请注意,确实与我的再现代码段中的create事件存在差异?在第二种情况下(mkdir -p)没有报告子目录。 为什么?虽然一切都很快发生,但递归设置还不够快。在捕获目标create上的第一个aa事件时,mkdir -p aa/bb也会完成创建目录bb。因此,dir create没有bb事件。再次,提醒,这不是本机inotify库的错;它是因为我们还没有在dir aa上设置一个监视器,但是我们将如何在世界上接收事件呢?

我希望能够解决问题!

等一下,如果dir bb的创建事件甚至没有被捕获,fluffy似乎如何设置监视并在那里报告后续事件在目录& #39; bb`?

好,你关注!你猜对了,但并不完全。 fluffy收到了dir create的第一个aa事件。当它处理此事件时,mkdir -p完成了它的工作,因此没有dir bb创建事件。对。但是,当fluffy设置监视目录aa时,dir bb已经存在。所以,蓬松,将bb拉入其中,因为它确实是dir aa的后代。你已经知道的其余部分。由于它正在被监视,它会报告后续事件,其中包括文件创建。

如果您(阅读此内容的任何人)打算在PyInotify GitHub项目页面上提出相关票据/问题,请随意引用此答案或指向fluffy。如果您需要更多信息,我很乐意提供。您可以在蓬松的GH页面上打开一个问题,以获得一般性讨论/建议/意见。 fluffy可以使用您的帮助来改善它。

答案 1 :(得分:0)

在我看来,抓住你希望收到通知的所有事件是很棘手的。我的经验是inotify在C中。我确信python包中添加了一些东西以方便使用。所以,我已经在这里定制了我的答案,以相当一般的术语来说明inotify。

对事件发生的顺序没有任何保证。创建的第一个目录将触发父级通知。稍后,将创建下一个目录,并为第一个目录注册事件通知。这些行动可能会发生两种可能的命令。

如果首先更新inotify,则会在创建第二个目录时收到通知。

当其他订单发生时,通知似乎不太可能。但是,有人可能会打开并检查条目。对于每个目录,更新inotify以观察它。

Inotify是获取初始信号的好工具。但是,它确实有其局限性。特别是在创建新目录时,您需要检查间隙和比赛。