dm-ebs で 4Kn ディスクの論理セクターサイズを 512 バイトに見せかける

ストレージ製品には論理セクターのサイズが 512 バイトのもの (512e) と 4K バイトのもの (4Kn) があり、混在している構成のシステムでは非常に厄介な問題を引き起こすことがあります。最近 Linux カーネルにマージされた dm-ebs という device mapper を使うと 4Kn のディスクの論理セクターサイズを 512 バイトに見せかけることができ、問題が発生した場合のワークアラウンドとして使うことができます。

注意

dm-ebs は Red Hat の開発者によって開発され Linux 5.8 に正式に含まれる可能性が高い機能ですが、開発されたばかりであるため利用の際は慎重な評価を行ってください。

発生する問題を確認する

512e のディスクの上に XFS のファイルシステムを作成したとします。今回は実験用として losetup コマンドで作成したループバックデバイス /dev/loop0 を利用します。

f:id:kujira16:20200802174759p:plain

バックアップためにこのディスクの中身をブロックデバイスレベルでファイルシステムごと別のディスクにコピーしたとします。このときコピー先のディスクが 4Kn だったとします。

f:id:kujira16:20200802175246p:plain

ここで もとのディスクが壊れてバックアップしたディスクをマウントしようとすると失敗します

確認してみましょう。まず 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 をマウントできるようにします。

f:id:kujira16:20200802184108p:plain

drivers/md/dm-ebs-target.cLinux 5.8 の rc にマージされた機能なので、Ubuntu では現時点の最新の LTS に含まれるカーネルを使ったとしても利用することができません。そのため Ubuntuカーネルチームが提供している mainline ビルドを利用しました。

gihyo.jp

現時点では 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年から指摘されていました。

bugzilla.redhat.com

まず 512e のディスクだけで VG を構成して LV を作成し、その上に XFS のファイルシステムを作成したとします。このとき LV の論理セクターサイズは 512 バイトになります。

f:id:kujira16:20200802191929p:plain

この VG に 4Kn のディスクを追加します。

f:id:kujira16:20200802192008p:plain

このあと LV を拡大すると、LV の論理セクターサイズは、LV のエクステントが乗っているディスクの中で最大の論理セクターサイズになります。すなわちこのような状況では 512 バイトから 4K バイトに変わってしまいます。

f:id:kujira16:20200802192320p:plain

このような場合でもやはり XFS をマウントできなくなってしまいますが、LV の上に dm-ebs を重ねることでファイルシステムの読み書きができることを確認しました。

f:id:kujira16:20200802192830p:plain

まとめ

dm-ebs を使って 4Kn のディスクの論理セクターサイズを 512 バイトに見せかけることで問題が発生した場合のワークアラウンドとして使えることを確認しました。