壊れたのは Windows と外付けのハードディスク2017年03月05日 16時29分40秒

Windows を壊して外付けのハードディスクも壊した。今回壊れたのは結局ハードディスク二つの MBR だった。

Windows の方は起動不可能だが、CD から起動した FreeBSD で見るとパーティションは壊れていない。そこで、このディスクの MBR のバックアップは古かったので、パーティション構成が違っていたはず。そのため、MBR を修復する前に、FreeBSD で第三と第四パーティションのデータを複製。

その後、古い MBR のバックアップで、元に戻す。FreeBSD の dd で 512 バイトのみ。

$ dd if=rv515-ada0.mbr of=/dev/ada0 bs=512 count=1
この後、案の定、第三と第四パーティションは見えなくなったが、取り敢えず Windows は起動するようになり、第二パーティションのデータは無事だった。

外付けのディスクは、バックアップはとても古いものしか無かった。こちらは、比較的最近 FreeBSD を起動できる様に再構成したものだった。どうもこちらは、パーティションテーブルも壊したようで、後部のパーティションの復帰は無理そう。古いバックアップの MBR を戻しても、第一パーティションのあったデータは無事見えるようになったが、それ以降のパーティションは無理だった。システムの複製が入っていただけなので、被害は軽微。

壊れた外付け USB ディスクの様子を FreeBSD で見る2017年03月02日 14時09分18秒

取り敢えず、前回破壊した外付け USB ディスクを FreeBSD に繋げると、こうなる。
da2 at umass-sim2 bus 2 scbus5 target 0 lun 0
da2: <I-O DATA HDPS-U > Fixed Direct Access SCSI-2 device
da2: Serial Number 000902A1541C
da2: 40.000MB/s transfers
da2: 305245MB (625142448 512 byte sectors)
da2: quirks=0x2<NO_6_BYTE>
GEOM_PART: integrity check failed (da2, MBR)
GEOM_PART: integrity check failed (ufsid/4cff0efe10087de1, MBR)
GEOM_PART: integrity check failed (diskid/DISK-000902A1541C, MBR)
ディスクの先頭領域が壊れているようだ。
% ls /dev/da2*
/dev/da2
ls でもパーティションは表示されていない。

FreeBSD には、この整合性の点検を無効にする方法がある。MBR 等を破壊してしまったディスクからの復旧に、役に立つ。root ユーザで。

$ sysctl kern.geom.part.check_integrity=0
% ls /dev/da2*
/dev/da2        /dev/da2s1      /dev/da2s2      /dev/da2s3      /dev/da2s4
これで、mount やら ntfs-3g などで、ディスクの中のファイルを見られる様になる。

なお、このディスクを繋いでも、起動画面が出ることも無い。

Windows が壊れた要因は良く分からない2017年03月01日 15時39分40秒

Windows が起動しなくなったが、実は再現環境が今でも分からない。Windows 7 が入っているのは、この Samsung の機種一機のみ。Windows Vista や Windows XP、それ以前の Windows が入っていた機種なら、HP や Toshiba などが複数台ずつあったが、間違ったボタンを押してもキーキーキーと不快音がなる程度で、起動しなくなった事は無い。

Windows 7 の問題なのか、Windows 7 から変わった LBA 等の起動機構に寄るものなのか、FreeBSD のブートローダが Windows 7 とは相容れないのか、はたまた Samsung 機種だからかなのかは分からない。

取り敢えず、この機械に、外付けのハードディスクを繋いで FreeBSD を起動するときには一段と気を付けなければいけないようだ。特に F5。

この機種に、FreeBSD のブートローダの入った USB ディスクで、F5 を押すと壊れるのは USB ディスクと内蔵ディスクの二台。MBR や LBA の情報が入っている、先頭 512 バイトが破壊される様だ。

BIOS で CD-ROM から起動するようにしたり、他の外付けの USB ディスクを繋ぎ直して、FreeBSD を起動することは出来る。ディスクも起動情報を直せばデータは無くならない。

Reboot and Select proper Boot device or Insert Boot Media in Selected Boot device and press a key2017年02月28日 14時37分12秒

Samsung RV515 に入っていた Windows 7 の機械を壊してしまった。電源を入れると「Reboot and Select proper Boot device or Insert Boot Media in Selected Boot device and press a key」と出てきて何も起動しない。

実は、この機械は一度同じように壊したことがあった。当時は日記に書く余裕が無かったが、確か 2013 年の冬の事。それ以来この機種では気つけていたのだが。

取り敢えず落胆中ではあるが、今回は再発防止を含めてのメモ。

まずは、再現方法。

  1. FreeBSD の boot ローダの入った USB デバイスを繋ぎ、BIOS で USB を優先する
  2. F1 などの起動パーティションを指定するところで、内蔵ディスクを指す F5 を押す
といたって簡単に破壊できる。

復旧にはデータを失わないように時間をかけるのだが、修復方法はいたって簡単。 MBR のあるディスクの先頭 512 バイトをバックアップから書き戻す。この部分のバックアップをしていなければ、各種 Windows でのもっと複雑な復旧作業が必要になるだろう。

ndis でクラッシュする原因は分かった2017年01月30日 18時23分42秒

デバッグを有効にしたカーネルを使ったら比較的簡単に原因が浮かび上がってきた。カーネルスタックは、ロックの型が一致してないとの事。

少しカーネルに変更を加えて、構造体のアドレスを表示してみた。すると、全て同じアドレスでなければいけないのに、異なったアドレスを表示する箇所がある。

