起動パーティションを含むzpoolの再構築

※注意※ ここにある操作例はZFSに対する操作の 心得がないと何かあった場合に全てを失うので、参考にする場合は 仮想化環境などで練習してから行なうこと。

zpoolのフラグメンテーションが酷くなると100倍とか1000倍とか 壊滅的に遅くなるのは周知のとおり。 zpool再構築するには一旦外付けHDDあたりに別のpoolを作って zfs send/recv でやりとりする。

以下、外付けHDDがda0だとする。

: 念のため既存パーティションをふっとばす
dd if=/dev/zero of=/dev/da0 count=64
: GPTのパーティション群を作る
gpart create -s gpt da0
gpart add -t freebsd-boot -s 512k da0
gpart add -t freebsd-swap -s 2g da0
gpart add -t freebsd-zfs da0
: ブートコードの書き込み
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0
zpool create -R /tmptank tank1 da0p2
zfs snap -r tank0@fullbackup
time idprio 30 zfs send -vR tank0@fullbackup | zfs recv -vuFd tank1

idprio 30としたのは稼動中のサーバに影響を与えにくくするため。

で、これが完了するまで結構時間がかかり、 その間にいろいろファイル書き込みが発生するので全てのコピーが終わったら 改めてその間の差分をsend/recvする。大体こんな感じ。

shutdown now
zfs umount -a
for z in `zfs list -r -t snap -H -oname tank0 \
	| cut -d@ -f1|sort -u`; do
  : 特定のデータセットz直属のsnapshotの作成時刻順一覧を得る
  snaps=`zfs list -H -t snapshot -d1 -s creation -o name $z`
  first=`echo "$snaps"|head -1`
  last=` echo "$snaps"|tail -1`
  echo "zfs send -v $first | zfs recv -vFdu $dst"
  echo "zfs send -v -I $first $last | zfs recv -vFdu $dst"
done

これでよさそうなら

!! | sh

として差分を送り込む。これでバックアップ完了。

新HDDからブートできるようにする。

zpool set bootfs=tank1/ROOT/default tank1

ROOT/default の部分は、実際には df / で調べたROOTパーティションのデータセット名を 新zpoolのものに置き換えたものにする。

既存HDDを外して新HDDから起動できるか確認。 新HDDのまま運用してよいならこれでおしまい。

元のHDDに書き戻ししなければならないなら、 同じ操作を逆方向で繰り返せばよいのだが、新旧HDDを両方つないだ状態だと 同じディレクトリに2つのデータセットがマウントされるので厄介。 新HDDからシングルユーザモードで起動し、すぐに zpool destroy OLDPOOL する。うまく行かなければ 先に別マシンにつなぐか、FreeBSDインストールCDから起動するなどして 古い方のzpoolを破壊してからつなぎ直すようにする。