それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

btrfsを使う前に調査。雰囲気で使ってるbtrfsをよく知ろう。

btrfs の練習

僕も、雰囲気でbtrfsを使ってる。

  • サブボリューム
  • スナップショット
  • マウント
  • スクラブ ( scrub )
  • デフラグ
  • バックアップ(send/receive)
  • スパニング(LVM/raid)
  • リサイズ
  • 重複排除
  • lxc storage

btrfsって多機能なんだぜ?でも、LVM+ext4で事足りるからあまり真剣に向き合って無いので、いい機会なので、使ったことない機能などを試して、自分にとって不明点を明らかにして調べることにした。

btrfs の作成

## パーティション作成
sudo sgdisk -Z /dev/sda
sudo sgdisk -n '0::+1G' /dev/sda
sudo sgdisk -n '0::+10G' /dev/sda
## btrfs 作成
sudo mkfs.btrfs /dev/sda1
sudo mkfs.btrfs /dev/sda2

作成されたことをcheckサブコマンドで確認

sudo btrfs check /dev/sda1
sudo btrfs check /dev/sda2

問題なく作成された

found 147456 bytes used, no error found

実験用に作る

実験するだけなら、適当なファイルを作って、フォーマットしてマウントすれば良い。

fallocate -l 128M sample.btrfs.img
mkfs.btrfs sample.btrfs.img
sudo mount -t auto sample.btrfs.img mnt

またはLoopバックデバイスを経由する

fallocate -l 128M sample.btrfs.img
sudo losetup -f sample.btrfs.img
DEV=$(sudo losetup | grep sample | cut -d ' ' -f 1 )
echo $DEV # /dev/loop10
mkfs.btrfs ${DEV}
sudo mount ${DEV} mnt

マウント・マウント解除

btrfs をマウントしてみる。

sudo mount /dev/sda1 /mnt

マウントのチェック

findmnt /mnt

正常にマウントされている。

TARGET SOURCE    FSTYPE OPTIONS
/mnt   /dev/sda1 btrfs  rw,relatime,ssd,space_cache=v2,subvolid=5,subvol=/

中身を見てみる。ext4 みたいなlost foundはない。root権限になっている

# ls -l /mnt
total 0
# ls -ld /mnt
drwxr-xr-x 1 root root 0  5月 19 16:07 /mnt
# touch /mnt/hello

問題なく作成された。

マウントを解除

sudo umount /mnt

サブボリュームを使う

最初にマウントする。

sudo mount /dev/sda1 /mnt

サブボリュームを一覧する

sudo btrfs  subvolume  list /mnt

サブボリュームを作る。

sudo btrfs  subvolume  create /mnt/subA

サブボリュームを一覧する

sudo btrfs  subvolume  list /mnt

実行結果の例

ID 256 gen 15 top level 5 path subA

サブボリューム内部にファイルを作る

sudo touch /mnt/subA/in-sub-a.txt

サブボリュームをマウントする(名前で指定)

sudo mount -o subvol=/subA /dev/sda1 /mnt

サブボリュームをマウントする(IDで指定)

sudo mount -o subvolid=256 /dev/sda1 /mnt

マウント結果の例。サブボリューム内部だけが見える。

ls /mnt
in-sub-a.txt

サブボリュームを削除する

sudo btrfs  subvolume delete /mnt/subA/

サブボリュームは、単なるディレクトリ?

単なるディレクトリとして考えても問題ないと思う。サブボリュームはディレクトリのすごいヤツ

ディレクトリと同名のサブボリュームは作成できない。

例:ディレクトリが存在するとサブボリュームが作れない。

# ls /mnt
dirA  hello
# btrfs  subvolume  create /mnt/dirA
ERROR: target path already exists: /mnt/dirA

ディレクトリと競合するのがSubvolumeである。ディレクトリの一種と考えておくといいだろう。(我々利用者から見るとディレクトリにしかみえない)

ディレクトリをサブボリュームに変換する方法

サブボリュームがディレクトリと同じように見えるとしても、サブボリュームとディレクトリの相互変換はできない。かわりに、名前をつけてrsyncでデータを抜き出すしか無いかも。

サブボリュームを移動する(名前変更)

上記で述べたように、サブボリュームは単なるディレクトリとして扱える。

サブボリュームの名前の変更(移動)は単純にmvコマンドを使う。ディレクトリとして扱うだけ

sudo mv subA/ subAA

実行結果の例。

$ sudo btrfs subv list  /mnt/
ID 257 gen 24 top level 5 path subAA