ifnet 構造体の ifp のアドレスがおかしい。if_ndisvar.h の ifnet の ifp 型が、ケーブル用と無線用で共に使われていたが、変更後に共有体の一部になった事が原因だ。

ndis のコード内で、ifp 型を受け取らなければいけない場所で、ieee80211com の構造体として、初期化された部分が渡されるので、渡された構造体が全く異なってしまっている。

FreeBSD の各種デバッグオプションを有効にし NDIS を観察2017年01月22日 12時52分06秒

NDIS が 11.0-RELEASE になって動かないが、あまり有効な手段を見付けられないので、取り敢えず FreeBSD の各種デバッグオプションを有効にして、カーネルを作ることにした。何らかのヒントが出てくれれば良いのだが。

カーネルの設定ファイルは他のものを読み込むことが出来る。

% cat /usr/src/sys/i386/conf/DEBUG 
include GENERIC

ident           GENERIC-DEBUG

#options        DEADLKRES               # Enable the deadlock resolver
options         INVARIANTS              # Enable calls of extra sanity checking
options         INVARIANT_SUPPORT       # Extra sanity checks of internal structures, required by INVARIANTS
options         WITNESS                 # Enable checks to detect deadlocks and cycles
options         WITNESS_SKIPSPIN        # Don't run witness on spinlocks for speed

options         DDB
options         KDB
include で GENERIC カーネルの設定を読み込み、DDB/KDB、INVARIANTS と WITNESS を有効にして、buildkernel KERNCONF=DEBUG。

再起動後に、ndis を試すと、ロックのエラーが表示された。

kernel: panic: mtx_lock() of spin mutex network driver @ /usr/src/sys/modules/if_ndis/../../dev/if_ndis/if_ndis.c:1849
kernel: cpuid = 0
kernel: KDB: stack backtrace:
kernel: #0 0xc0c81d3f at kdb_backtrace+0x4f
kernel: #1 0xc0c3f1d5 at vpanic+0x115
kernel: #2 0xc0c3f0b9 at kassert_panic+0xd9
kernel: #3 0xc0c1e3c3 at __mtx_lock_flags+0x183
kernel: #4 0xc73b4d08 at ndis_start+0x38
kernel: #5 0xc73b1021 at ndis_starttask+0x21
kernel: #6 0xc6ceaea1 at _end+0x4f2afd1
kernel: #7 0xc0bffd6e at fork_exit+0x7e
kernel: #8 0xc119af50 at fork_trampoline+0x8

NDIS に変更が行われたのは 2015 年の夏2017年01月05日 12時54分41秒

NDIS が FreeBSD 11.0-RELEASE から使えなくなっている。current メーリングリストで、テスト募集中とあったのを見た覚えがあったので、見返してみた。メールは 2015 年の夏だった。どうやら一人だけ、テストをしてみようとした人はいたみたいだったが、動作するデバイスを持っていないようだった。

当時は当該機 も current を使っていなかったので、目に止めただけだった。これに返信しても、返事が貰えるかは定かではないが、とりあえず駄目元で返信を試みた。

ndis のデバッグを有効にする2016年12月06日 13時24分20秒

NDIS はカーネルモジュールとして読み込まれるので、素のカーネルの sysctl を探しても出て来ない。ndis モジュールを読み込んだ後に debug.ndis が変更できる。
$ sysctl debug.ndis=1
debug.ndis: 0 -> 1

11.0-RELEASE と 11-CURRENT の NDIS の状態2016年12月01日 12時09分13秒

ifconfig wlan0 に ssid を指定すると、問題が起きる事まで突き止めた。これは FreeBSD 11.0-RELEASE でのテスト。

FreeBSD 11.0-RELEASE では既に NDIS の一部が動かない様だが、何度か古いカーネルで試した結果からみても、最新のコードが一番真っ当な様だ。

春先に 11-CURRENT で wlan の作成が出来なくなった変更があった。11.0-RELEASE を下に調査を続ける前に、その変更が原因で壊れたのかを点検したい。SVN の履歴などを調べるとRev 300738が該当の変更だったようだ。そこで、Rev 300737 に戻して、試してみようと思う。尚、変更は ifconfig だったので、buildworld と buildkernel が必要になるので、時間が掛かりそうだ。

11.0-RELEASE で NDIS でパニックの再現2016年11月29日 18時50分38秒

ifconfig wlan0 list scan は動作するのは確認した。しかし、dhclient は動かない。この後、sysctl を使うとカーネルがパニックを起こす場合があるのを確認した。

ndis から wlan デバイスを作成しただけでは大丈夫なようだ。

$ kldload if_ndis
$ kldload /boot/modules/bcmwl5_sys.ko
$ sysctl -a | wc -l
5330
$ ifconfig wlan0 create wlandev ndis0 up
$ ifconfig wlan0 list scan
$ sysctl -a | wc -l
5338
$ dhclient wlan0
wlan0: no link .............. giving up
$ sysctl -a | wc -l
5338

ssid を指定して wlan を作成するとパニックを起こすようだ。

$ kldload if_ndis
$ kldload /boot/modules/bcmwl5_sys.ko
$ wlan create wlandev ndis0 ssid <id> wepmode on wepkey <key> weptxkey 1 up
$ sysctl -a | wc -l
kdb に落ちるので見ると、fill_kinfo_proc 内の strlcpy を指している。
db> where
Tracing pid 993 tid 100145 td 0xc7275000
strlcpy(...)
fill_kinfo_proc()
kern_Proc_out()
fill_kinfo_proc では二箇所で strlcpy が使われていた。