inotify(file change notification system)覚書-Part1

ファイルシステムの変更イベントを捕まえて同期を行う Lsyncd(Live Syncing Daemon) というツールがある。
いろいろと使えそうだったので、lsyncd が下回り(ファイルシステムのイベント通知)に利用している inotify を調査。

—–

inotify/dnotify mechanism
inotify はファイルシステムのイベントをモニターするメカニズム。John McCutchan, Robert Love, Amy Griffis らが中心となって実装し、 Linux Kernel 2.6.13 から取り込まれている。
Kernel 2.4 以降には dnotify という同様の仕組みが存在していたものの

  • ディレクトリしか監視できない
  • 監視対象ごとにファイルディスクリプター(以下 FD)が必要
  • イベント通知がシグナル(SIGIO)で行われる

などの欠点があったため、dnotify を葬りさるべく inotify が用意された。

inotify と dnotify の違いは、inotify 実装者の Robert Love が “Why Not dnotify and Why inotify” という若さあふれるドキュメントを書いている。

Robert Love : Why Not dnotify and Why inotify
http://www.kernel.org/pub/linux/kernel/people/rml/inotify/README

inotify API

inotify の API はシンプル。

  1. inotify_init(2) で inotify インスタンスを初期化
  2. ファイルなりディレクトリを inotify_add_watch(2) でワッチリストに追加
  3. 初期化したときのファイルディスクリプタを select/poll/epoll で監視
  4. イベントが起こるたびに read し、起きたイベントにしたがってハンドラーで処理

通知されるイベントは 作成(IN_CREATE)、変更(IN_MODIFY)、オープン(IN_OPEN)などなど。詳細は man を参照

inotify が有効になっているかカーネルをチェック

CONFIG_INOTIFY_USER=y になっていれば OK。

$ grep INOTIFY_USER /boot/config-$(uname -r)
CONFIG_INOTIFY_USER=y

inotify が利用するマクロは次のヘッダーファイルで定義されている。

/usr/include/sys/inotify.h

inotify を使ってみる

Michael Kerrisk 著 The Linux Programming Interface の Ch.19 “Monitoring File Events” のサンプルプログラムを利用。

demo_inotify は引数で監視先を指定すると、発生したイベントを表示する。

$ mkdir -p dir1 dir2
$ ./demo_inotify dir1 dir2 &
[1] 3638
Watching dir1 using wd 1
Watching dir2 using wd 2
$ cat > dir1/aaa
Read 64 bytes from inotify fd
    wd = 1; mask = IN_CREATE
        name = aaa
    wd = 1; mask = IN_OPEN
        name = aaa

hello world # ファイルに書き込み
Read 32 bytes from inotify fd
    wd = 1; mask = IN_MODIFY
        name = aaa
Read 32 bytes from inotify fd
    wd = 1; mask = IN_CLOSE_WRITE
        name = aaa

$ mv dir1/aaa dir2/bbb # ディレクトリ移動
Read 64 bytes from inotify fd
    wd = 1; cookie = 573; mask = IN_MOVED_FROM
        name = aaa
    wd = 2; cookie = 573; mask = IN_MOVED_TO
        name = bbb

$ rmdir dir1/ # ディレクトリ削除
Read 32 bytes from inotify fd
    wd = 1; mask = IN_DELETE_SELF
    wd = 1; mask = IN_IGNORED

inotify API はシステムコール
inotify は dnotify とは異なりシステムコール呼び出し。
GNU tail では inotify が利用されているので strace で確認

