xfsのちょっとした調査

投稿者: | 7月 6, 2020

超久々の投稿。今回はLinuxのxfsについて、そもそもxfsはSGI IRIXのファイルシステムらしい。
大学時代SGI IRIXの運用も実は担当していて、サーバのOSを片っ端からいれていた。必ずインストールメディアを10枚以上のCDメディアを2回挿入する必要があったのだが。。。多分メディアにはオブジェクトファイルしかはいっていなくて、インストール時にリンクしていたんじゃないかと疑っていたり。。。

閑話休題
LinuxのxfsにはCOW(Copy on Write)が実装されているらしい。それを使うためにはファイルシステムフォーマット時からちょっとしたコツがいる。

まずは利用できるかどうかの確認。比較的新しいものは、カーネルバージョンやモジュールの確認をすることを癖にしたいところ。
また、OSやカーネルバージョンが異なったり、xfsprogsのバージョンが異なると不具合が発生する場合があるので要注意。

自分の環境は、Ubuntu 18.04.4 LTS。
cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION=”Ubuntu 18.04.4 LTS”
uname -r
4.15.0-106-generic
lsmod | grep xfs
xfs                  1204224  1
libcrc32c              16384  2 xfs,raid456
modinfo xfs
filename:       /lib/modules/4.15.0-106-generic/kernel/fs/xfs/xfs.ko
license:        GPL
description:    SGI XFS with ACLs, security attributes, realtime, no debug enabled
author:         Silicon Graphics, Inc.
alias:          fs-xfs
srcversion:     483E2FAA26259522319BFA2
depends:        libcrc32c
retpoline:      Y
intree:         Y
name:           xfs
vermagic:       4.15.0-106-generic SMP mod_unload
signat:         PKCS#7
signer:
sig_key:
sig_hashalgo:   md4

ちなみに、

dmesg | less
XFSで検索するとこんなも記載がある。
[42285.088293] SGI XFS with ACLs, security attributes, realtime, no debug enabled
[42285.095229] XFS (sdb1): EXPERIMENTAL reflink feature enabled. Use at your own risk!
[42285.095711] XFS (sdb1): Mounting V5 Filesystem
[42285.134057] XFS (sdb1): Ending clean mount

おいおい。ubuntu 18.04でもreflinkは、Experimentalなのかい!

xfsにまつわるコマンドは以下。mkfs.xfsとかが含まれている。

dpkg -l xfsprogs
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                                        Version                    Architecture               Description
+++-===========================================-==========================-==========================-============================================================================================
ii  xfsprogs                                    4.9.0+nmu1ubuntu2          amd64                      Utilities for managing the XFS filesystem

ファイルシステムフォーマットは以下のコマンドラインで行う。reflinkとcrcを有効にする。crcは、CRC32 に基づいて、突然の停電などでメタデータが破損するのを保護するのに役に立つ。

mkfs.xfs -b size=4096 -m reflink=1,crc=1 /dev/sdb1
meta-data=/dev/sdb1              isize=512    agcount=4, agsize=6553472 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1
data     =                       bsize=4096   blocks=26213888, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=12799, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

xfsをマウントしておこう。
この表示を後で見るには、xfs _infoコマンドを利用する。自分は諸事情で/backupにマウントした。

xfs_info /backup
meta-data=/dev/sdb1              isize=512    agcount=4, agsize=6553472 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1
data     =                       bsize=4096   blocks=26213888, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=12799, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

これで設定自体は終わり。
さて、使い方だが、xfsやbtrfsですでにcpコマンドでサポートをされていたりする。

cpコマンドのマニュアル
https://linuxjm.osdn.jp/html/GNU_coreutils/man1/cp.1.html

–reflink[=WHEN]
clone/CoW コピーを制御する。下記を参照

その下記がこちら
–reflink[=always] が指定された場合、軽量コピーが実行されデータブロック が変更された場合にのみコピーされます。そうでない場合、コピーが失敗した 場合、または –reflink=auto が指定された場合、通常のコピーにフェイル バックされます。

つまり、cpコマンドに–reflink-alwaysとかつけておけばいいらしい。ちなみに–reflink=neverというのはできないらしい。


cp –reflink=always file1 file2

これで終わりらしい。

以下からは実機での確認。
公平を記すためにext4のファイルシステムで1GBのテストデータを作成
cd /tmp
dd if=/dev/urandom of=testfile1 bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 7.9756 s, 135 MB/s

また、もとのxfsの容量は
df -t xfs
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sdb1      524029956 3688416 520341540   1% /backup
df -ht xfs
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb1       500G  3.6G  497G   1% /backup

これをxfsの領域に持っていく。
cp /tmp/testfile1 /backup/test

容量は1GB増えた。当たり前だが。
df -t xfs
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sdb1      524029956 4736992 519292964   1% /backup
df -ht xfs
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb1       500G  4.6G  496G   1% /backup

