ストレージ製品には論理セクターのサイズが 512 バイトのもの (512e) と 4K バイトのもの (4Kn) があり、混在している構成のシステムでは非常に厄介な問題を引き起こすことがあります。最近 Linux カーネルにマージされた dm-ebs という device mapper を使うと 4Kn のディスクの論理セクターサイズを 512 バイトに見せかけることができ、問題が発生した場合のワークアラウンドとして使うことができます。
注意
dm-ebs は Red Hat の開発者によって開発され Linux 5.8 に正式に含まれる可能性が高い機能ですが、開発されたばかりであるため利用の際は慎重な評価を行ってください。
発生する問題を確認する
512e のディスクの上に XFS のファイルシステムを作成したとします。今回は実験用として losetup コマンドで作成したループバックデバイス /dev/loop0
を利用します。
バックアップためにこのディスクの中身をブロックデバイスレベルでファイルシステムごと別のディスクにコピーしたとします。このときコピー先のディスクが 4Kn だったとします。
ここで もとのディスクが壊れてバックアップしたディスクをマウントしようとすると失敗します。
確認してみましょう。まず losetup で 512e のブロックデバイスを作成して、その上に XFS のファイルシステムを作成します。
$ fallocate -l 128M disk.img $ sudo losetup -f disk.img $ lsblk -t NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC ROTA SCHED RQ-SIZE RA WSAME loop0 0 512 0 512 512 1 mq-deadline 256 128 0B ... $ sudo mkfs.xfs -f /dev/loop0 meta-data=/dev/loop0 isize=512 agcount=4, agsize=8192 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=0, rmapbt=0, reflink=0 data = bsize=4096 blocks=32768, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal log bsize=4096 blocks=855, version=2 = sectsz=512 sunit=0 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 $
/mnt
にマウントして適当に何か書いておきます。
$ sudo mount /dev/loop0 /mnt/ $ ls /mnt/ $ echo "Hello, world!" | sudo tee /mnt/hello.txt Hello, world! $ cat /mnt/hello.txt Hello, world! $ sudo umount /mnt $ sudo losetup -d /dev/loop0 $
先ほど書き込んだデータを含む disk.img
を 4Kn のブロックデバイスと見なして、再びマウントしてみましょう。losetup コマンドの --sector-size
オプションは Linux 4.14 以降でしか使えない機能であることに注意してください。
$ sudo losetup --sector-size 4096 -f disk.img $ sudo mount /dev/loop0 /mnt/ mount: /mnt: mount(2) system call failed: Function not implemented. $ sudo dmesg | tail -n1 [ 804.657310] XFS (loop0): device supports 4096 byte sectors (not 512) $
マウントに失敗しました。mkfs.xfs
でファイルシステムを作成したときに何もオプションを設定しなかったため sectsz=512
としてフォーマットされていましたが、そのファイルシステムが今では 4Kn のブロックデバイス上に存在するので、サポートされていないセクターサイズ(512 バイト)での読み書きを防ぐためマウントできなかったようです。
このような問題が起きるとバックアップからファイルを読み出すことができなくなり困ります。
dm-ebs を使ってみる
4Kn のディスクに dm-ebs を重ねて 512e のディスクと見せかけることで XFS をマウントできるようにします。
drivers/md/dm-ebs-target.c は Linux 5.8 の rc にマージされた機能なので、Ubuntu では現時点の最新の LTS に含まれるカーネルを使ったとしても利用することができません。そのため Ubuntu のカーネルチームが提供している mainline ビルドを利用しました。
現時点では Linux 5.8 は正式リリースされていないので v5.8-rc7 を使うことにしました。https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.8-rc7/amd64/ から以下のファイルをダウンロードしてインストールしました。
- linux-image-unsigned-5.8.0-050800rc7-generic_5.8.0-050800rc7.202007262231_amd64.deb
- linux-modules-5.8.0-050800rc7-generic_5.8.0-050800rc7.202007262231_amd64.deb
- linux-headers-5.8.0-050800rc7_5.8.0-050800rc7.202007262231_all.deb
- linux-headers-5.8.0-050800rc7-generic_5.8.0-050800rc7.202007262231_amd64.deb
セクターサイズが 4K バイトの /dev/loop0
の上に dm-ebs を重ねることで、セクターサイズが 512 バイトの hello
というデバイスを作ります。
$ DEV=/dev/loop0 $ echo "0 $(sudo blockdev --getsz ${DEV}) ebs ${DEV} 0 1" | sudo dmsetup create hello $ lsblk -t NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC ROTA SCHED RQ-SIZE RA WSAME loop0 0 4096 0 4096 4096 1 mq-deadline 256 128 0B └─hello 0 4096 0 4096 512 1 128 128 0B ... $
マウントしてみると何事もなかったかのように読み書きできます。
$ sudo mount /dev/mapper/hello /mnt/ $ ls /mnt/ hello.txt $ cat /mnt/hello.txt Hello, world! $ echo "Hello, dm-ebs!" | sudo tee /mnt/hello.txt Hello, dm-ebs! $ cat /mnt/hello.txt Hello, dm-ebs! $
現実的に困る状況
512e ディスクと 4Kn ディスクが混在することで困った状況になる現実的な設定として LVM のボリュームグループ (VG) にディスクを追加して論理ボリューム (LV) を拡大した場合があります。この問題は2013年から指摘されていました。
まず 512e のディスクだけで VG を構成して LV を作成し、その上に XFS のファイルシステムを作成したとします。このとき LV の論理セクターサイズは 512 バイトになります。
この VG に 4Kn のディスクを追加します。
このあと LV を拡大すると、LV の論理セクターサイズは、LV のエクステントが乗っているディスクの中で最大の論理セクターサイズになります。すなわちこのような状況では 512 バイトから 4K バイトに変わってしまいます。
このような場合でもやはり XFS をマウントできなくなってしまいますが、LV の上に dm-ebs を重ねることでファイルシステムの読み書きができることを確認しました。
まとめ
dm-ebs を使って 4Kn のディスクの論理セクターサイズを 512 バイトに見せかけることで問題が発生した場合のワークアラウンドとして使えることを確認しました。