なんだか今週は重めの計算機トラブルが二つ発生して直すのに手間取ったので、対処方法を記録しておきます。 一つ目は、カーネルパニックが出てしまうという問題で、二つ目はWSLからインターネットにつなげないというものです。
カーネルパニック
症状
Ubuntuを起動しようとすると、Tux(Linuxのペンギン)のAAと感嘆符とともに、カーネルパニックを起こしたとメッセージが表示されます(写真からの書き起こしなのでスペースの数とかが違うかもしれません。以下同様です)。
.--. _ |o_o | | | |:_/ | | | // \ \ |_| (| | ) _ /'\_ _/`\ (_) \___)=(___/
KERNEL PANIC!
Please reboot your computer.
VFS: Unable to mount root fs on unknown-block(0,0)
SSDが壊れてしまったとかだとすると面倒なことになったようです。
解決手順
Ubuntu再起動時にKernel Panicを起こした #OS - Qiitaを参考にしました。 最初はGRUBのシェル風コマンドラインから頑張ろうとしたのですが、USB接続キーボードの反応が悪すぎて、1文字打ったつもりが2文字になるわバックスペースキーを押すと2文字分消えるわで、思ったようにコマンドが打てません。 画面はちゃんと出ている感じがするので、グラフィックドライバの問題ではなさそうです。 そこで、この手順(上記Qiita記事の1の手順)はスキップして、このUbuntuをインストールするときに使ったLive USBをつないで、何が起こっているかを確認しました。 ライブセッションでは、USB接続キーボードの反応はまともでした。 画面は黄色と白になっていて非常に見づらいですが、これは前にインストールした時もそうだったので今回の症状とは無関係と判断しました*1。
まず、lsblk -fをすると、以下のように出てきました。
nvme0n1
├─nvme0n1p1
│ vfat FAT32
└─nvme0n1p2
ext4 1.0
ext4になっているのがUbuntuのルートパーティションらしいので、nvme0n1p2をマウントします。
sudo mount /dev/nvme0n1p2 /mnt
その後、システムディレクトリをマウントし、sudo chroot /mntでルート環境に入り、update-initramfs -u -k allをやっても直りませんでした(上記Qiita記事の2の手順が失敗)。
その次に、上記Qiita記事で成功したと書かれていた4の手順の最初のコマンド(ls /mnt/boot/)を実験してみました。
System.map-6.11.0-24-generic memtest86+ia32.bin
System.map-6.14.0-28-generic memtest86+ia32.efi
config-6.11.0-24-generic memtest86+x64.bin
config-6.14.0-28-generic memtest86+x64.efi
efi vmlinuz
grub vmlinuz-6.11.0.24-generic
vmlinuz-6.14.0-28-generic
initrd.img-6.11.0-24-generic vmlinuz.old
initrd.img.old
※grubの下に謎のスペースがありますが、ここには何らかの文字が出力されている可能性があります。おそらく、画面が黄背景白文字になっていることが原因で読めない配色で出力されているのでしょう。位置的には、grub2でしょうか。
これを見ると、上記Qiita記事と同様、initrdのバージョンが古い物しかない(他のは6.14.0-28-genericがあるのに、initrdだけそれがない)ことがわかります。
アップデートが途中で終わっちゃったとかでしょうか。
いずれにせよ、上記Qiita記事と類似の症状ということで、同じ手順で直せる可能性が高そうです。
そこで、以下の手順でinitrd.img-6.14.0-28-genericを作成しました。
sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys sudo mount --bind /run /mnt/run update-initramfs -c -k 6.14.0-28-generic update-grub
この後、このライブセッションを終了し、USBメモリを外してから電源を入れれば、無事に起動することができました。
WSLからインターネットにつながらない
症状
Windowsからは普通にインターネットにつながるのに、WSLからはインターネットにつながらなくなりました。
$ ping 8.8.8.8 ping: connect: Network is unreachable
解決までに試した手順(失敗したもの)
WSL側のDNS自動生成を有効化
まず、/etc/resolv.confがどうなっているかを調べました。
ChatGPTに聞いたところ、以下のどちらかを切り分けましょうと言われました。
/run/systemd/resolve/stub-resolv.confへのシンボリックリンクか、/run/systemd/resolve/resolv.confへのシンボリックリンク(systemd-resolved方式)- リンクではないファイルであるか、または、そもそも存在しない(WSL方式)
しかし、/etc/resolv.confは/mnt/wsl/resolv.confへのシンボリックリンクになっています。これは新しめの方式だそうです。
まず、wsl --updateを行って、最新のバージョンにしました(2.3.26.0→2.5.10.0)。
これにより、dnsProxyやdnsTunnelingが規定で有効になるので、うまくいくはずとのことで次の手順を試しましたが、うまくいきませんでした。
$ sudo chattr -i /etc/resolv.conf 2>/dev/null || true $ sudo rm -f /etc/resolv.conf
PS> wsl --shutdown
systemd-resolvedに任せる
WSLの自動生成を使わないで、Ubuntuのsystemd-resolvedに作らせる方式を試しました。
まず、/etc/wsl.confに以下を書き加えました。
[network] generateResolvConf = false
つづいて、以下のコマンドを実行しましたが、まだ駄目です。
$ sudo rm -f /etc/resolv.conf $ sudo ln -s /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf $ sudo systemctl enable --now systemd-resolved
PS> wsl --shutdown
resolvedが上流DNSを把握できるようにする
以下を実行するように促されましたが、そもそもip route show defaultが何も返さないようです。
# 1) 既定経路のゲートウェイIPを取得(だいたい 172.29.x.1)
GW=$(ip route show default | awk '{print $3}')
IF=$(ip route show default | awk '{print $5}') # だいたい eth0
# 2) そのゲートウェイを上流DNSとして設定し、既定の検索ルートにする
sudo resolvectl dns "$IF" "$GW"
sudo resolvectl domain "$IF" "~."
sudo resolvectl flush-caches
# 3) 動作確認
getent hosts example.com
デフォルト経路を復旧
以下を実行するように促されましたが、vEthernet (WSL)はないようです。
また、Restart-Service : サービス名 'LxssManager' のサービスが見つかりません。というエラーも出ます。
wsl --shutdown # vEthernet (WSL) を再起動 Get-NetAdapter -Name "vEthernet (WSL)" | Restart-NetAdapter -Confirm:$false # WSL のサービスも再起動(念のため) Restart-Service LxssManager
ネットワークアダプターをすべて表示
PowerShellで以下のようにやると、ネットワークアダプターを全て表示することができるそうです。
# vEthernet 系や Hyper-V 仮想NICを一覧(非表示も含む)
Get-NetAdapter -IncludeHidden |
Where-Object { $_.Name -match '^vEthernet' -or $_.InterfaceDescription -like '*Hyper-V Virtual Ethernet Adapter*' } |
Sort-Object Name |
Format-Table -Auto Name, Status, InterfaceDescription
すると以下のようになりました。やはりWSL用のネットワークアダプターがないのがおかしそうです。
vEthernet (Default Switch) Up Hyper-V Virtual Ethernet Adapter vEthernet (内部仮想スイッチ) Up Hyper-V Virtual Ethernet Adapter #3
WSLの中から見てみると、以下のようになっていて、eth0がないのがおかしそうです。
$ ip -br a lo UNKNOWN 127.0.0.1/8 10.255.255.254/32 ::1/128 enPXXXXp0s0 DOWN XXX.XXX.XXX.XXX/32 docker0 DOWN 172.17.0.1/16 $ ip r 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
※XXXXは数値、XXX.XXX.XXX.XXXは特定のグローバルIPアドレス
mirroredの影響を排除
次を促されましたが、これはうまくいきませんでした。
notepad $env:USERPROFILE\.wslconfig
を管理者PowerShellから実行して以下を書き込む
[wsl2] networkingMode=NAT dnsProxy=true
管理者PowerShellから以下をやる
# 1) いったん WSL を止める
wsl --shutdown
# 2) HNS と vmcompute を再起動(LxssManager は最新版WSLでは無いことがあるのでスキップでOK)
Stop-Service hns -Force
Start-Service hns
Restart-Service vmcompute
# 3) 壊れた WSL NAT があれば削除(無ければスキップされます)
Get-NetNAT | Where-Object Name -eq 'WSL' | Remove-NetNAT -Confirm:$false
# 4) 既存の HNS ネットワークに 'WSL' があれば削除(Default Switch は触らない)
$wslNet = Get-HnsNetwork | Where-Object Name -eq 'WSL'
if ($wslNet) { Remove-HnsNetwork -Id $wslNet.Id }
# 5) WSL を一度だけ起動してネットワークを再生成させる
wsl -e /bin/true
直った手順
Windows側を修正
以下を実行した後、Windowsマシンを再起動したところ、WSLからインターネットにつながりました。 単にWindowsマシンを再起動するだけでも直ったのかもしれず、これを実行したことが決め手となったかはわかりません。
wsl --shutdown DISM /Online /Enable-Feature /FeatureName:VirtualMachinePlatform /All /NoRestart DISM /Online /Enable-Feature /FeatureName:Microsoft-Windows-Subsystem-Linux /All /NoRestart netsh winsock reset netsh int ip reset
WSLの自動生成に戻す
試行錯誤の途中で追加された次の記述を/etc/wsl.confから取り除きました。
[network] generateResolvConf = false
その結果、自動生成されるresolv.confは以下のようになり、正しくなりました。
$ cat /etc/resolv.conf # This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf: # [network] # generateResolvConf = false nameserver 10.255.255.254 search XX.ad.jp
※XX.ad.jpは契約しているプロバイダのドメイン名
WSLの中からは次のように見えていて、ちゃんとeth0が出現しています。
$ ip -br a lo UNKNOWN 127.0.0.1/8 10.255.255.254/32 ::1/128 eth0 UP 172.22.XXX.XXX/20 fe80::215:5dff:feXX:XXXX/64 docker0 DOWN 172.17.0.1/16 $ ip r default via 172.22.32.1 dev eth0 proto kernel 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 172.22.32.0/20 dev eth0 proto kernel scope link src 172.22.XXX.XXX
XX:XXXXはWSLを起動するたびに変わります(fe80::はリンクローカルアドレスを意味していて、その後の215:5dff:feは製造元がマイクロソフトであることを意味しているので、WSLであればここは変わらないはずです)。 XXX.XXXも変わりうるようです(172.22.32.0/20を検索するとWSL関連しか出てこないので、この範囲で変わるのでしょうか)。
PowerShellから確認しても、ちゃんとWSLの仮想スイッチが出現していました。
PS C:\WINDOWS\system32> # vEthernet 系や Hyper-V 仮想NICを一覧(非表示も含む)
PS C:\WINDOWS\system32> Get-NetAdapter -IncludeHidden |
>> Where-Object { $_.Name -match '^vEthernet' -or $_.InterfaceDescription -like '*Hyper-V Virtual Ethernet Adapter*' } |
>> Sort-Object Name |
>> Format-Table -Auto Name, Status, InterfaceDescription
Name Status InterfaceDescription
---- ------ --------------------
vEthernet (Default Switch) Up Hyper-V Virtual Ethernet Adapter
vEthernet (WSL (Hyper-V firewall)) Up Hyper-V Virtual Ethernet Adapter #2
vEthernet (内部仮想スイッチ) Up Hyper-V Virtual Ethernet Adapter #3
まとめ
計算機トラブルを二つ片付けました。 生成AIを使うと対話的に問題を解決できるので、なかなか便利になりました。
一つ目の問題は結果的にはQiita記事に助けられたわけですが、完全に同じ症例だったわけではないので、その手順が応用可能な範囲に関する情報も有用かなと思って書きました。 二つ目の問題は生成AIの言うがままにコマンドを実行していったら直ったわけで、その情報はきっとインターネットのどこかにあるのでしょう。 生成AIの出力を理解しないままに貼り付けて記事にするのはどうなのかなとも思いましたが、実際に試してうまくいったとかうまくいかなかったとか、どういう出力が得られるのが普通なのかとか、そういった情報はあれば役に立つこともあるかなと思って書きました。
*1:今ウェブ検索してみると直し方がたくさん出てきました。