実際にCoWを確認してみる。
cd /backup/test
cp -v –reflink=always testfile1 testfile2
‘testfile1’ -> ‘testfile2’
なんかコピーが速い。

ファイルシステムの表示を確認してみる。(lsのオプションの「s」は、実際のファイルシステムでの利用量も表示してくれる。
ls -lhs
total 2.0G
1.0G -rw-r–r– 1 root root 1.0G Jul  5 17:19 testfile1
1.0G -rw-r–r– 1 root root 1.0G Jul  5 17:22 testfile2
どうやらスパースファイルとかみたいになっていない模様。これだとどうだかさっぱりわからない。

xfsにはエクステントという概念があるので、実際に利用しているエクステント、つまり、実際のファイルシステムの格納場所を調べてみる。

filefrag -v testfile1 testfile2
Filesystem type is: 58465342
File size of testfile1 is 1073741824 (262144 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  262143:         20..    262163: 262144:             last,shared,eof
testfile1: 1 extent found
File size of testfile2 is 1073741824 (262144 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  262143:         20..    262163: 262144:             last,shared,eof
testfile2: 1 extent found
ファイルシステムの場所は同じところを指している!!!

ファイルシステムの容量的にはこんな感じ
df -t xfs
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sdb1      524029956 4736992 519292964   1% /backup
df -ht xfs
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb1       500G  4.6G  496G   1% /backup

1GBのテストファイルをコピーしてきたときと容量が変わっていない。つまり、xfs内でコピーしても容量が増えていない。
つまり、testfile1とtestfile2は実際には同じものなので、容量は1つ分、1GBしか使っていない。
勘違いしないで欲しいのは重複排除をしているわけではなくあくまでも2つのファイルが同一ファイルを見ているに過ぎない。
普通の重複排除は、ファイルシステムの外からファイルがコピーされた結果で重複排除がされているのだがこのreflinkはあくまでもファイルシステムの中だけで起きている。
違うかもしれないが、ファイルシステム内でのハードリンクファイルにどちらかというと近い。
よって、ファイルシステムの中でCoWが起きないと効果が得られない。(ファイルシステム内でCopyが起きて初めて効果を発揮する。)

余談だけど、MacOSのAPFSにもこれに近い機能がついている。
MacOSのFinder.appでファイルの複製をするとすごく速いのはこれと同じ。
コマンドラインだとcp -c testfile1 testfile2とすることで同じことが体験できる。

このファイルシステムは仮想マシンのイメージファイルの運用に便利そうだな。

もっと違うテスト
以下のコマンドで500ファイルにコピーした。つまり500GBになるはず。
for i in {1..500}; do cp –reflink=always testfile1 dummy_${i}.dat ; done
一瞬で終了。

作成確認
ファイル数
ls -1 | wc -l
501 (実はtestfile2は消したのでこれで正解)

reflinkされているかの確認。(代表でファイルdummy_100.datを使う)
filefrag -v testfile1 dummy_100.dat
Filesystem type is: 58465342
File size of testfile is 1073741824 (262144 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  262143:         20..    262163: 262144:             last,shared,eof
testfile: 1 extent found
File size of dummy_100.dat is 1073741824 (262144 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  262143:         20..    262163: 262144:             last,shared,eof
dummy_100.dat: 1 extent found

ファイルの確認
ls -lhs testfile1 dummy_100.dat
1.0G -rw-r–r– 1 root root 1.0G Jul  5 18:22 dummy_100.dat
1.0G -rw-r–r– 1 root root 1.0G Jul  5 17:22 testfile1

ディレクトリ容量の確認
du -sh
502G    .

dfでの確認
df -t xfs
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sdb1      524029956 4737240 519292716   1% /backup
df -ht xfs
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb1       500G  4.6G  496G   1% /backup

500GBのファイルがあるはずなのに。。。利用容量が増えていない!つまり500ファイル全てが同じエクステントにある。
CPUやメモリの利用量とかを調べようと思ってsysstatを仕込んでおいたが。。。無駄だった。1GBのファイルの500コピーが1秒以内で終わったので。

 

ちなみに、xfsには一応重複排除をしてくれるツールがあるにはある。
https://github.com/markfasheh/duperemove
Ubuntu 18.04にも入っているといえば入っているんだが。

dpkg -l duperemove
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                                        Version                    Architecture               Description
+++-===========================================-==========================-==========================-============================================================================================
ii  duperemove                                  0.11-1                     amd64                      extent-based deduplicator for file systems

このツールはbtrfsとxfsで利用可能で、xfsでは以下のようにして利用する。

duperemove -hdr –hashfile=./dedup.hash .

あまりにも大量にメッセージが表示されて追えず。。。

Using 128K blocks
Using hash: murmur3
Gathering file list…
Using 4 threads for file hashing phase
[1/2] (50.00%) csum: /backup/test/testfile1
[2/2] (100.00%) csum: /backup/test/testfile2
Total files:  2
Total hashes: 16384
Loading only duplicated hashes from hashfile.
Using 4 threads for dedupe phase
〜略〜
[0x55be2cf90940] Dedupe 1 extents (id: d288da8f) with target: (37.6M, 128.0K), “/backup/test/testfile1”
[0x55be2cf90800] (1507/8192) Try to dedupe extents with id d27a8030
[0x55be2cf908a0] Dedupe 1 extents (id: d26379ff) with target: (775.9M, 128.0K), “/backup/test/testfile1”
[0x55be2cf90800] Dedupe 1 extents (id: d27a8030) with target: (763.9M, 128.0K), “/backup/test/testfile2”
[0x55be2cf90940] (1506/8192) Try to dedupe extents with id d288da8f
[0x55be2cf908f0] (1509/8192) Try to dedupe extents with id d254e24c
[0x55be2cf908a0] (1508/8192) Try to dedupe extents with id d26379ff
[0x55be2cf90800] (1510/8192) Try to dedupe extents with id d2525ec3
[0x55be2cf90940] Dedupe 1 extents (id: d288da8f) with target: (37.6M, 128.0K), “/backup/test/testfile2”
[0x55be2cf908f0] Dedupe 1 extents (id: d254e24c) with target: (708.0M, 128.0K), “/backup/test/testfile1”
[0x55be2cf90800] Dedupe 1 extents (id: d2525ec3) with target: (402.2M, 128.0K), “/backup/test/testfile1”
[0x55be2cf908a0] Dedupe 1 extents (id: d26379ff) with target: (775.9M, 128.0K), “/backup/test/testfile2”
[0x55be2cf90940] (1511/8192) Try to dedupe extents with id d23cc8b0
[0x55be2cf90800] (1510/8192) Try to dedupe extents with id d2525ec3
〜略〜
[0x55be2cf908a0] Dedupe 1 extents (id: 0001ba6b) with target: (490.5M, 128.0K), “/backup/test/testfile2”
[0x55be2cf90800] Dedupe 1 extents (id: 00008319) with target: (723.9M, 128.0K), “/backup/test/testfile1”
[0x55be2cf90800] (8192/8192) Try to dedupe extents with id 00008319
[0x55be2cf90800] Dedupe 1 extents (id: 00008319) with target: (723.9M, 128.0K), “/backup/test/testfile2”
Kernel processed data (excludes target files): 2.0G
Comparison of extent info shows a net change in shared extents of: 0.0

先ほどのtestfile1とtestfile2が入っているフォルダでやってみたが結構時間がかかる。たかが各1GBのファイルなんだが。

ls
dedup.hash  testfile1  testfile2

dedup.hashというファイルができていた。何だろう?

file dedup.hash
dedup.hash: SQLite 3.x database, last written using SQLite version 3022000

SQLiteのデータベースファイルかぁ。眠いから開かないで放置。このコマンド結構リソース食いそう。

結果は、同じファイルだったから何も変わらなかった。他のファイルをやれば少しは結果がでたのかもしれないが。
他のブログでは少しは空き容量が増えたという声もあったが。

再度環境を変えてテスト
一度、testfile2を削除して、testfile1を/tmpにコピーして改めて/tmpからtestfile1をtestfile2としてみた。
rm testfile2
cp testfile1 /tmp
cp /tmp/testfile1 testfile2
filefrag -v testfile1 testfile2
Filesystem type is: 58465342
File size of testfile1 is 1073741824 (262144 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  262143:     262164..    524307: 262144:             last,eof
testfile1: 1 extent found
File size of testfile2 is 1073741824 (262144 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  262127:     524308..    786435: 262128:
   1:   262128..  262143:          0..        15:     16:     786436: last,unknown_loc,delalloc,eof
testfile2: 2 extents found

エクステントが変わっているのでもう一度duperemoveを利用してみる。
duperemove -hdr –hashfile=./dedup.hash . | tee output.txt

filefrag -v testfile1 testfile2
Filesystem type is: 58465342
File size of testfile1 is 1073741824 (262144 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  262143:     524308..    786451: 262144:             last,shared,eof
testfile1: 1 extent found
File size of testfile2 is 1073741824 (262144 blocks of 4096 bytes)
ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..  262143:     524308..    786451: 262144:             last,shared,eof

少しだけ効果があったようだ。

 

しかし、このコマンドは大変危険なのでやらないほうがいいかも。このコマンドでファイルシステムがクラッシュしたらほんと目も当てられない。
まして、NASでなんかやった暁には。。。自分のSynologyはbtrfsだから誘惑にかられそうになったが。。。

ということでxfsファイルシステムの調査は終わり。

コメントを残す