上記のように、mv コマンドでディレクトリ名変更でサブボリューム名が変更されている。ディレクトリ操作である。「我々利用者から見るとディレクトリと思っておけば良い。」という理由である。

スナップショットを使う。

スナップショットは、サブボリューム。

btrfs subvolume snapshot /mnt/src_name/ /mnt/snap_name
sudo muont /dev/sda1 /mnt
sudo touch /mnt/s1/sodium.txt

動作サンプル

sudo btrfs subvolume snapshot /mnt/s1/ /mnt/s1.snap
Create a snapshot of '/mnt/s1/' in '/mnt/s1.snap'

スナップショットとの差分を作る

sudo touch /mnt/s1/sodium_hydroxide.txt

スナップショットとオリジナルの差分を見てみる。

sudo ls /mnt/s1*/s*.txt

スナップショット時点と違いが出ても保持されているとわかる。

sudo ls -l /mnt/s1*/s*.txt
-rw-r--r-- 1 root root 0  5月 19 21:21 /mnt/s1.snap/sodium.txt
-rw-r--r-- 1 root root 0  5月 19 21:21 /mnt/s1/sodium.txt
-rw-r--r-- 1 root root 0  5月 19 21:24 /mnt/s1/sodium_hydroxide.txt

スナップショットは単なるサブボリュームである。

読み取り専用モード

スナップショットをバックアップの目的で作るならread onlyで作る。

## read only
sudo btrfs subvolume snapshot -r /mnt/s1/ /mnt/s1.snap.ro
## read write
sudo btrfs subvolume snapshot -r /mnt/s1/ /mnt/s1.snap.rw

read only は次で使う。send / recieveで必要

send/recieve

send はbtrfsの中身を取り出してストリームにする。

receiveは ストリームを受け取って btrfs に書き込む

send / recieive の例

sudo btrfs send /mnt/s1.snap.ro/ | sudo btrfs receive /mnt/subB

実行後のスナップショット

sudo btrfs sub list /mnt
ID 256 gen 13 top level 5 path subA
ID 257 gen 20 top level 5 path subB
ID 258 gen 13 top level 5 path s1.snap.ro
ID 260 gen 21 top level 257 path subB/s1.snap.ro

サブボリュームの内部にファイルがコピーされた

send はファイルに書き出せる

sudo btrfs send /mnt/s1.snap.ro/ | cat - > out

書き出したファイルを見てみると。ストリームである。

hexdump -C out
00000000  62 74 72 66 73 2d 73 74  72 65 61 6d 00 01 00 00  |btrfs-stream....|
00000010  00 2e 00 00 00 01 00 a8  c3 e9 a1 0f 00 0a 00 73  |...............s|
00000020  31 2e 73 6e 61 70 2e 72  6f 01 00 10 00 93 7e dc  |1.snap.ro.....~.|
00000030  42 ca d0 f8 4f ae 65 e3  38 89 f1 69 9f 02 00 08  |B...O.e.8..i....|
00000040  00 0b 00 00 00 00 00 00  00 1c 00 00 00 13 00 02  |................|
00000050  37 2d 8c 0f 00 00 00 06  00 08 00 00 00 00 00 00  |7-..............|
00000060  00 00 00 07 00 08 00 00  00 00 00 00 00 00 00 10  |................|
00000070  00 00 00 12 00 59 55 75  35 0f 00 00 00 05 00 08  |.....YUu5.......|
00000080  00 ed 01 00 00 00 00 00  00 34 00 00 00 14 00 98  |.........4......|

このことから、tar などと同じく、パイプ転送ができることがわかる。

btrfs send /mnt/s1.snap.ro/ | ssh root@127.0.0.1 'btrfs receive /mnt/subC'

実行後のサブボリューム

sudo btrfs sub list /mnt
ID 256 gen 13 top level 5 path subA
ID 257 gen 20 top level 5 path subB
ID 258 gen 13 top level 5 path s1.snap.ro
ID 260 gen 23 top level 257 path subB/s1.snap.ro
ID 261 gen 25 top level 5 path subC
ID 262 gen 26 top level 261 path subC/s1.snap.ro

サブボリューム内部に、スナップショットが転送された。

別のパーティションでも試す。

別のディスクのパーティションへ転送してみたらどうなるのか。

sudo mount -t btrfs /dev/sdb1 /mnt2

別のパーティションへ転送する

btrfs send /mnt/s1.snap.ro/ | sudo btrfs receive /mnt2/an1/

