多分5年以上使っていたNAS, TS-219PについているHDDの2台のうち片方が壊れた。Software RAID1構成なので、交換してリビルドすればいいという話だったはずなのだが、長期戦になってしまった。
今回は時系列に沿って。日数はフィクションです。仕事の話じゃなくてよかった(仕事だったらもっと慎重だったろうから、こんなんにならないと思うけど)。
1日目: 拡張できるはずだったのに
もともと2TB x 2本の構成だった。もちろん2TBを買ってきて取り替えればよい。だが、容量を拡張できる機能があることがわかったので、2015年現在のGB単価的(→
サハロフの秋葉原レポート)に4TBにしようと思って4TBを2本買ってきた。
もちろん、時代的に4TB扱えなくてもそういうものかという感じな気がするので、compatibility listを見て4TBに対応していることを確認して買った。
ところが、4TBを差しても認識しない。ファームウェアがだいぶ古いので、アップグレードしてみることにする。
2日目: ファームウェアアップグレード
ファームウェアアップデートすると、今度は生きている2TBのディスクまでWeb管理画面から見えなくなってしまった。sshログインを使って、cat /proc/filesystemsを見ると、ext4がいない。ファームウェアの更新がうまくいかなかったのかなと思って再度更新をかけようとすると、バージョンを確認しろという旨のエラーが出て受け付けてもらえない。
バージョンがとんでもなく変わっていたので、変化に耐えられなかったのであろう。もうだめだ。ブラックボックスな独自OSで戦うのはここで限界。汎用OSで使えるものを探そう。
3日目: Debianインストール チャレンジ
Debianが使えないかなと調べてみると、Martin Michlmayr さんという方がまとめてくれている。手順まで詳しく載っており、これは戦えそうである。
→
Debian on QNAP TS-21x/TS-22x
インストール手順は
Installing Debian on QNAP TS-21x/TS-22xにある通り、
まずフラッシュ領域をバックアップする(後にわかることだが、これは大変に重要であり、絶対に避けてはいけない。)
vfatもマウントできない状態なので、別のマシンでUSBメモリをext2でフォーマットしておいたものを挿入し、catでコピーする。
mount /dev/sdX1 /tmp/usb
cd /tmp/usb
cat /dev/mtdblock0 > mtd0
cat /dev/mtdblock1 > mtd1
cat /dev/mtdblock2 > mtd2
cat /dev/mtdblock3 > mtd3
cat /dev/mtdblock4 > mtd4
cat /dev/mtdblock5 > mtd5
cd
umount /tmp/usb
そうしたら、カーネルやインストーラの入ったinitrdをダウンロードし、flash-debianスクリプトを起動する。
cd /tmp
busybox wget http://ftp.debian.org/debian/dists/stable/main/installer-armel/current/images/kirkwood/network-console/qnap/ts-219/initrd.gz
busybox wget http://ftp.debian.org/debian/dists/stable/main/installer-armel/current/images/kirkwood/network-console/qnap/ts-219/kernel
busybox wget http://ftp.debian.org/debian/dists/stable/main/installer-armel/current/images/kirkwood/network-console/qnap/ts-219/flash-debian
busybox wget http://ftp.debian.org/debian/dists/stable/main/installer-armel/current/images/kirkwood/network-console/qnap/ts-219/model
sh flash-debian
リブートするよう促されるので、rebootした。
reboot
DHCPでアドレスが払い出されるので、そのアドレスに対してinstallerユーザでsshログインする。
$ ssh installer@192.168.1.XX
cursorsのUIが起動し、インストーラが開始する。あとは選べばよいだけ……のように見えた。
4日目: インストーラが途中で止まる
普通のDebianインストーラだと安心し進んでいくと、パッケージのインストールのプログレスバーが途中で止まってしまう。最初からやり直しても同じ。
何度かディスクの構成を変えながら試してみても変わらないので、もう一つinstallerユーザでsshし、shellを選び/var/logのログを見ていると「UUID ~ doesn't exist in /dev/disk/by-uuid」なるログが。
そのキーワードを基に検索してみると、こんなバグ報告を発見。
#791794 - INSTALL REPORT (Jessie on QNAP TS-420U)
どうやらmdでミラーを組んでしまうと、/dev/disk/by-uuidのIDが更新されず、flash-kernelという裏で動くmtdデバイスにカーネルイメージを書き込むツールが書き込みに失敗するらしい。このツールがエラー終了するのではなく、Ctrl+C待ちで止まってしまっているので、フロントのインストーラのプログレスが止まったままとなっていたようだ。
書いてある感じに、ディスクの構成が終わったタイミングでもうひとつssh接続し、shellに降りて
udevadm tigger
とすることで、進むようになった。
このバグで触れられていたために、mdで作られたRAIDミラーがdegradedだと、起動時にemergency shellに落ちるという恐怖のバグを発見。通常コンソールのないこのNASでは、sshできない状態に落とされるのは致命的である。
#784070 - mdadm Software RAID1 with GPT on Debian 8.0.0 amd64 - Does not mount/boot on disk removal
おすすめされる行為ではないが、sidには修正済みのパッケージがあったため、バージョンの変化やdependencyなどを見てsidから持ってきて入れた。実際に1本外して試したところ、きちんと立ち上がるようになっていた。
LVMを構成したり、NFSやSambaなどなどNASっぽいデーモンをインストールしたりする。Ansibleで作ったのでやりなおせる。
5日目: rsyncデータコピー待ち
USB接続した元々の2TB HDDからrsyncでデータをコピーする。たいへんに時間がかかるが、待つしかない。
6日目: 再起動したら……
データのコピーも終わり、デーモンの動作もOK, 念のため再起動を試しておく。
……立ち上がらない。コンソールがないので状況もわからない。
11/30: フラッシュ・リカバリ
Martinさんはリカバリの方法も書いてくれていたので、QNAP NASのリカバリの手順でインストーラを起動して中の様子を見てみることにする。
Recovery mode of QNAP TS-21x/TS-22x
TS-219Pのリカバリモードは、ブート時にtftpでリカバリイメージを取得し、フラッシュ領域を書き直す。
debian-installerを動作させるイメージを作るには、まずカーネルイメージにpaddingを加えて所定のサイズにする。
dd if=kernel of=kernel.pad ibs=2097152 conv=sync
あとはinitrd.gzと、もともとのmtdblockイメージを連結して作る。取っててよかったバックアップ!
cat mtdblock0 mtdblock4 mtdblock5 kernel.pad initrd.gz mtdblock3 > F_TS-219
このファイル名は、u-boot パラメータが格納されているmtdblock4に入っているので念のため確認しておく。
strings mtdblock4 | grep bootp_vendor_class
次に、適当なノートPCを使ってDHCPサーバ + TFTPサーバを立てる。Martinさんは普通にdhcpdで立てているようだが、dnsmasqはそのどちらの機能も備えており、さくっと立てることができた。
あとは、NASをdnsmasqを立てたノートPCと直結し、背面にあるLANコネクタの隣あたりにあるピンで押すリセットボタンを押しながら、電源ボタンを押して起動する。すると、ピー、ピーと短く鳴って起動する。
その時のコマンド・ログはこんな感じだった。
$ sudo dnsmasq --no-daemon --port=0 --interface=eth0 --domain=example.com \
--dhcp-range=192.168.0.3,192.168.0.253,255.255.255.0,1h --dhcp-boot=F_TS-219 \
--enable-tftp --tftp-root=`pwd`
dnsmasq: started, version 2.75 DNS disabled
dnsmasq: compile time options: IPv6 GNU-getopt DBus i18n IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset auth DNSSEC loop-detect inotify
dnsmasq-dhcp: DHCP, IP range 192.168.0.3 -- 192.168.0.253, lease time 1h
dnsmasq-tftp: TFTP root is /tmp/ts219
dnsmasq-dhcp: DHCPDISCOVER(eth0) 00:08:9b:XX:XX:XX
dnsmasq-dhcp: DHCPOFFER(eth0) 192.168.0.216 00:08:9b:XX:XX:XX
dnsmasq-dhcp: DHCPREQUEST(eth0) 192.168.0.216 00:08:9b:XX:XX:XX
dnsmasq-dhcp: DHCPACK(eth0) 192.168.0.216 00:08:9b:XX:XX:XX
dnsmasq-tftp: sent /tmp/ts219/F_TS-219 to 192.168.0.216
--no-daemonで起動すると、わざわざtail -fしなくてもログが追え便利であった。
10分程待つと再びピー、ピーと音がなり、再起動される。すると、無事に同じようにinstaller@で接続できるようになった。
インストーラが起動したら、ディスクの設定画面まで進めたあと、別のssh接続を行い、shellに降りる。shellが起動したら、以下のようにchrootを実行して、ディスク上の環境を得る。
mount /dev/md0 /mnt/md0
mount --bind /dev /mnt/md0/dev
mount --bind /proc /mnt/md0/proc
mount --bind /sys /mnt/md0/sys
chroot . bin/bash
fstabがおかしいかなと新しく作ったエントリをコメントアウトしたりした。終わったら、元のカーネルに戻すべくフラッシュする。
flash-kernel
rebootすると、無事起動した。原因についてははっきりわかっていないが、おそらく、fstabうんぬんではなく、USB接続したディスクをmdデバイスとして見せた状態でinitrdを更新してしまったために、変な情報を覚えられてしまったのかなと思っている。ディスクが見えなくなるから起動しなくなるかもよみたいなことを書いてあった記憶。
7日目: USBシリアルからコンソール出せれば便利じゃね?
ブートオプション変更すればUSBシリアルにコンソール出せるんじゃね?このデバイスはU-Boot使ってるからfw_setenvでブートオプション変更できるんじゃね?と思ったらやっぱりあった。
U-Boot tools for Debian ARM Linux in QNAP Server | Black God
ダメでもどうせフラッシュすればいいやーと思って書き換えてみることにする。
まずは設定。
$ cat /proc/mtd
dev: size erasesize name
mtd0: 00080000 00040000 "U-Boot"
mtd1: 00200000 00040000 "Kernel"
mtd2: 00900000 00040000 "RootFS1"
mtd3: 00300000 00040000 "RootFS2"
mtd4: 00040000 00040000 "U-Boot Config"
mtd5: 00140000 00040000 "NAS Config"
# vi /etc/fw_env.config
(書き込み)
# Configuration file for fw_(printenv/saveenv) utility for
# QNAP TS-119, TS-219 and TS-219P.
# MTD device name Device offset Env. size Flash sector size
/dev/mtd4 0x0000 0x1000 0x40000
確認。
# fw_printenv
ttyUSB0を使うように書き換え(コマンドはイメージです:
注:このデバイスでのコンソールアクセスがない状態での書き換えはやってはいけません)
# sudo fw_setenv bootargs 'console=ttyS0,115200 root=/dev/ram initrd=0xa00000,0x900000 ramdisk=32768'
再びfw_printenvを実行してみると、書き換わっている。
いざ再起動……立ち上がらない。まぁいいや、リカバリならもう慣れた……リカバリ完了。立ち上がらない!?
8日目: カーネルビルドという選択肢
試しにPCでUSBシリアルを接続し、grubからconsole=ttyUSB0として起動しようとしてみると、起動しない。先にやっておくべきだった!
でもU-Bootのコンフィグが入っているのは先に見たようにmtd4。フラッシュイメージにはmtd4が入っている。直るはずだ!
とMartinさんのページをよく見てみると、こんな記述が。
During recovery mode, mtd0 (the boot loader), mtd4 (the boot loader configuration) and on some devices mtd5 (device configuration) are ignored
……なぜここを読み飛ばしてしまっていたのか。mtd4はリカバリでは戻らない。やってしまった……
U-Bootのコンソールを叩きにいけば直るはずなので、シリアルコンソールに接続してコマンドを叩けば直る。でも現状その接続はない。そこでもう一つの選択肢。設定されたbootargsで立ち上がるカーネルを作ればよい。
ということで、活躍していないsqueezeのarmelデバイスがあったので、これを使ってlinux-sourceをダウンロード。中に入っているはずのカーネルパッケージに含まれるconfigを見ると、どうもCONFIG_USB_SERIAL=mであるのが影響していそうだ。
ということで、=yになるようmake menuconfigでちょいちょいといじって、カーネルを作り直す。起動しない。linux-sourceからのカーネルビルドの手順にまったく沿っていないためか、そもそも元のconfigで作り直しても全然違うサイズになる。やり方が雑過ぎたようだ。
9日目: クロスビルド環境でのカーネルコンパイル(失敗)
make menuconfigを眺めていると、ブートオプションを強制するオプションがあった。.config的にはこんな感じである。
CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram initrd=0xa00000,0x900000 ramdisk=32768"
CONFIG_CMDLINE_FORCE=y
なおビルドについては、armelデバイスが古すぎるためか、一晩寝てもコンパイルが完了しない。これでは時間がかかりすぎるので、クロスビルドするしかないか、と思って適当なページを見ながら、適当なUbuntu 15.10のマシンを使ってコンパイルするも、コンパイルエラー。まともに環境を作ろうとすると大変そうなのでこのビルド方式はあきらめ。
How do I cross-compile the kernel on a Ubuntu host? - Raspberry Pi Stack Exchange
$ sudo apt-get install git ncurses-dev make gcc-arm-linux-gnueabi
(カーネルとconfigを配置/展開)
make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- oldconfig
make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- menuconfig
make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- zImage
10日目: そもそもarmelをエミュレーションした環境でビルドする(途中)
そういえばx86なマシンでもqemu使えばarmel環境をエミュレーションできるんじゃね?ということで環境を作る。
qemu-debootstrapを使ってユーザモードQEMUで動くDockerイメージを作ってみる - ももいろテクノロジー
$ sudo apt-get install debootstrap qemu-user-static
$ sudo qemu-debootstrap --verbose --arch=armel --variant=buildd \
--include=vim-tiny,less jessie rootfs-debian-armel http://http.debian.net/debian/
$ sudo chroot rootfs-debian-armel
今度こそjessieになったので
HowToRebuildAnOfficialDebianKernelPackageの手順を使ってビルドしてみる。armel指定の部分はこんな感じ。
# fakeroot make -f debian/rules.gen setup_armel_none_kirkwood
# fakeroot make -f debian/rules.gen binary-arch_armel_none_kirkwood binary-indep \
DEBIAN_KERNEL_JOBS=4
普通に進んでいたので、このままほっとけばできたのかもしれないが、4つコアを使っている感じがなく時間がかかりすぎて作業時間オーバー。とりあえず断念。
11日目: そしてシリアルコンソールへ
カーネルビルド方式では、リカバリまで含めての試行錯誤の1ターンがかかりすぎるので、ついにシリアルコンソールに手を出すことにした。ここで失敗するとハードウェア破壊を意味するので、あまりやりたくなかったのだ。
やりかたはMartinさんがピン配置を書いてくれているので、この通り接続する。
Serial console for QNAP TS-21x/TS-22x
コネクタはPHR-4というもので
千石電商の2Fにあったので買ってケーブルとピンヘッダに差すコネクタをハンダ付けしてケーブルを作った。
RS-232Cレベルではなく、3.3Vなので昔買ったFT232RLの変換アダプタにつなげばよさそうだなーと思ったが、Raspberry Piのシリアルピン使えるんじゃね?とRasPiの存在を思いだし、RasPiが登場。TS-219P - RasPiをTx - Rx, Rx - Tx, GND - GNDで接続した。
RasPi側ピン
(
https://www.raspberrypi.org/documentation/usage/gpio/)より
TS-219P側ピン
黄: Tx
黒: Vcc (接続しない)
赤: Rx
青: GND
シリアルポートの場所はここ。ケースは固いので開けたくなかったが、開けないと手が届かない。
RasPiは、ブートオプションconsole=に当該ポートが指定されていて使えないので、/boot/cmdline.txtを編集してconsole=ttyAMAの記述をトル。
http://elinux.org/RPi_Serial_Connection
console=パラメータの変更はまさに悩んでいる部分なので、こうさらっと変更できると複雑な気分。
あとは起動して、
$ cu -s 11200 -l /dev/ttyAMA0
として待つ。あとはTS-219Pをブートすればコンソールが現れるのでauto-bootを止める。あとはsetenv, saveしてブート。
__ __ _ _
| \/ | __ _ _ ____ _____| | |
| |\/| |/ _` | '__\ \ / / _ \ | |
| | | | (_| | | \ V / __/ | |
|_| |_|\__,_|_| \_/ \___|_|_|
_ _ ____ _
| | | | | __ ) ___ ___ | |_
| | | |___| _ \ / _ \ / _ \| __|
| |_| |___| |_) | (_) | (_) | |_
\___/ |____/ \___/ \___/ \__| ** LOADER **
** MARVELL BOARD: DB-88F6281A-BP LE
U-Boot 1.1.4 (Jan 5 2009 - 12:58:51) Marvell version: 3.4.4
U-Boot code: 00600000 -> 0067FFF0 BSS: -> 00690DCC
Soc: MV88F6281 Rev 3 (DDR2)
CPU running @ 1200Mhz L2 running @ 400Mhz
SysClock = 400Mhz , TClock = 200Mhz
(略)
Hit any key to stop autoboot: 0
QNAP: Recovery Button pressed: 0
Marvell>> printenv
(略)
Marvell>> setenv bootargs console=ttyS0,115200 root=/dev/ram initrd=0xa00000,0x900000 ramdisk=32768
Marvell>> saveenv
Saving Environment to Flash...
................................................................
.
Un-Protected 1 sectors
Erasing Flash...
.
Erased 1 sectors
Writing to Flash... done
................................................................
.
Protected 1 sectors
Marvell>> printenv
baudrate=115200
(略)
bootargs=console=ttyS0,115200 root=/dev/ram initrd=0xa00000,0x900000 ramdisk=32768
Environment size: 1339/4092 bytes
Marvell>> boot
Unknown command 'uart1' - try 'help'
## Booting image at 00800000 ...
Image Name:
Created: 2015-12-02 15:12:54 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1968432 Bytes = 1.9 MB
Load Address: 00008000
Entry Point: 00008000
Verifying Checksum ... OK
OK
Starting kernel ...
Uncompressing Linux... done, booting the kernel.
無事起動。これでちゃんと起動するDebian環境が得られた。
おわりに
USBシリアルでコンソールを見ようというのは本当に余計だった。
自分の環境ではこんな目にあってしまったが、今まで見てきたARMデバイスの中ではDebian officialで済む範囲が多いデバイスなので、Debianを入れてみるというのはアリだと思う。カーネルイメージは公式のものを使えなかったり、ファンコントロールは外部だったりといったことが多いが、これはどちらもofficialに含まれている。
もちろんメーカーの力は得られなくなるので、いわゆる自己責任で。新しく買ってきてというよりは、昔の保証切れてそうな箱でやってみるという感じがよいかとは思う。