削除できないZFSのZIL(slog)を強制的に削除するお話です。
(このブログでZFSの話題を取り上げるのは3年ぶり…!)
ZIL(ZFS Intent Log)というかSLOG(Separate Intent Log)なデバイスをzpoolコマンドで取り外そうとしても取り外せないという現象が長年使ってるプールで起きることに気が付きました。
詳しい現象は以下のとおり。
※作業中に記録とってなかったのでコマンドの実行結果は実際のものではないです。そのため辻褄が合わない部分があるかもしれませんが、重要な部分はなるべく再現するようにしました。
root@localhost:~ # zpool status tank
pool: tank
state: ONLINE
scan: resilvered 0 in 0h32m with 0 errors on Sun Nov 29 02:32:14 2015
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
ada1 ONLINE 0 0 0
ada2 ONLINE 0 0 0
ada5 ONLINE 0 0 0
ada6 ONLINE 0 0 0
ada3 ONLINE 0 0 0
ada4 ONLINE 0 0 0
logs
ada0s3 ONLINE 0 0 0
errors: No known data errors
root@localhost:~ # zpool remove tank ada0s3
root@localhost:~ # echo $?
0
root@localhost:~ # zpool status tank
pool: tank
state: ONLINE
scan: resilvered 0 in 0h32m with 0 errors on Sun Nov 29 02:32:14 2015
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
ada1 ONLINE 0 0 0
ada2 ONLINE 0 0 0
ada5 ONLINE 0 0 0
ada6 ONLINE 0 0 0
ada3 ONLINE 0 0 0
ada4 ONLINE 0 0 0
logs
ada0s3 ONLINE 0 0 0 ← 頑固
errors: No known data errors
root@localhost:~ # zdb
tank:
version: 5000
name: 'tank'
state: 0
txg: 5771422
pool_guid: xxxxxxxxxxxxxxxxxxxx
hostname: 'localhost'
vdev_children: 1
vdev_tree:
type: 'root'
id: 0
guid: xxxxxxxxxxxxxxxxxxxx
children[0]:
type: 'raidz'
id: 0
guid: xxxxxxxxxxxxxxxxxxxx
nparity: 2
metaslab_array: 23
metaslab_shift: 36
ashift: 12
asize: xxxxxxxxxxxxxx
is_log: 0
children[0]:
type: 'disk'
id: 0
guid: xxxxxxxxxxxxxxxxxxxx
path: '/dev/ada1'
phys_path: '/dev/ada1'
whole_disk: 0
DTL: 106
### 途中省略 ###
children[5]:
type: 'disk'
id: 5
guid: xxxxxxxxxxxxxxxxxxxx
path: '/dev/ada4'
phys_path: '/dev/ada4'
whole_disk: 1
DTL: 51
children[1]:
type: 'disk'
id: 0
guid: xxxxxxxxxxxxxxxxxxxx
path: '/dev/ada0s3'
metaslab_array: 38
metaslab_shift: 24
ashift: 9
asize: xxxxxxxxxx
is_log: 1
removing: 1 ← 削除中
create_txg: 428
features_for_read:
com.delphix:hole_birth
com.delphix:embedded_data
root@localhost:~ # zpool iostat -v tank
capacity operations bandwidth
pool alloc free read write read write
------------ ----- ----- ----- ----- ----- -----
tank 10.1T 805G 0 0 1.35K 1.10K
raidz2 10.1T 805G 0 0 1.35K 1.10K
ada1 - - 0 0 1.01K 1.13K
ada2 - - 0 0 995 1.09K
ada5 - - 0 0 1.24K 1.08K
ada6 - - 0 0 939 1.06K
ada3 - - 0 0 1012 1.11K
ada4 - - 0 0 953 1.09K
logs
ada0s3 4K 21G 0 0 251 4.28K
------------ ----- ----- ----- ----- ----- -----
↑ココ(これ自体は特に珍しい現象ではない?)
root@localhost:~ # zpool replace tank ada0s3 ada7s1
### 自動的にresilverが開始されるのでしばらく経ったのち ###
root@localhost:~ # zpool status tank
pool: tank
state: ONLINE
scan: resilvered 0 in 0h32m with 0 errors on Sun Nov 29 06:55:21 2015
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
ada1 ONLINE 0 0 0
ada2 ONLINE 0 0 0
ada5 ONLINE 0 0 0
ada6 ONLINE 0 0 0
ada3 ONLINE 0 0 0
ada4 ONLINE 0 0 0
logs
ada7s1 ONLINE 0 0 0 ← replaceできた
errors: No known data errors
という感じです。
実はこの現象だいぶ前から気づいていて、色んな操作をやってみたのですが全く解消されず、諦めて放置してました…
slogデバイスを物理的に取り外したいときは、面倒ですが身代わりのデバイス(※)を用意してreplaceすればよいですし…
※物理デバイスを用意するのは大変なので、実際はよくスパースファイルを割り当てたりしてました。
ただこんなこといつまでもやってられないし気持ち悪かったので、今回思い切って対策してみました。
対策内容としては、slogを強制削除するようZFSのカーネルモジュールのソースを書き換えコンパイルして実行する、という非常に危険な方法です。
ただ、ZFSのソースや後で紹介するパッチを見てもらうと分かると思うのですが、ファイルシステムそのものを直接弄るような変更ではないですし、またパッチはすごく短くそれ自体で削除を実行するようなものではないですし、zpool importしてzpool removeしてzpool exportするだけの一回限りの環境で使用するだけなのでまぁ大丈夫かなと。
もちろん一切保証はしませんが。
b333z/zfs_slog_zero_vsalloc_inline.patch
※長くなるので逐一コマンドを表記したりはしませんが、ほとんど全て一般的な操作なので調べれば色々情報は出てきますしさほど難しくはないでしょう。
パッチはLinux用ですが、私が使用してるのはNAS4Free 10.2とFreeBSD 10.2なので、そのまま適用はできません。
しかし重要な部分はそのまま使えました。
以下作業内容(箇条書き)
まずは対象のPCに新しいストレージを追加して、そこにFreeBSD 10.2をインストールして起動。
そしたら、
/usr/src/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c
の spa_vdev_remove_from_namespace 関数を以下のように変更。
※3行追加しただけ。追加部分をサンドイッチするようなコメントの書き方は嫌いですが、この記事を書くにあたって分かりやすくするために書きました。
/*
* Complete the removal by cleaning up the namespace.
*/
static void
spa_vdev_remove_from_namespace(spa_t *spa, vdev_t *vd)
{
vdev_t *rvd = spa->spa_root_vdev;
uint64_t id = vd->vdev_id;
boolean_t last_vdev = (id == (rvd->vdev_children - 1));
ASSERT(MUTEX_HELD(&spa_namespace_lock));
ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
ASSERT(vd == vd->vdev_top);
// 追加ここから
if (vd->vdev_islog == 1 && vd->vdev_removing == 1 && vd->vdev_state == VDEV_STATE_OFFLINE && vd->vdev_stat.vs_alloc > 0) {
vd->vdev_stat.vs_alloc = 0;
}
// 追加ここまで
/*
* Only remove any devices which are empty.
*/
if (vd->vdev_stat.vs_alloc != 0)
return;
(void) vdev_label_init(vd, 0, VDEV_LABEL_REMOVE);
if (list_link_active(&vd->vdev_state_dirty_node))
vdev_state_clean(vd);
if (list_link_active(&vd->vdev_config_dirty_node))
vdev_config_clean(vd);
vdev_free(vd);
if (last_vdev) {
vdev_compact_children(rvd);
} else {
vd = vdev_alloc_common(spa, id, 0, &vdev_hole_ops);
vdev_add_child(rvd, vd);
}
vdev_config_dirty(rvd);
/*
* Reassess the health of our root vdev.
*/
vdev_reopen(rvd);
}
そしたらカーネルの再構築。
以下のページを参考にしました。
最近はもっと良いやり方があるらしいですが、古いやり方でも今回は特に問題ありませんでした。
FreeBSD – How to build kernel
新しいカーネルで再起動したら、普通に対象のプールをzpool importし(状況によってはslogを無視するために-mオプションが必要かも)、zpool offlineでslogをオフラインにし(※)、zpool removeでslogを削除しました。
この時点でzpool statusするとslogが消えてました。
※パッチのifでデバイスがオフラインになってるかどうかもチェックしてるのでzpool offlineが必要になります。
あとはzpool exportしてから、本来の環境で再起動。
これでプールに余計なslogが無い状態で今までどおり使えているようです。
最初、VMwareの仮想マシン上にslogの強制削除環境を構築し、ddで実ストレージにイメージコピーし、ターゲットのPCで起動しようとしたのですが、なんか起動しませんでした。
起動プロセス的には結構最後に近い方まで進むんですがkernel panicで落ちる感じです(※)。
※実のところ表示が一瞬過ぎてよく分からなかったのです…
Linuxだとハードウェアが変わるとinitramを再作成しないと起動しなかったりとかはあるんですが、FreeBSDのことはよく知らないですし、そのとき眠くて頭が動かなかったので、FreeBSDのインストールからカーネルの再構築まで実機でやり直しました。
ident以外はGENERICそのままのconfigでコンパイルしたんですが、コンパイル環境のHWに応じて自動的にモジュールが取捨されるのだろうか…
あと今回取り上げた現象、検索してみると結構同じような報告があって、もしかしたらslogの削除に未対応だった時代からzpool upgradeしながら使い続けているプールのかなりの割合で同じ問題が起きているのではなかろうかと思いました。
最近のコメント
たかたむ
はじめまして。初リアルフォース(R3ですが)で,同…
nokiyameego
ZFS poolのデバイスラベル破損で悩んていたと…
名前
しゅごい
Jane Doe
FYI Avoid Annoying Unexpe…
Jane Doe
ご存じとは思いますが、whileには、”~の間”と…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…
花粉症対策2019 – 日曜研究室
[…] 花粉症対策についてはこれまで次の記事を書いてきました。https://…