転送結果から、無事に転送されたことがわかる。

sudo btrfs su list /mnt2/an1/
ID 256 gen 8 top level 5 path an1
ID 257 gen 11 top level 256 path s1.snap.ro

このことから、send/receiveでバックアップやdumpが取れる。

btrfs はサブボリュームをメインに使って、サブボリューム単位でスナップショットを取って使うのが良さそう。

ext4 のように、dump fs /restore fs が存在しないが、btrfs では send / reciveを使って同様っぽい

btrfs subvolume を省略する

subvolume は長いので、もう少し短くできる。

sudo btrfs su list  
sudo btrfs sub list 
sudo btrfs subv list
sudo btrfs subvol list 
sudo btrfs subvolu list
sudo btrfs subvolume list

scrub send subvolumeと3つあるので、btrfs s のように究極の省略はできない。

メンテナンス defrag / scrub / check

デフラグ(マウント中)

sudo btrfs filesystem defragment -r /mnt

チェック(アンマウント必須)

チェックコマンドは、ディスクの修正を兼ねている.

sudo umount /dev/sdb
sudo btrfs check /dev/sdb

ちょっとおかしい程度なら、 check して scan したら治ってることが多い。 repairしたこと無いし、使うことがない

スクラブ

スクラブ、時間がかかるので start -> status でfinishチェック

sudo btrfs scrub start /dev/sdb
sudo btrfs scrub status /dev/sdb

空き容量の確認 ( usage )

sudo btrfs filesystem usage /mnt

使用容量の確認

sudo btrfs filesystem df /mnt
sudo btrfs filesystem du /mnt

df / df より、usageをつかことが多くて詳しいことは知らない。

ssd trim

マウント時に、discardオプションを付けておくと、fstrimコマンドが使えるようになる。

mount -o discard 

discardには並列(非同期)があって、そちらのオプション( -o discard=async )も使えるらしい

LVM的に使う

btrfs では、lvmのように、複数のディスクにまたがったファイルシステムが作成可能です。

2つのディスクから1つのbtrfsを作る

2つのディスクを作る。

## 1 つめ
fallocate -l 128M sample.btrfs.img
sudo losetup -f sample.btrfs.img # /dev/loop10
## 2つ目
fallocate -l 128M sample2.btrfs.img
sudo losetup -f sample.btrfs.img # /dev/loop10

2つのディスクからBtrfsを作る。

mkfs.btrfs -m single /dev/loop10 /dev/loop11 

マウントすると、2倍の容量になってる。

$ sudo mount /dev/loop11 /mnt
$ df -h /mnt
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop10     256M  3.4M  242M   2% /mnt

マウントは、2つどちらをを指定しても同じようです。

ディスクの追加

LVMの特徴といえば、ディスクを柔軟に使えることだろう。btrfsでも同じようなことができる。

1本目のディスクを作成

sudo mkfs.btrfs -f /dev/loop10
sudo mount /dev/loop10 /mnt

2本目のディスクを追加

sudo btrfs device add /dev/loop11 /mnt

追加後の結果を表示(singleになっていて、容量が増えたことがわかる。)

$ sudo btrfs filesystem df /mnt
Data, single: total=8.00MiB, used=0.00B
$ sudo btrfs filesystem usage /mnt
Overall:
    Device size:                 256.00MiB

2本目のディスクを削除

sudo btrfs device remove /dev/loop11 /mnt

LVMはPVをremoveするときに、pvmove で別ディスクにデータを移して削除してくれるし、それはオンラインでしかもマウント継続中のまま行えたと思う。btrfsでも同じようだ。空き容量があれば、LVMみたいに自動的に移動してくれるっぽい。

ディスクを取り外す。(あまり使わない)

sudo umount /mnt
sudo btrfs device scan --forget /dev/loop11
sudo btrfs device scan
sudo mount /dev/loop10 /mnt

removeと間違えそうだ。使うときは、ディスクを取り出してミラーリングの別ディスクに付け替えるときだろうか。何も考えずに forgetしたら ディスクにアクセスできなくなった。scanをしたらディスクが再びマウント可能になった。

raid の場合

Raid1(ミラーリングで作る)

sudo mkfs.btrfs -d raid1 /dev/loop10 /dev/loop11
sudo mkfs.btrfs  /dev/loop10 /dev/loop11

Raid0(ストライピング)

sudo mkfs.btrfs -m raid0 /dev/loop10 /dev/loop11

シンプル(スパニング)

