2009年10月9日金曜日

page fault while in kernel mode ??


ハードディスクの全セクタ検査をやっている間、VMware Workstation で実験環境を作ってみたのですが、gmirrorしたディスクの上でzfsを動かすと、何故かリブートの度に gm0 のrebuildが走ってしまい、起動時にzfsプロセスがpage fault を起こす、という、GEOMなのかzfsなのかVMware Workstationなのか原因がはっきりしないトラブルに見舞われました。とりあえず記録。あやしいことをやっていることは確かなのです(^^;

環境:VMware Workstation 6.5.3 build-185404
ホストOS: Microsoft Windows Server 'Longhorn' Business 6.0.6002, Service Pack 2 (32bit)
ゲストOS: FreeBSD/amd64 8.0-RC1 (64bit)

やったこと:
仮想メモリ1536MBの仮想PCを作成。それに30GBの仮想ドライブを2台(da0, da1)作成し接続。
うち1台(da0)にFreeBSD/amd64 を "User" インストールする。
ただし、OSのインストールには10GB程度しか使わず、残り20GBは空けておく。
OSインストール終了後、FreeBSD ハンドブックを参考にしてgmirrorでミラーリングする。
(zfsを使うよう /boot/loader.conf や /etc/rc.conf を書き換えておく。)
ミラーリング出来たら、空き容量のある mirror/gm0s1 に見えるので、
# gpart add -b xxxxx -s xxxxxx -t freebsd-zfs
で空いてる部分を mirror/gm0s1g として作成する。
この mirror/gm0s1g を使って、zfsの領域を作成、適宜マウントする。
# zpool create tank mirror/gm0s1g
# zfs create tank/home
# zfs create tank/export
# zfs create tank/ulocal
# mkdir /home /export
# zfs set mountpoint=/home tank/home
# zfs set mountpoint=/export tank/export
# zfs set mountpoint=/usr/local tank/ulocal
# zfs set mountpoint=none tank

このあたりはいろいろなサイトに載っている普通の手順かと思います。
が、どういう訳かここで再起動すると、上記スクリーンショットのようなFatal errorが起きます。原因はよく分かりません。さて、実機でも同様なことが起こるのでしょうか……?

2009年10月8日木曜日

結局HDD障害だったようです。

先日からatacontrolでRAID1が構築出来なかった件ですが、その後 gmirror に乗り換えてみたところ……


ad16: FAILURE - READ_DMA status=51 error=40 LBA=93492224
GEOM_MIRROR: Request failed (error=5). ad16[READ(offset=47868018688, length=131072)]
GEOM_MIRROR: Synchronization request failed (error=5). mirror/gm0[READ(offset=47868018688, length=131072)]

というわけで、どうやらHDD障害だったようです。

カーネルパニックを起こしたatacontrolと違い、こんなエラーがあってもmirrorを続けるgmirrorはすごいですね。しかしこれでは使えない。エラーがあると思われる領域は /usr にあり、/usr/src を展開しようとしたら、その作業が止まってしまいました。

ディスクがエラーで使えないと分かったら即座にOfflineにするatacontrolの振る舞いも理解出来るんですが、まさかその使えないディスクを元にして懸命にrebuildしてたとは思わなかったようです。

mhddでチェックしたところ、当該部分はUNCとしてXがついてました。ただ、mhddがError:として返してきた位置は 93492434 なんですが、atacontrolのときやgmirrorのときに返された値とは若干ずれてます。やはりHDDとしてダメだったというこなのでしょう。ディスク障害に備えて新品のHDDで環境を構築しようとしたら、その前段階でコケるとは。

ところでmhddのフルスキャン、1TBのディスクをチェックするのに3時間弱かかります。で、とりあえずチェックしないといけないHDDは3本。これは……また帰りが遅くなりそうです。

2009年10月7日水曜日

atacontrolでRAID1を作り直す→失敗してデータ消失?

先日PCを新調しました。
Intel Core i7-860 + GIGABYTE GA-P55-UD3R という新しめのハードに、FreeBSD/amd64 8.0-RC1 という挑戦的な仕様です。(dmesgは後日。)

で、実験がてら、ICH10Rの機能でRAID1を組み、一端FreeBSDをインストール。その後、ケーブルを抜いてみてRAID1をDEGRADEさせ、そこから復旧させようと思ったのですが……

ar0: WARNING - mirror protection lost. RAID1 array in DEGRADED mode
ar0: 953867MB status: DEGRADED
ar0: disk0 READY (master) using ad16 at ata8-master
ar0: disk1 DOWN no device found for this subdisk

起動時にこんな感じにメッセージが出ると、RAID1がおかしくなっている証拠。

# atacontrol status ar0
ar0: ATA RAID1 status: DEGRADED
subdisks:
0 ad16 ONLINE
1 ---- MISSING (←実際の障害の内容でここは書き換わると思います。)
# atacontrol list (ダメになったディスクがどのataチャンネルにあったか見る。)
ATA channel 9:
Master: no device present (抜いたディスクは本来ここにあった。)
Slave: no device present
# atacontrol detach ata9 (この例ではata9になる。) 
電源を切ってディスク交換。ホットスワップでもいいのかな?
# atacontrol attach ata9 (必要ないかも?)
Master: ad18 SATA revision 2.x
Slave: no device present
# atacontrol status ar0
ar0: ATA RAID1 status: DEGRADED
subdisks:
0 ad16 ONLINE
1 ---- MISSING (ないことになっている)
# atacontrol addspare ar0 ad18
# atacontrol status ar0
ar0: ATA RAID1 status: DEGRADED
subdisks:
0 ad16 ONLINE
1 ad18 SPARE  (スペア扱いになる)
# atacontrol rebuild ar0 (指示出しだけなので一瞬で終わる。)
# atacontrol status ar0
ar0: ATA RAID1 status: REBUILDING 0% completed
subdisks:
0 ad16 ONLINE
1 ad18 SPARE

この処理をマルチユーザモードでやっており、リビルド作業をインターネット経由で行っていました。リビルドコマンドを投入した後、viでちょっとしたスクリプトを書いていたところ、ファイルをセーブしたところでフリーズ。

コンソール画面を見ると、

......
g_vfs_done():ar0s1a[WRITE(offset=1348632576, length=16384)]error = 5
g_vfs_done():ar0s1a[WRITE(offset=1348698112, length=16384)]error = 5
g_vfs_done():ar0s1a[WRITE(offset=1541259264, length=16384)]error = 5
g_vfs_done():ar0s1a[WRITE(offset=2311831552, length=16384)]error = 5
g_vfs_done():ar0s1a[WRITE(offset=2697117696, length=16384)]error = 5
g_vfs_done():ar0s1a[WRITE(offset=3082403840, length=16384)]error = 5
panic: initiate_write_inodeblock_ufs2: already started
g_vfs_done():cpuid = 0
ar0s1d[WRITE(offset=65536, length=2048)]Uptime: error = 5
47m24s
Cannot dump. Device not defined or unavailable.
Automatic reboot in 15 seconds - press a key on the console to about

落ちてました。リビルドはシングルユーザモードでやったほうがいいということでしょうか。

で、もう一度RAID1を構成しなおしOSを入れ、今度はシングルユーザモードで試してみました。

# zfs umount -a   (zfsのほうからマウント解除)
# umount -a     (ufsのほうをマウント解除)
# atacontrol detach ata9
# atacontrol attach ata9 (意図的にDEGRADEさせる)
# atacontrol addspare ar0 ad18
# atacontrol rebuild ar0
(とここまでは手順通り)
# echo "ttt" >> /test.txt
# echo "ttt" >> /test.txt   つい魔が差してやってしまった。
# echo "ttt" >> /test.txt
# sync
# atacontrol status ar0
ar0; ATA RAID1 status: REBUILDING 1% completed
subdisks:
0 ad16 ONLINE
1 ad18 SPARE
# (放置後数分経過)
ad16: FAILURE - READ_DMA status=51 error=40 LBA=93492352
ar0: FAILURE - RAID1 array broken
ad18: WARNING - WRITE_DMA taskqueue timeout - completing request directly
atacontrol: read: Input/Output error
WARNING - WRITE_DMA48 freeing taskqueue zombie request
リビルドに失敗してBROKEN扱いです……

なお、困ったことに、こうなってから再起動した後で、BIOSのRAID調整メニューから見たときドライブが Offline Member になっていると、RAID1は破損。リビルドは絶望的なようです。再マウントしてデータを取り出せるかどうかは分かりません。あまりに危険な状況なので、もし試される場合はお手元の余りHDDでお試し下さい。

次こそは悪戯せずにrebuildに挑戦…と思いましたが、台風が近いので帰ることにします。

2009年10月6日火曜日

続:FreeBSDのdump -Lってzfsに対応してますか?

昨晩書いた話の続きなんですが、一晩よく寝て改めて確認してみたら、いくつか勘違いしていることに気づきました。話を整理しましょう。

まず、dumpは伝統的に ファイルシステム単位でバックアップするものであり、tarやrsyncなどのようなファイル単位でのバックアップツールではないこと。
よって、ファイルシステムが異なる場合は、それに対応するダンプ用のコマンドを用いるのが適切であること。例えばSolarisであればufsdump/ufsrestoreという名前になっている。

zfs send は snapshotをダンプするコマンドであること。よってdump -Lとは扱いが異なる(バックアップ前に手動でsnapshotを作る作業が必要?)。dumpと同様に標準出力やファイルへの書き込みが可能なので、バックアップ先のファイルシステムは問わない。ただしFreeBSD 8.0RC1のマニュアルには
The format of the stream is evolving. No backwards compatibility is
guaranteed. You may not be able to receive your streams on future
versions of ZFS.
などと書いてあるのでOSのメジャーアップデートの際は気をつけましょう。

実際のところ、FreeBSDのdumpはzfsに対応していません。FreeBSD/amd64 8.0-RC1で実行しようとすると。

# df /home
Filesystem 1K-blocks Used Avail Capacity Mounted on
zfstank/home 850525952 58368 850467584 0% /home
basil# dump -0aLu -f /backup/home-amd64-091006.zfsdump /home
DUMP: WARNING: Cannot use -L on an unmounted filesystem.
dump: /home: unknown file system
という結果となりました。そりゃ、そうか。素直に zfs sendを使いましょう。

何故dumpにこだわるのかというと、FreeBSDにはchflags (Linuxで言うとchattr)で調整できる拡張ファイル属性があり、これがバックアップ作業に影響することがあるため。例えばrsyncなどでうまく処理出来なかったりします。

というわけで、先日のエントリで無知を晒したわけですが、いつものことなので気にしない分からなくなったらとりあえず寝てから整理する、というのは重要ですね、ということで。

debian/ubuntuでは dump パッケージを導入します。それでも ext2/3 までの対応で、snapshotを取ってダンプする機能があるようには見えませんでした。FreeBSD dump でufs2をダンプしたものを Linux restore でext2/3に移動出来るかは分かりません。他のファイルシステムについては、ext4についてはdump/restore可xfsはxfsdump/xfsrestoreがある、btrfsはよく分かりません。開発中?

2009年10月5日月曜日

FreeBSD の dump -L ってzfsに対応してますか?

職場PCを新調する機会があり、HDDを増設し、FreeBSD 8.0-RC1 を導入しました。

もののついでに、ちょっとバックアップ体制について見直したのですが、最近は dump(8) に -L オプションなるものがついていて、これを実行すると、丁寧にも一端スナップショットを取得してからdumpする、という振る舞いを見せます。つまりシングルユーザモードに落ちなくても稼働中にdumpが出来るというわけです。これはかなり便利。

ところが、このスナップショットを取得する部分が、ファイルシステムが巨大(100GB以上?)になると途端に処理が重くなります。どうも、ufs2のスナップショットを取得する /sbin/mksnap_ffs に原因があるようです。

http://www.freebsd.org/cgi/query-pr.cgi?pr=111782
600GBくらいのファイルシステムを-Lでダンプしようとするとおかしくなる?(6.x系列)
mksnap_ffs time
シリンダグループの数が多すぎると遅くなる、らしい。

そこで、最近流行の zfs に乗り換えれば、もしかしたらスナップショットの取得も早くなり、dumpも気軽に出来るのかな、と思ったのですが、ここでふと疑問。dumpオプションの-Lは zfs に対応しているのでしょうか?

(バックアップ元のファイルシステムが zfs であるときに、バックアップ先のHDDもzfsにして、zfs send/receive を使うのが筋としては適切、というのは分かるのですが、バックアップ先のHDDがzfsではない、とか、実は未だにテープを愛用している、とか、dump系のシェルスクリプトを書き直すのがちょっとなあ……等といった状況を想定しています。)

dump(8) は -L オプションが実行されると、スナップショットを取得するコマンドを用いるのですが、コードを見ると……
http://www.freebsd.org/cgi/cvsweb.cgi/src/sbin/dump/main.c?rev=1.67.2.1;content-type=text%2Fplain

char snapname[BUFSIZ], snapcmd[BUFSIZ];

snprintf(snapname, sizeof snapname, "%s/.snap", mntpt);
if ((stat(snapname, &sb) < 0) || !S_ISDIR(sb.st_mode)) {
msg("WARNING: %s %s\n",
"-L requested but snapshot location",
snapname);
msg(" %s: %s\n",
"is not a directory",
"dump downgraded, -L ignored");
snapdump = 0;
} else {
snprintf(snapname, sizeof snapname,
"%s/.snap/dump_snapshot", mntpt);
snprintf(snapcmd, sizeof snapcmd, "%s %s %s",
_PATH_MKSNAP_FFS, mntpt, snapname);
unlink(snapname);
if (system(snapcmd) != 0)
errx(X_STARTUP, "Cannot create %s: %s\n",
snapname, strerror(errno));
if ((diskfd = open(snapname, O_RDONLY)) < 0) {
unlink(snapname);
errx(X_STARTUP, "Cannot open %s: %s\n",
snapname, strerror(errno));
}
unlink(snapname);
if (fstat(diskfd, &sb) != 0)
err(X_STARTUP, "%s: stat", snapname);
spcl.c_date = _time_to_time64(sb.st_mtime);
}

ここでスナップショットを取得するコマンドが _PATH_MKSNAP_FFSとして定義されているようです。これ、どこにあるのかというと…
http://www.freebsd.org/cgi/cvsweb.cgi/src/include/paths.h?rev=1.28.2.1;content-type=text%2Fplain

#define _PATH_MKSNAP_FFS "/sbin/mksnap_ffs"

これ。で、このソースを見ると、
http://www.freebsd.org/cgi/cvsweb.cgi/src/sbin/mksnap_ffs/mksnap_ffs.c?rev=1.10.2.1;content-type=text%2Fplain

読み切れませんでしたorz

とりあえず、zfsだからといって zfs snapshot を使っているようにも見えず、正直よく分からないのですが、さて、zfsのファイルシステムを dump -L でダンプすることは出来るのでしょうか? それとも、zfsだと実はわざわざスナップショットを取る必要がない、とか?

追記:後日談を書きました。