2014年5月8日

BTRFSのFIEMAP/filefragは嘘をつく

FIEMAPioctlとそれを使ったfilefragコマンドは、ディスク上に散らばったファイルの実体(エクステント)を返す・表示するので、ファイルの断片化状態を見たりするのに使う。ところが、BTRFSのFIEMAPで返されるエクステントのディスク上のセクタ番号(=アドレス)は実際の物理ディスク上の位置と一致しない。

これは、BTRFSが内部にRAID機能を持っており、FIEMAPで返されるエクステントの位置情報は、この内部RAID上の位置だからだ。

3.0カーネルに含まれるBTRFSは
  • ストライピング(RAID0)
  • ミラリング(RAID1)
  • ストライピング+ミラリング(RAID10)
  • 複数ディスクの連結(JBOD)
をサポートしており、mkfs.btrfs でファイルシステム構築時にRAIDに使用するディスクを指定、または稼働中に btrfs device add/delete で使用するディスクを増減できる。

この内部RAID上のエクステント情報(FIEMAPが返すのと同じ)は内部的には「論理エクステント」、実際のディスク上のエクステント情報は「物理エクステント」と呼ばれており、外部から利用できる明確なレイヤの境界はなく、したがって論理エクステントと物理エクステントを変換するAPIもないようだ。

この論理エクステントと物理エクステントの変換に関わるコードは fs/btrfs/volumes.c にほとんどが含まれている。

さらにややこしいのは、 BTRFSのファイルをstatして得られるデバイス番号は、本物のメジャー:マイナー番号ではなく、BTRFSが内部的に作成するサブボリュームデバイスの仮想的なデバイス番号だと言うこと。

例えば、下の例では /mnt にマウントされた /dev/md91と言う md のRAID上のファイル /mnt/etc/ld.so.cache を見ているが、/dev/md919:91 のデバイス番号にも関わらず、ファイルを stat すると 0:35 が返される。これはカーネル内部では無名(anonymous)デバイス番号と呼ばれ、メジャー番号は常にゼロ、マイナー番号はデバイス登録の要求がある度に1づつ増える(登録取り消しデバイス番号の再利用はない)。この無名デバイス番号と物理デバイスの関係を解決する直接的な手段はない。

root@h-rn312:~# df -h /mnt/etc/ld.so.cache
Filesystem      Size  Used Avail Use% Mounted on
/dev/md91       396M  2.5M  390M   1% /mnt
root@h-rn312:~# ls -l /dev/md91
brw-rw---T 1 root disk 9, 91 May  7 14:37 /dev/md91
root@h-rn312:~# stat /mnt/etc/ld.so.cache
  File: `/mnt/etc/ld.so.cache'
  Size: 30475         Blocks: 64         IO Block: 4096   regular file
Device: 23h/35d    Inode: 1164        Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2014-05-07 12:50:28.426131463 -0700
Modify: 2014-05-07 12:50:28.426131463 -0700
Change: 2014-05-07 12:50:28.426131463 -0700
 Birth: -

root@h-rn312:~#

現在、FIEMAPを拡張してファイルの物理エクステント情報と物理デバイス番号を返せる機能を開発中。

なお、ファイルサイズが小さい場合(上限サイズは不明)は、ファイル本体がメタデータと一緒に格納されるようで、その場合はfilefragはディスクポジションとしてゼロを表示する。

注意:上で「ディスク」「物理デバイス」と書いたが、これはあくまでもBTRFSの下位のレイヤと言う意味で、実際に物理ディスクまたはそのパーティションでなくても、mdのRAIDだとか、LVMのボリュームだとか、loopデバイスだとか、要するにブロックデバイスなら何でもよい。

0 件のコメント:

コメントを投稿