プロセスがinotifyで監視しているオブジェクトの数を取得する

inotifyを使っていると、プロセスが監視しているファイルの数がfs.inotify.max_user_watchesの値を上回ってno space left on deviceのエラーとなる…ということはよくあるのだけど、じゃあ今いくつ監視しているのか?を知りたくなるので調べた。結論としては、プロセスがオープンしいるinotifyインスタンスに監視中のオブジェクト一覧が保存されており、数えると知ることができる。

まずは調査用のプロセスが欲しいので、無限にファイルを作りそれを監視するプログラムを用意する。

package main

import (
	"fmt"
	"github.com/fsnotify/fsnotify"
	"log"
	"os"
	"time"
)

func NewWatcher() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event, ok := <-watcher.Events:
				if !ok {
					return
				}
				log.Println("event:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					log.Println("modified file:", event.Name)
				}
			case err, ok := <-watcher.Errors:
				if !ok {
					return
				}
				log.Println("error:", err)
			}
		}
	}()

	i := 1
	for {
		path := fmt.Sprintf("/tmp/foo_%d.txt", i)
		_, err := os.Create(path)
		if err != nil {
			log.Fatal(err)
		}
		err = watcher.Add(path)
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf("start watching %s\n", path)
		i += 1
		time.Sleep(1 * time.Second)
	}
	<-done
}

func main() {
	NewWatcher()
}

このプログラムを実行したあと(プロセスIDは4244)、/proc/32531/fdを見てみる。anon_inode:inotifyへのリンクになっている3が調査対象となるfd。

ubuntu@alpaca-dev:~$ ls -ahltr /proc/4244/fd
total 0
dr-xr-xr-x 9 ubuntu ubuntu  0 Nov 25 13:28 ..
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 9 -> /tmp/foo_2.txt
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 8 -> 'anon_inode:[eventpoll]'
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 7 -> /tmp/foo_1.txt
l-wx------ 1 ubuntu ubuntu 64 Nov 25 13:28 6 -> 'pipe:[548152]'
lr-x------ 1 ubuntu ubuntu 64 Nov 25 13:28 5 -> 'pipe:[548152]'
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 4 -> 'anon_inode:[eventpoll]'
lr-x------ 1 ubuntu ubuntu 64 Nov 25 13:28 3 -> anon_inode:inotify
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 2 -> /dev/pts/2
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 14 -> /tmp/foo_7.txt
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 13 -> /tmp/foo_6.txt
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 12 -> /tmp/foo_5.txt
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 11 -> /tmp/foo_4.txt
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 10 -> /tmp/foo_3.txt
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 1 -> /dev/pts/2
lrwx------ 1 ubuntu ubuntu 64 Nov 25 13:28 0 -> /dev/pts/2
dr-x------ 2 ubuntu ubuntu  0 Nov 25 13:28 .

次に、/proc/4244/fdinfo/3の中を見てみると、監視しているディスクリプタ一覧がある。inotifyから始まる行を数えると、そのinotifyインスタンスで監視しているファイル数がわかる。

ubuntu@alpaca-dev:~$ cat /proc/4244/fdinfo/3
pos:    0
flags:  02000000
mnt_id: 13
inotify wd:10 ino:1a9d sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:9d1a00007e8b11e5
inotify wd:f ino:1a9c sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:9c1a0000a2cbafb8
inotify wd:e ino:1a9a sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:9a1a0000d962ed0a
inotify wd:d ino:1a99 sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:991a00005d758c3d
inotify wd:c ino:1a73 sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:731a0000aa47aa90
inotify wd:b ino:1a72 sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:721a0000d00cc24f
inotify wd:a ino:1a6e sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:6e1a0000c3e218c9
inotify wd:9 ino:1a4d sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:4d1a00007a377089
inotify wd:8 ino:1a3e sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:3e1a0000cdc73ba9
inotify wd:7 ino:1a26 sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:261a00008ce7205f
inotify wd:6 ino:1a23 sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:231a0000f8d65bf0
inotify wd:5 ino:1a22 sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:221a00003cc01fa5
inotify wd:4 ino:18f9 sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:f9180000870fe1f0
inotify wd:3 ino:18e5 sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:e5180000d052e2f0
inotify wd:2 ino:9e sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:9e0000002427522c
inotify wd:1 ino:6e sdev:fc00001 mask:fc6 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:6e00000094549bc1

これをメトリクス化すれば、no space left on deviceエラーが発生した時に監視対象がmax_user_watchesの値を越えそうになっているのだな、ということが確認できるのではないか?

参考文献