はじめに
表題の通り、新年早々やらかしました。備忘録として、あるいは、もしかして誰かの役に立つかもしれないので、事象発生から復旧までの流れをまとめたものを簡単に書いておきます。
1/4 朝: 移動
締め切りが非常に厳しい仕事をかかえる中、自宅から300kmほど離れた場所に移動。作業用マシンにはリモートアクセスできるので仕事には支障なし。の、はずだった。
1/4 夕方: 破壊
目的地に着いて、もろもろ落ち着いたので仕事を開始。テスト用のパーティションに書き込みをする簡単なプログラムを動かしていた。ここでタイプミスしてルートファイルシステムの先頭1GBくらいにランダムなデータを書いてしまうことにより、ぶっ飛ばした。即死はしなかったが、dmesgを見ると案の定カーネル(の中のファイルシステム)のバックトレースが出た上で、ルートファイルシステムが読み出し専用マウントされていた。
余談だが、ここでパーティションをopen()する際にO_EXCLを指定しておけば、マウント中のルートファイルシステムはEBUSYで開けないため、問題は発生していなかった。しかし、わずかな手間を惜しみ、ここをサボった*1。馬鹿じゃないの。
以下、man 2 openより抜粋。
In general, the behavior of O_EXCL is undefined if it is used without O_CREAT. There is one exception: on Linux 2.6 and later, O_EXCL can be used without O_CREAT if pathname refers to a block device. If the block device is in use by the system (e.g., mounted), open() fails with the error EBUSY.
1/4 夕方: リモート復旧の準備
このリモートマシンをなんとかデータを復旧した上で運用継続するにはどうすればいいか、頭をひねった。リモートマシンなのでリブートできないという制約が、なかなかに辛い。
いろいろ考えた末、次のような案を思いついた。
- 空いているパーティションに、作業用のルートファイルシステムを作る
- 1で作ったファイルシステムにchroot
- 破壊されたファイルシステムをumount
- 破壊されたファイルシステムのデータを可能な限りサルベージ*2
- 破壊されたファイルシステム上に、新たなルートファイルシステムを作る
- 5で作ったファイルシステムにchroot
- 定期バックアップデータからルートファイルシステムを復旧
- 死亡直前まで更新していたデータを、4でサルベージしたデータを用いて、出来る限り復旧
1と3のルートファイルシステム作成については次の2つの方法が考えられた。
- debootstrap
- Ubuntu Cloud Imagesからインストール済イメージを持ってきてddでフルコピー
友人たちと相談した結果、aを選択することにした。
どのデータが壊れているかわからないので、いつ死ぬかわからない運試しの作業だが、やるしかない。
1/4 夜: リモート復旧
作業開始。debootstrap起動時に
# deboo
とタイプした後にtabで補完しようとした段階で接続が切れる。即死。多分bash-completionに関するファイルを読もうとしてI/Oエラーによって死んだ。
もうやることがないので、ふて寝。
1/5 朝: 敗走
遠隔地で時間を空費するのはまずいので、自宅に敗走。1週間以上滞在するはずだったのだが、まさかの一日でとんぼ返り。人生は厳しい。
1/5 昼: ローカル復旧
バックアップのあるローカル復旧は、めんどくさいけど、言ってしまえば「やるだけ」。次のような手順で復旧。
- USBメモリにUbuntuインストーラを焼く
- 1で作ったものをlive USBメモリとして使って、起動
- 壊れたルートファイルシステムからデータをサルベージ
- Ubuntuをクリーンインストール
- バックアップデータを新ルートファイルシステムにコピー
- 死亡直前まで更新していたデータを、3でサルベージしたデータから出来る限り復旧
これは、とくに何事もなく成功した。直前まで更新していたソースコードや文書はうまくサルベージできたので、時間と金を浪費した以外に大した実害はなかった。不幸中の幸い。
おわりに
- フェイルセーフ大事
- 二度とやりたくない
- IPMI搭載マシンほしい