SSDに対するBlock Discard/TRIMをSystemTapで可視化する

パソコンを買いました。

今回はOLIOSPECさんのMicro Monster H67 Super Silentをカスタマイズして注文しました。デスクトップ機をリプレイスするのは実に9年ぶりなのですが、最近のパソコンはすごく良いですね。速くて静かで低消費電力です。本日はこのパソコンを使って、近年のLinuxにおけるSSD事情を確認していきたいと思います。

TRIMとは

近頃では定番SSDの座をすっかりCrucial RealSSD C300に奪われてしまった感のあるIntel X25-M G2ですが、4KiBアライメントが不要という使い勝手の良さ、およびWindows XPでもTRIMを利用可能というところを評価してこちらを選びました。どちらの製品も間もなくモデルチェンジを控えており、今が買いどきかと言われると少し微妙な情勢です。でも欲しかったので仕方がないです。

TRIMとは、OSがSSDに対し不要になった領域を通知するATA規格のコマンドです。SSDはNANDフラッシュの特性上、空き領域が少なくなると性能が劣化するという弱点があります。OS上でファイルを削除すれば空き領域は増えたように見えますが、SSDにとってはそれが「書いた」のか「消した」のかの区別がつかないため、TRIMコマンドによって実際に「消した」ことを伝える必要があります。

ただし、古いOSではTRIMがサポートされていません。TRIMを利用するには最新のOSとファイルシステムを使用する必要があります。現在のところ、以下のOSとファイルシステムの組み合わせでTRIMを利用することが可能となっています。

例外的にIntel X25-M G2については、Intel SSD Toolboxを用いることでWindows XP/VistaでもTRIMを利用することができます。

LinuxにおけるTRIMの利用とモニタリング

本当はCentOS 6.0がリリースされるのを首を長くして待っていたのですが、待ちきれなかったのでとりあえずFedora 14をインストールしました。LinuxでTRIMを利用するには、ext4ファイルシステムをマウントする際にdiscardオプションを指定します。

# mount -t ext4 -o discard /dev/sda5 /mnt

Linuxでは、ブロックデバイスに不要領域を通知する機能のことをBlock Discardと呼んでいます。Block DiscardによってATAバイスにはTRIMコマンドが、SCSIバイスにはUNMAPというコマンドが発行されます。
さて、設定はこれだけなのですが、これで実際にTRIMが機能しているのかどうか少し心配になります。というのも、TRIMについてはログなどが何も出力されないためです。
そこで、SystemTapを用いてBlock Discardの様子をモニタリングするスクリプトを作ってみました。SystemTapについては昨年のエントリでも取り扱っていますので、そちらも是非ご覧ください。

以下のスクリプトをdiscard.stpという名前で保存します。

probe kernel.function("blkdev_issue_discard").return {
  printf("%s, sector=%d, nr_sects=%d, return=%d (%d - %d KiB)\n",
    execname(), $sector, $nr_sects, $return,
    $sector / 2, ($sector + $nr_sects) / 2 - 1);
}

stapコマンドでSystemTapを起動します。

# stap discard.stp

別のターミナルで、大きなファイルを作ってから削除してみます。

# dd if=/dev/zero of=temp.dat bs=8388608 count=128 oflag=direct
128+0 records in
128+0 records out
1073741824 bytes (1.1 GB) copied, 9.1373 s, 118 MB/s

# rm temp.dat 
rm: remove 通常ファイル `temp.dat'? y

すると、数秒経ってから以下のようなログが出力されました。

jbd2/sda5-8, sector=5767168, nr_sects=16392, return=0 (2883584 - 2891779 KiB)
jbd2/sda5-8, sector=4718592, nr_sects=262144, return=0 (2359296 - 2490367 KiB)
jbd2/sda5-8, sector=4980736, nr_sects=262144, return=0 (2490368 - 2621439 KiB)
jbd2/sda5-8, sector=5242880, nr_sects=262144, return=0 (2621440 - 2752511 KiB)
jbd2/sda5-8, sector=5505024, nr_sects=262144, return=0 (2752512 - 2883583 KiB)
jbd2/sda5-8, sector=6029312, nr_sects=262144, return=0 (3014656 - 3145727 KiB)
jbd2/sda5-8, sector=5799936, nr_sects=229376, return=0 (2899968 - 3014655 KiB)
jbd2/sda5-8, sector=6291456, nr_sects=262144, return=0 (3145728 - 3276799 KiB)
jbd2/sda5-8, sector=6815744, nr_sects=32768, return=0 (3407872 - 3424255 KiB)
jbd2/sda5-8, sector=6569984, nr_sects=245760, return=0 (3284992 - 3407871 KiB)

左から、プロセス名、TRIM開始セクタ、セクタ数、戻り値、括弧内はTRIM対象範囲をKiB単位に換算した値です。jbd2というのはファイルシステムジャーナリング機能を付加するJournaling Block Deviceモジュールのext4対応版です。見ると、確かに合計1GiBの領域がTRIMされていることや、一度にTRIMされる領域が最大128MiBであることなどが分かります。
また、Fedora 14ではファイルシステム構築時にもTRIMが発行されます。

# mkfs -t ext4 /dev/sda5
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
524288 inodes, 2097152 blocks
104857 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2147483648
64 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 25 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

このときSystemTapの出力は以下のようになり、一度にデバイスの全領域をTRIMしていることが見てとれます。

mkfs.ext4, sector=0, nr_sects=16777216, return=0 (0 - 8388607 KiB)

一方、HDDなどTRIMに対応していないデバイスでは、戻り値として-95が返されます。これはEOPNOTSUPP、「Operation not supported on transport endpoint」というエラーを表しています。

jbd2/sdb5-8, sector=1312776, nr_sects=8, return=-95 (656388 - 656391 KiB)
jbd2/sdb5-8, sector=270336, nr_sects=245760, return=-95 (135168 - 258047 KiB)
jbd2/sdb5-8, sector=524288, nr_sects=262144, return=-95 (262144 - 393215 KiB)
jbd2/sdb5-8, sector=1048576, nr_sects=262144, return=-95 (524288 - 655359 KiB)
jbd2/sdb5-8, sector=802816, nr_sects=245760, return=-95 (401408 - 524287 KiB)
jbd2/sdb5-8, sector=1572864, nr_sects=262144, return=-95 (786432 - 917503 KiB)
jbd2/sdb5-8, sector=1327104, nr_sects=245760, return=-95 (663552 - 786431 KiB)
jbd2/sdb5-8, sector=2097152, nr_sects=262144, return=-95 (1048576 - 1179647 KiB)
jbd2/sdb5-8, sector=1851392, nr_sects=245760, return=-95 (925696 - 1048575 KiB)
jbd2/sdb5-8, sector=2375680, nr_sects=65536, return=-95 (1187840 - 1220607 KiB)

おわりに

メジャーなLinuxディストリビューションにおけるSSDのTRIM対応はWindowsに比べて少し遅れていたため、これまでSSDの導入に躊躇していたのですが、ようやく条件が整ってきました。ちょうどIntelから新しいCPUも発売されたことですし、Sandy BridgeRHEL 6.0/Ubuntu 10.10+最新SSDへと環境を刷新する絶好のタイミングかもしれません。
LinuxでのSSD利用についてはもう少し調べているので、情報がまとまったら再度レポートしたいと思います。