(今はまだ)WSL1にUbuntu 20.04を入れるな

# 2020-09-01 - 直ります

**20H2 Build 19042.487 (KB4571744)** で修正された。version 20H2は例年から考えれば10月とかに出るだろうが、COVID-19で何かしら遅れることがあるかもしれない[^20h1releasedate]。WSL1でUbuntu 20.04を使いたくて夜も `nanosleep` できない人はInsiderのBetaかRelease Previewを入れよう。

[^20h1releasedate]: 6月の[MicrosoftのWindows Experience Blogでは今年後半に出ると言っている](https://blogs.windows.com/windowsexperience/2020/06/16/whats-next-for-windows-10-updates/)

> This issue is fixed for Insiders in the Beta channel and the Release Preview channel with 20H2 Build 19042.487 (KB4571744). I would recommend reversing any custom changes to your WSL once you've updated.
https://github.com/microsoft/WSL/issues/4898#issuecomment-682109141

このコメントを最後にIssueはクローズ、ロックされている。

# TL;DR - 不眠症になったUbuntu

- What: **<font color="red">WSL1とUbuntu 20.04 (Focal Fossa)を併用するな</font>**
- Why: **glibc 2.31で`nanosleep`がWSL1非対応のシステムコールを使うようになったせい**
    - **Ubuntuに限らずglibc 2.31(2020年2月リリース)を利用するディストリビューションは危険**
- How to avoid: **Ubuntuを19.10 (Eoan Ermine)以下で使うかWSLを2に上げろ**
    - 他ディストリビューションでも同様に、glibc 2.31を使わないバージョンを選ぶように
    - (Alpineとか)glibcを使わないディストロはたぶん大丈夫

| バージョン | WSL1 | WSL2 | 実例 |
|:-:|:-:|:-:|:-:|
| **glibc 2.31**  | <font color="red">**死**</font>  |  <font color="blue">**可**</font> | Ubuntu 20.04 (Focal Fossa), Arch Linux(2月以降？)[^arch], [Fedora 32](https://fedoraproject.org/wiki/Changes/GLIBC231), [OpenSUSE Tumbleweed](http://download.opensuse.org/tumbleweed/repo/oss/x86_64/) |
| **&lt;glibc 2.31**  |  <font color="blue">**可**</font> | <font color="blue">**可**</font>  | Ubuntu 19.10(Eoan Ermine), 18.04 LTS (Bionic Beaver), Debian 10 (Buster), Fedora 31, OpenSUSE Leap 15|

[^arch]: Arch Linux詳しくないのでわからないのだが、[リポジトリを見る感じでは](https://git.archlinux.org/svntogit/packages.git/log/trunk?h=packages/glibc)2月にglibcが2.31に上がっているっぽい感じはする

# 具体的にこんな事が起きるぞ

### **Ubuntu 18.04からアップグレードできない**

そもそも`do-release-upgrade -d`が途中でコケるなどしてアップグレードできない。筆者環境のUbuntu 18.04 LTSは`sudo apt upgrade`すると`E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).`などと言われた[^a]。

[^a]: 筆者は英語環境のままにしている。理由は不明

それで `sudo apt --fix-broken install` すると…

```
sleep: cannot read realtime clock: Invalid argument
dpkg: error processing package libc6:amd64 (--configure):
 installed libc6:amd64 package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
 libc6:amd64
E: Sub-process /usr/bin/dpkg returned an error code (1)
```

エラーが出る。この `sleep: cannot read realtime clock: Invalid argument` が例の問題が発生したことを示している。ちなみに日本語では`実時間の時計を読み取ることができません: 無効な引数です` と出るようだ。

### `rustup` がツールチェインをインストールできない


(UNIX-likeでの)Rustの環境構築は`curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`をシェルに貼り付けるだけなのだが、

```
info: profile set to 'default'
info: default host triple is x86_64-unknown-linux-gnu
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: latest update on 2020-04-23, rust version 1.43.0 (4fb7144ed 2020-04-20)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `22`,
 right: `4`', src/libstd/sys/unix/thread.rs:166:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `22`,
 right: `4`', src/libstd/sys/unix/thread.rs:166:21
stack backtrace:
```

なんということでしょう。

rust-lang側でもすでにissueが立っている([rust-lang/rustup#2245: rustup panic with WSLv1 + glibc 2.31](https://github.com/rust-lang/rustup/issues/2245), [#2293](https://github.com/rust-lang/rustup/issues/2293))。

---

以上は確認した限り。

# 対処

[Ubuntu 20.04 and WSL 1 - Ubuntu Community Hub](https://discourse.ubuntu.com/t/ubuntu-20-04-and-wsl-1/15291)

> For WSL 1 users, I recommend you sit tight on Ubuntu 18.04 for now. The patch for issue 4989 will take some time to be backported. Ubuntu 18.04 is an LTS release, short for long-term servicing, and is supported through 2023 so you will continue to get security patches and backports from Canonical in the meantime.


> WSL1 のユーザーには、Ubuntu 18.04に留まることを勧める。Issue 4989 (*訳注: この問題のこと。たぶん[microsoft/WSL#4898](https://github.com/microsoft/WSL/issues/4898)のTypo。*) へのパッチがバックポートされるまでしばらくかかるだろう。Ubuntu 18.04 はLTS、つまり長期サポート(Long-Term Servicing)で、2023年まではセキュリティパッチやバックポートをCanonical社から受け取ることができる。

要約すると、**問題を修正するパッチが来るまではUbuntu18.04で待ってろ**ということ。

### Ubuntu 20.04を避ける

#### 今からUbuntuを導入する時は…

今からWSL1を導入し、Ubuntuをインストールしようという人は「[Ubuntu 18.04 LTS](https://www.microsoft.com/en-us/p/ubuntu-2004-lts/9n6svws3rx71)」というアプリをインストールすればよい。逆に「Ubuntu 20.04 LTS」という見えてる地雷や、分かりづらいが単に「[Ubuntu](https://www.microsoft.com/store/productId/9NBLGGH4MSV6)」と書いてあるアプリも20.04をインストールしてしまう。16.04があった気がするんだがいつの間にか消えていた。

#### 今Ubuntuを使ってる時は…

すでにUbuntu 19.10以下が導入されている人は、そのまま待機すればよい。「Ubuntu」「Ubuntu 18.04」アプリに時々アップデートが届くが、これはUbuntu本体のアップグレードとは無関係なので安心してOK。逆にUbuntuのシェルで`do-release-upgrade`を実行するとアップグレードが始まってしまうので注意。

### WSL1 へのパッチを待つ

「パッチがバックポートされるまでは」という言葉でおや？と思ったかもしれないが、[Microsoftのこちらの方のコメント](https://github.com/microsoft/WSL/issues/4898#issuecomment-603384784)によれば修正が来ており、バックポートを検討中であるらしい。

[Windows Insider Fastリングの19608.1006では解決されてるとのコメント](https://github.com/microsoft/WSL/issues/4898#issuecomment-619327787)もあるが、[Windows Insider Previewのアナウンス](https://blogs.windows.com/windowsexperience/2020/04/15/announcing-windows-10-insider-preview-build-19608/)では特に言及されていないし、2月ぐらいのビルドまでさかのぼってもこの問題が解決されたという話はなかった。サイレント修正とみるべきか。

追記(2020-09-01): 19042.487で解消したらしいんだが、ビルド番号はいったいどういう付番規則になっているんだ…

### WSL2 を導入する

追記(2020-05-28): **WSL 2** を搭載した Windows 10の次期バージョン **May 2020 Update**[^win] がリリースされた。WSL2はマジのLinuxカーネルを使うためこの問題は起きない。詳しいことはググってほしい。

WSL1にも1なりの長所があるので廃止の予定はなく、現にこうやってWSL1のためにパッチが出されている。1, 2という序列のある名前よりも、もっと対等な感じの名前を捻出できなかったものだろうかとは思う。

[^win]: バージョン番号では2004、開発中のバージョン番号は20H1、ビルド番号では19041.207。as known asが多すぎる

### その他の方法

- [ppa:rafaeldtinoco/lp1871129](https://launchpad.net/~rafaeldtinoco/+archive/ubuntu/lp1871129)で公開されているglibc 2.31の改造版(2.31-0ubuntu8+lp1871129~1)を入れる([米番612622828](https://github.com/microsoft/WSL/issues/4898#issuecomment-612622828))
- [Busyboxのsleepにシンボリックリンクを貼る](https://github.com/microsoft/WSL/issues/4898#issuecomment-610310116)
- `sudo apt-mark hold` [を使ってバージョンを固定する](https://github.com/microsoft/WSL/issues/4898#issuecomment-599288066)

といったのも提案されている。

Arch Linuxでは`downgrade`[コマンドを使ってバージョンを下げられる](https://github.com/yuk7/ArchWSL/issues/108#issuecomment-585254666)ようだ。

## Ubuntu 20.04なら俺の横で寝てるよ

アップグレードを実行してしまった手遅れな人[^teokure]たちへ。

とりあえず、変なことをしていなければ`mv`や`cp`は使えるはずなので、**必要なデータはWindows側(`/mnt/c`)に退避させる**のがいいと思う。筆者は必要なデータがそもそもWindows側に置いてあったのでかまわず実験台に載せていろいろしてしまったが。

[^teokure]: 筆者のこと

[#4898のコメント番号611583534](https://github.com/microsoft/WSL/issues/4898#issuecomment-611583534)に対処が書いてある。…のだが、筆者が試したらUbuntuが完全に死んだ[^rip]のであまり信頼できない。コメント自体も :thumbsup: が3で :thumbsdown: が7で、しかもこの後に“as soon as I did that, my WSL broke completely”というコメントまで届いているのでうーんという感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411269/d07ac401-36f1-3784-4fde-b17ac98bb170.png)
度重なる実験の結果、起動しようとするとこうなるようになってしまったUbuntu。適当にググった結果SIGSEGV(セグメンテーション違反)らしい。たいへんだ。

[^rip]: 筆者はアホなので、その後のコメントの方法を試したせいなのかこいつのせいなのかが全くわからない


# どうしてこうなった

**glibc 2.31が`sleep`でWSL1非対応のシステムコールを使うようになったから**。

そもそもWSL1は、Linux上で動くソフトウェアが「Linuxカーネルのこの機能を使わせろ」と要求してくるのをWindows NTカーネルのために翻訳して仲介する役割を果たすものだった。
それに対してWSL2はLinuxカーネルをまるまる載せている。Linuxカーネルそのものなので、WSL1に実装されていないシステムコールでも理解できる。

この問題が広まっているのは Ubuntu 20.04でglibcが2.31に上がってからだろうが、Arch Linuxでは2月にアップグレードされているためすでに問題が発生していたようだ(参考: [yuk7/ArchWSL#108](https://github.com/yuk7/ArchWSL/issues/108), 02/12、[VSCode(WSL1)でCPU使用率が下がらない場合の原因と対処法 - Qiita](https://qiita.com/RShirohara/items/727feb89c63cdd0d1f62), 03/03)[^archwsl]。

[^archwsl]: ArchWSLはMicrosoft Storeにないのでそもそも存在を初めて知ったが、作者が19歳で親近感が湧いた。

では、もう少しだけ原因を知りたいので[さっきの投稿](https://discourse.ubuntu.com/t/ubuntu-20-04-and-wsl-1/15291)をもう一回持ってくる。

> **Issue 4989**

> An example of the WSL team continuing to service WSL 1 for now is a patch for issue 4989. Issue 4989 arises from a patch in glibc 2.31 that implements a nanosleep() library call in a more UNIX-like manner based on CLOCK_REALTIME. Emulating UNIX system clocks on an NT kernel is tricky. WSL 1 implemented the most popular clock-based system calls, but not all of them, and did not build CLOCK_REALTIME support into nanosleep. But because this is such a fundamental change in glibc the WSL team is very graciously implementing support for CLOCK_REALTIME in nanosleep in WSL 1 and will be backporting it in updates to existing builds. This is a challenging task that will take some time. In contrast, other more obscure system clock calls, like the one raised in issue 4973, will likely not see implementation in WSL 1.


訳すと、

> この問題はglibc 2.31が `nanosleep()` ライブラリ をCLOCK_REALTIMEを使った、よりUNIX-likeな方法で呼び出すようになったことに起因する。Windows NTカーネル上でUNIXシステムクロックをエミュレートするのは大変だ。WSLは最も一般的なクロックベースのシステムコールを実装しているが、全部実装されてるわけではなく、nanosleepにはCLOCK_REALTIMEのサポートが入っていない。しかしこれはglibcの根本的な変更であるため、ありがたいことにWSLチームはnanosleepにCLOCK_REALTIMEのサポートを実装してくれ、それは既存のビルドにもアップデートで提供されるだろう。これは挑戦的で時間のかかることだ。一方、その他のあまりポピュラーでないシステムクロックコール、たとえば#4973で話題になってるようなものは、たぶんWSL1には実装されないだろう。

Linuxに詳しくないので全然わからないのだが、CLOCK_REALTIMEというのは時刻を取得するときのフラグのひとつらしい。(？)
[この記事](https://qiita.com/ozaki-r/items/fb4a48c2833e4b479ae1)によればフラグは複数種あって、どうやらWSL1はそもそもCLOCK_REALTIMEに非対応であるらしい。[microsoft/WSL#2503](https://github.com/microsoft/WSL/issues/2503)は2017年9月に立てられた、CLOCK_REALTIMEがWSLで`EINVAL`とともに失敗することのissueだ。「時計システムなんてエミュレート実装すんのめんどくさいし後回しでよくね？」的に当時は実装しないまま放置されていたのがglibc側のアップデートでこっちが呼ばれるようになって…という感じだろうか。


## glibc側を掘る

[microsoft/WSL#4898へのコメント](https://github.com/microsoft/WSL/issues/4898#issuecomment-586547232)によれば、glibcの/posix/nanosleep.cにコードが追加されたのが原因なようだ。そのコミットが[こちら](https://github.com/bminor/glibc/commit/3537ecb49cf7177274607004c562d6f9ecc99474)。2019年11月06日のコミットなので、8月に出た2.30と2020年2月に出た2.31のちょうど中間に存在している。descriptionの文章を見る感じではGNU HurdのためにつねにCLOCK_REALTIMEで呼び出すようにしたっぽい。

# まとめ

- WSL2はいいぞ。たぶん
- Linuxなんもわからん、というか/bin/sleepはGNUがやってるなんて初めて知ったよ
    - Linuxカーネル単独ではPOSIX完全準拠に至っていないというブコメ[^hatebu]を見た、かなり驚き
- ArchWSL使ってみたいな
- Hurdの名前をこんなところで見るとは思わなかった
- みんながいろいろと解決策を模索している感じが見てて面白いし勉強になる

[^hatebu]: 筆者はアホなので、Qiitaユーザー名をmominisからAumyFに変更したのでURLが変わっておりブコメが分離してしまい悲しい気持ちになっている。ユーザー名が変わっても記事の `eaf42dd3345a2285ff9e` という何らかの16進数は変わらずリンクは切れないのでまあそこまで深刻ではないけども。