sudo mkfs.btrfs -m single /dev/loop10 /dev/loop11

ギョーカイでは常識なRAIDだけど、専用カードによるRAIDはよく壊れるので私は信用してない。ソフトウェアなら信じてもいいのだけど、Btrfsではどうなのでしょうね。Raid5/6には重大なバグがあるとかだから、raid0/1も過度に信用して良いものか迷う。

raidメタデータ

raidは、メタデータ-m と実データ-d について指定する。デフォルトはデータシングルメタデータdup

デフォルトの確認(オプションなし

$ sudo mkfs.btrfs /dev/loop10
$ sudo mount /dev/loop10 /mnt
$ sudo btrfs filesystem df /mnt
Data, single: total=8.00MiB, used=0.00B
System, DUP: total=8.00MiB, used=16.00KiB
Metadata, DUP: total=32.00MiB, used=128.00KiB
GlobalReserve, single: total=3.25MiB, used=0.00B

デフォルトの確認( -m single )

$ sudo mkfs.btrfs -f -m single /dev/loop10
$ sudo btrfs filesystem df /mnt
Data, single: total=8.00MiB, used=0.00B
System, single: total=4.00MiB, used=16.00KiB
Metadata, single: total=8.00MiB, used=128.00KiB
GlobalReserve, single: total=3.25MiB, used=0.00B

デフォルトの確認-d single

$ sudo mkfs.btrfs -f -m single /dev/loop10
$ sudo mount /dev/loop10 /mnt
$ sudo btrfs filesystem df /mnt
Data, single: total=8.00MiB, used=0.00B
System, DUP: total=8.00MiB, used=16.00KiB
Metadata, DUP: total=32.00MiB, used=128.00KiB
GlobalReserve, single: total=3.25MiB, used=0.00B

上記の結果からわかる通り、メタデータとデータがRaidになる。メタデータはデフォルトがDUPであり、実データは single であるとわかる。

このことは、mkfs.btrfsの実行結果にも出てくる。(たぶん最初のうちは読み飛ばしてると思う)

mkfs.btrfsの実行結果 の例

sudo mkfs.btrfs -f  /dev/loop10
btrfs-progs v5.16.2
See http://btrfs.wiki.kernel.org for more information.

Performing full device TRIM /dev/loop10 (128.00MiB) ...
NOTE: several default settings have changed in version 5.15, please make sure
      this does not affect your deployments:
      - DUP for metadata (-m dup)
      - enabled no-holes (-O no-holes)
      - enabled free-space-tree (-R free-space-tree)

-m dupの記述があるのがわかる。

  - DUP for metadata **(-m dup)**

RAIDは上記のことを踏まえた上で、指定して使う必要がある。

私はRAIDに愛情が全く無いのでこれ以上は調べてない。

btrfs の特徴

Btrfs には従来のExt2などと違う特徴を持ってる。

  • 遅延書き込み
  • 自動デフラグ
  • 自動圧縮
  • 重複排除

自動圧縮・自動デフラグ・遅延書込についてはマウントのオプションで指定する。

重複排除

重複排除 はbtrfs の特徴である。MacのAPFSも同じ特徴を備えている。

ただし、Btrfsではコピー時重複排除がメインで、CoW ( copy on write )の機能がある。

btrfsでは重複排除だからといって、同じファイルを別名で作成した場合は重複排除はされない。(この機能は、将来の夢であり、プラグインをインストールすると使えるらしい。)

cp --reflink

明示的にCoW を有効にするなら

cp --reflink=always

上記のようにオプションをつけないとreflink が生成されない。それをしない限りに置いてはCoWはうまく動作しないと思われる。

また、重複排除はdupremoveコマンドをを用いて重複ファイルをreflink へ変更する必要があり、こちらもマニュアルで動かすので、重複排除はあまり期待してはいけない。

commit 指定(遅延書き込み)

遅延書き込みについては参考資料

これはext4 と同じ。

LABEL=my / ext4  defaults,discard,errors=remount-ro,commit=300 0 1
LABEL=s0 / btrfs defaults,discard,errors=remount-ro,commit=300 0 1

commit 間隔はデフォルト30秒なので、それ以上に間隔を開けておけば、小さなファイルの見かけ上の速度向上はみられる。

SDカードなどは600秒とかにしておけば、書き込みタイミングをずらせるので寿命に寄与するかもしれない(そもそも、書込総量を減らしたり、無駄データを捨てたほうが圧倒的に寿命を長くするのだが、commitで書き込みをズラすと、更新箇所の上書き更新といった不要な書込みを減らせて寿命に寄与するかと)

自動圧縮( compress )

btrfs ではファイルを透過的に圧縮できる。ext4 にはこの機能がない。デフォルトはOFFである。

compress=zstd

zlib, lzo, zstd の3つから選ぶ。

何でもかんでも圧縮するわけでもなく、ファイルの先頭だけで圧縮を試して、圧縮が効果が上がると判明したときだけ、圧縮が行われる。チェックを飛ばして全ファイルを圧縮するオプションcompress-forceもある。

compress-force=zstdの、forceを使うと、速くなることがあるらしい

NTFSはすべて圧縮するので、compress-force の動作イメージに似ているかもしれない。

SDカードの場合は、このCompressオプションで圧縮してやると、データ総量が抑えられるので、SD寿命の延命に寄与することだろう。

自動デフラグ (autodefrag)

defaults,autodefrag

ただし、自動デフラグ無限ループになる可能性があり非推奨らしい

リサイズ

XFSは、容量の縮小ができない、なので不採用です。btrfsではどうなのでしょうか。

btrfsでもリサイズはサポートされています。ext4同じように扱えます。

マウントした状態で扱います。

# 1G にする
sudo btrfs filesystem resize 1G /mnt
# +5M にする
sudo btrfs filesystem resize +5M /mnt
# -15Mする
sudo btrfs filesystem resize -15M /mnt

このようにファイルシステムの実サイズを扱えるため、別途容量が必要になっても対応できます。

冒頭でXFSをDisりましたが、縮小ってあんまり使わない。容量が小さい別ディスクにコピーするときで事前に容量を揃えられない程度の問題で、実は必要ないんですよね。XFSが割り切った縮小って、なくても問題ないんですよね。縮小ができないXFSで困るのは、小さいディスクにコピーしたときにUUIDが変わっちゃうことなんですよね。同じラベルをつけ直すのが手間というか。fstab書き換えが面倒というか。その点においてbtrfsでは困りません。良かったです。

btrfsでは制限があって。/dev/loopのリサイズができない。

$ sudo mount sample.btrfs.img  /mnt
$ sudo btrfs filesystem resize -5M /mnt
Resize device id 1 (/dev/loop10) from 128.00MiB to 123.00MiB
ERROR: unable to resize '/mnt': Invalid argument

上記のように、ループバックデバイス経由で、イメージファイルを扱ってる場合は、リサイズができない。nbdではどうなのでしょうか。試してない。

lxd で btrfs を使うと

ubuntu にはLXD/LXCのコンテナが標準で入ってる。そのLXDのストレージにbtrfs や zfs使う事ができる。これらは共通のの機能があって、スナップショットが自動的作られるそうだ。

lxd を btrfs で使うと、次の機能が使える

  • snapshots.expiry 全自動で削除
  • snapshots.schedule 全自動スナップショット
  • snapshots.pattern 自動生成の名前規則

ふぁーすごい

ただ、scrubが必要など、btrfs のLXDでは、トラブル多かったのでメインに採用するのは避けたい。といってもzfsは扱いにくいしエラー時のリカバリが大変だったのでそれはそれで使いづらい・・・個人的にはbtrfsかなぁ

man pages

マニュアルの呼び出しに、少し癖があって

man btrfs-filesystem
man btrfs-send
man btrfs-scrub

btrfsのサブコマンドをハイフンにしてマニュアルを確認できる。細かいオプションが掲載されてて便利。

オンラインで見たいときは https://btrfs.readthedocs.io/en/latest/ が便利。

filesystemの場合はここを見ると読みやすい。

気づいたこと

btrfs はソコソコ完成していて、ext4 と同じように使える。

LVMの機能もあるので、ext4+lvmと同等なのが改めて理解できた。

サブボリュームは、ディレクトリってのが面白かった。

send / receive でパイプ転送できるってのが良い。でもスナップショットしか転送できないっぽいのが困る。

それなりに安定してるし、機能を見ると、btrfsで十分じゃんって思ってしまった。

次にインストールするときに、採用してみたい。

そうえいば、ファイルシステムといえば速度比較だけど。速度に興味がないので言及してない。高速nvme時代に、速度を気にする必要性に疑問です。

btrfsの速度比較とか言ってもlvm有無で変わるので信用してはいけないね。 その速度比較してるファイルシステムはスナップショット取れるんですか?圧縮できるんですか?と煽りたくなるね。

参考資料

ファイルシステムの本