ablog

不器用で落着きのない技術者のメモ

バッファページにブロックバッファをキャッシュするのはファイルシステムではない?

バッファページ*1もページキャッシュ*2ファイルシステムのキャッシュだと思っていましたが、どうやら勘違いしていたようです。
ブロックデバイスのデバイスファイル(/dev/sda1など)に直接アクセスした場合は、メモリ上にキャッシュされないと思っていましたが、以下のような dd コマンドを実行した前後で、free コマンドを実行すると、buffers が増えるのでおかしいなと思って調べてみて気づきました。

oel11gr2 root% dd if=/dev/sda1 of=/dev/null count=100 bs=1M

嘘ついてたみたいです。デバイスファイルに対して読み書きする場合、そのデバイスファイルがファイルシステムとして使われているか、キャラクタデバイスとして使われているかなどの違いにより挙動(ページキャッシュやバッファページにキャッシュされるか否かなど)が変わるようです。従って、ページキャッシュもバッファページもファイルシステムのキャッシュだと思います。

検証結果

  • free コマンドで buffers の値を確認しておく。
oel11gr2 root% free
total       used       free     shared    buffers     cached
Mem:       1035064     226556     808508          0      16036     161348
-/+ buffers/cache:      49172     985892
Swap:      2096472          0    2096472
  • /dev/sda1 を dd コマンドで読み込む。
oel11gr2 root% time dd if=/dev/sda1 of=/dev/null count=100 bs=1M
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 8.28306 seconds, 12.7 MB/s
dd if=/dev/sda1 of=/dev/null count=100 bs=1M  0.00s user 1.25s system 15% cpu 8.287 total
  • free コマンドで buffers の値を確認すると、96656KB、つまり 100MB 近く増えている。
oel11gr2 root% free
             total       used       free     shared    buffers     cached
Mem:       1035064     325136     709928          0     112692     161368
-/+ buffers/cache:      51076     983988
Swap:      2096472          0    2096472
  • キャッシュを解放する。
oel11gr2 root% echo 3 > /proc/sys/vm/drop_caches
  • free コマンドで確認すると、buffers も chached も大幅に減っている。
oel11gr2 root% free
             total       used       free     shared    buffers     cached
Mem:       1035064      58672     976392          0        236      12056
-/+ buffers/cache:      46380     988684
Swap:      2096472          0    2096472
  • dd コマンドに iflag=direct をつけてキャッシュを経由せずに /dev/sda1 を読み込んでみる。
oel11gr2 root% time dd if=/dev/sda1 of=/dev/null count=100 bs=1M iflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 2.18937 seconds, 47.9 MB/s
dd if=/dev/sda1 of=/dev/null count=100 bs=1M iflag=direct  0.00s user 0.25s system 11% cpu 2.287 total
  • free コマンドで確認しても、buffers はほとんど増えていない。
oel11gr2 root% free
             total       used       free     shared    buffers     cached
Mem:       1035064      59600     975464          0        772      12888
-/+ buffers/cache:      45940     989124
Swap:      2096472          0    2096472
  • さらに、dd コマンドで iflag=direct をつけずに /dev/sda1 を読み込んでみる。
oel11gr2 root% time dd if=/dev/sda1 of=/dev/null count=100 bs=1M
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 2.08102 seconds, 50.4 MB/s
dd if=/dev/sda1 of=/dev/null count=100 bs=1M  0.00s user 0.36s system 17% cpu 2.088 total
  • free コマンドで確認すると、100MBほど buffers が増えている。
oel11gr2 root% free
             total       used       free     shared    buffers     cached
Mem:       1035064     162392     872672          0     102920      12876
-/+ buffers/cache:      46596     988468
Swap:      2096472          0    2096472


追記(2010/11/12):
嘘ついてました。fdsik でフォーマットもしてないデバイスを dd で読み込んでみたところ、ブロックバッファはバッファページにキャッシュされませんでした。どうも、デバイスファイルシステムとして使われているかキャラクタデバイスとして使われているかなどで、挙動が変わるようです。

oel11gr2 root% echo 3 > /proc/sys/vm/drop_caches
oel11gr2 root% free
             total       used       free     shared    buffers     cached
Mem:       1035064      58596     976468          0        204      11928
-/+ buffers/cache:      46464     988600
Swap:      2096472          0    2096472
oel11gr2 root% dd if=/dev/sdc of=/dev/null count=100 bs=1M
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 2.22824 seconds, 47.1 MB/s
oel11gr2 root% free
             total       used       free     shared    buffers     cached
Mem:       1035064      58640     976424          0        220      12140
-/+ buffers/cache:      46280     988784
Swap:      2096472          0    2096472

まとめ

  • バッファページにブロックをキャッシュするのはファイルシステムより下の汎用ブロック層
  • 従って、「cat /dev/sda1 > /dev/null」などとすると、バッファページにブロックバッファがキャッシュされる。
  • ファイルシステムがキャッシュするのはページキャッシュとバッファページ。
  • DIRECT I/O *3を使うとバッファページにブロックバッファをキャッシュしない。
  • バイスファイルシステムとして使われているかキャラクタデバイスとして使われているかなどで、挙動が変わるぽい。

*1:安定版 Linux 2.4.10 以降、バッファキャッシュは実質的に存在しない。ページキャッシュの中のバッファページと呼ばれる専用ページにブロックバッファを置いている。

*2:バッファページとページキャッシュの違いは、sar -r でメモリ使用状況を確認する - ablog 参照。

*3:dd コマンドだと「iflag=direct」を指定した場合。要するに O_DIRECT フラグを付けてシステムコールで読み書きした場合。