$ strace -e inotify_init,inotify_add_watch tail -f /tmp/tail_test
inotify_init() = 4
inotify_add_watch(4, "/tmp/tail_test", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1

ということで、確かに inotify を利用して tail が実装されている。

カーネルパラーメータ
inotify はカーネル空間のリソース制御のために以下のカーネルパラメータを利用している。

# sysctl -a | grep inotify
fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.inotify.max_queued_events = 16384

各パラメータの設定内容は以下

/proc/sys/fs/inotify/max_queued_events

The value in this file is used when an application calls inotify_init(2) to set an upper limit on the number of events that can be queued to the corresponding inotify instance. Events in excess of this limit are dropped, but an IN_Q_OVERFLOW event is always generated.

/proc/sys/fs/inotify/max_user_instances

This specifies an upper limit on the number of inotify instances that can be created per real user ID.

/proc/sys/fs/inotify/max_user_watches

This specifies an upper limit on the number of watches that can be created per real user ID.

カーネルパラーメータの上限を超えた時のエラー

上述のパラメータを1にして、上限を超えた時のエラーを確認

move で同時に複数のイベントを発生。イベントキューの上限を超えると IN_Q_OVERFLOW が発生

# sysctl -n -w fs.inotify.max_queued_events=1
1
$ mkdir dir
$ touch dir/test
$ ./demo_inotify dir &
[1] 3896
Watching dir using wd 1
$ mv dir/test dir/test2
Read 48 bytes from inotify fd
    wd = 1; cookie = 574; mask = IN_MOVED_FROM
        name = test
    wd =-1; mask = IN_Q_OVERFLOW

inotify インスタンスを一つ動かしている状態で2つ目をインスタンス化すると、EMFILE Too many open files が発生

# sysctl -n -w fs.inotify.max_user_instances=1
1
$ ./demo_inotify demo_inotify.c
ERROR [EMFILE Too many open files] inotify_ini

ワッチリストの上限を超えると ENOSPC No space left on device が発生

# sysctl -n -w fs.inotify.max_user_watches=1
1
$ ./demo_inotify demo_inotify.c dnotify.c
ERROR [ENOSPC No space left on device] inotify_add_watch

ファイルディスクリプタ

dnotify は監視対象ごとに FD を消費し、inotify は inotify インスタンスごとに FD を消費することを確認

dnotify
dnotify プログラムも Linux Programming Interface Ch.19 から拝借

$ mkdir -p dir1 dir2
$ ./dnotify dir1/ dir2 &
[1] 4225
opened 'dir1/' as file descriptor 3
events: 20000000077
opened 'dir2' as file descriptor 4
events: 20000000077
$ lsof -p 4225
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dnotify 4225 jsmith cwd DIR 252,0 4096 916623 /home/jsmith/work/tlpi-book/inotify
dnotify 4225 jsmith rtd DIR 252,0 4096 2 /
dnotify 4225 jsmith txt REG 252,0 27274 916866 /home/jsmith/work/tlpi-book/inotify/dnotify
dnotify 4225 jsmith mem REG 252,0 1685816 1440531 /lib/x86_64-linux-gnu/libc-2.13.so
dnotify 4225 jsmith mem REG 252,0 141088 1440528 /lib/x86_64-linux-gnu/ld-2.13.so
dnotify 4225 jsmith 0u CHR 136,2 0t0 5 /dev/pts/2
dnotify 4225 jsmith 1u CHR 136,2 0t0 5 /dev/pts/2
dnotify 4225 jsmith 2u CHR 136,2 0t0 5 /dev/pts/2
dnotify 4225 jsmith 3r DIR 252,0 4096 916334 /home/jsmith/work/tlpi-book/inotify/dir1
dnotify 4225 jsmith 4r DIR 252,0 4096 917097 /home/jsmith/work/tlpi-book/inotify/dir2

inotify

$ ./demo_inotify dir1 dir2 &
[2] 4267
Watching dir1 using wd 1
Watching dir2 using wd 2
$ lsof -p 4267
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
demo_inot 4267 jsmith cwd DIR 252,0 4096 916623 /home/jsmith/work/tlpi-book/inotify
demo_inot 4267 jsmith rtd DIR 252,0 4096 2 /
demo_inot 4267 jsmith txt REG 252,0 25238 916865 /home/jsmith/work/tlpi-book/inotify/demo_inotify
demo_inot 4267 jsmith mem REG 252,0 1685816 1440531 /lib/x86_64-linux-gnu/libc-2.13.so
demo_inot 4267 jsmith mem REG 252,0 141088 1440528 /lib/x86_64-linux-gnu/ld-2.13.so
demo_inot 4267 jsmith 0u CHR 136,2 0t0 5 /dev/pts/2
demo_inot 4267 jsmith 1u CHR 136,2 0t0 5 /dev/pts/2
demo_inot 4267 jsmith 2u CHR 136,2 0t0 5 /dev/pts/2
demo_inot 4267 jsmith 3r 0000 0,9 0 4067 anon_inode

inotify library/software

References

Tagged with:
Posted in linux

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
%d bloggers like this: