WSL2標準kernelでZFS


# ZFSモジュール
WSL2標準kernelに組み込めるZFSモジュールの作り方。
ZFS有効なカスタムカーネルを作る方法は[ここ](https://wsl.dev/wsl2-kernel-zfs)を、WSL2標準kernelのソースコードでビルドする方法は[ここ](https://qiita.com/matarillo/items/bcae7e61ada3d1a7f9a4)、dxgkrnl有効カーネルを作る方法は[ここ](https://qiita.com/qawsed477/items/06102341e30215c0e4d0)を参照。

zfsモジュールの[ビルドスクリプト](https://github.com/qawsed90/mod_zfs_on_wsl)。
~~スクリプトの93行目をコメントアウトすると、5.15.79.1以降で "BPF:[134983] FWD" エラーによるモジュールロードに失敗しなくなる(正しい方法かどうかは不明)。~~ [カーネルとモジュールを同じツールチェインでビルド](https://qiita.com/qawsed477/items/11e4248861fdf8c6a585#zfs-%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)すれば BPF のエラーは出なくなる。
<details><summary>build_wsl_module.sh</summary><div>

```shell
#!/bin/sh
set -xe

#ZFS_VERSION="2.1.2"
#ZFS_VERSION="2.1.3"
#ZFS_VERSION="2.1.4"
#ZFS_VERSION="2.1.5"
ZFS_VERSION="2.1.6"
ZFS_RELEASE="1"

KERNELVER=$(uname -r)
#KERNELVER="5.10.43.3-microsoft-standard-WSL2"
#KERNELVER="5.10.60.1-microsoft-standard-WSL2"
#KERNELVER="5.10.93.2-microsoft-standard-WSL2"
#KERNELVER="5.10.102.1-microsoft-standard-WSL2"
#KERNELVER="5.15.57.1-microsoft-standard-WSL2"
#KERNELVER="5.15.68.1-microsoft-standard-WSL2"
#KERNELVER="5.15.74.2-microsoft-standard-WSL2"
LINUX_VERSION=$(echo ${KERNELVER}|awk -F'[-]' '{print $1}')
LINUX_RELEASE="1"

SCRIPTDIR=$(pwd)
KERNELSRCDIR=${SCRIPTDIR}/WSL2-Linux-Kernel
ZFSSRCDIR=${SCRIPTDIR}/zfs

#
# Install pre-requisites
#
sudo apt update && \
sudo apt upgrade -y && \
sudo apt install tzdata
sudo apt install \
  autoconf \
  automake \
  bc \
  binutils \
  bison \
  build-essential \
  curl \
  dwarves \
  fakeroot \
  flex \
  gawk \
  gcc-9 \
  libblkid-dev \
  libelf-dev \
  libffi-dev \
  libssl-dev \
  libtool \
  python3 \
  python3-setuptools \
  uuid-dev \
  wget \
  zlib1g-dev

#
# Download source code
#
if [ ! -d ${KERNELSRCDIR} ];then
  git clone https://github.com/microsoft/WSL2-Linux-Kernel.git
fi
if [ ! -d ${ZFSSRCDIR} ];then
  git clone https://github.com/openzfs/zfs.git 
fi

#
# kernel build prepare
#
cd ${KERNELSRCDIR}
git fetch --tags origin
KERNELTAG=$(git tag | grep wsl | grep ${LINUX_VERSION})
git checkout ${KERNELTAG}
make mrproper
cp Microsoft/config-wsl .config
if [ -f ${SCRIPTDIR}/add_module_config ];then
  cat ${SCRIPTDIR}/add_module_config >> .config
fi
make CC=gcc-9 olddefconfig
make CC=gcc-9 LOCALVERSION= modules -j$(nproc)

#
# original kernel (5.15.74.2-microsoft-standard-WSL2) can't load module.
# dmesg say below:
#[    4.655440] BPF:[134983] FWD
#[    4.655837] BPF:struct
#[    4.656047] BPF:
#[    4.656277] BPF:Invalid name
#[    4.656610] BPF:
#
#[    4.790484] modprobe: ERROR: could not insert 'zfs': Invalid argument
# to fix this error, comment out
#
#cp /sys/kernel/btf/vmlinux ${KERNELSRCDIR}

#
# build zfs
#
cd ${ZFSSRCDIR}
git fetch --tags origin
git checkout zfs-${ZFS_VERSION}
sh autogen.sh
CC=gcc-9 ./configure \
	--prefix=/usr \
	--sysconfdir=/etc \
	--libdir=/lib \
	--includedir=/usr/include \
	--datarootdir=/usr/share \
	--enable-linux-builtin=no \
	--with-linux=${KERNELSRCDIR} \
	--with-linux-obj=${KERNELSRCDIR}

rm -rf ${ZFSSRCDIR}/debwork
make CC=gcc-9 -j$(nproc) DESTDIR=${ZFSSRCDIR}/debwork 
make CC=gcc-9 -j$(nproc) DESTDIR=${ZFSSRCDIR}/debwork install
rm -rf ${ZFSSRCDIR}/debwork/lib/modules/

INSTALLED_SIZE=$(du -ks debwork|awk '{print $1}')

mkdir -p ${ZFSSRCDIR}/debwork/DEBIAN
cat > ${ZFSSRCDIR}/debwork/DEBIAN/control << EOF
Package: zfs
Priority: extra
Section: kernel
Installed-Size: ${INSTALLED_SIZE}
Maintainer: $(whoami)@$(hostname)
Architecture: amd64
Version: ${ZFS_VERSION}-${ZFS_RELEASE}
Provides: zfs
Description: zfs for WSL linux
EOF

fakeroot dpkg-deb --build debwork ${SCRIPTDIR}

#
# build kernel module
#
rm -rf ${KERNELSRCDIR}/debwork
cd ${ZFSSRCDIR}/module
make CC=gcc-9 -j$(nproc) DESTDIR=${KERNELSRCDIR}/debwork
make CC=gcc-9 -j$(nproc) DESTDIR=${KERNELSRCDIR}/debwork install
cd ${KERNELSRCDIR}
make CC=gcc-9 -j$(nproc) INSTALL_MOD_PATH=${KERNELSRCDIR}/debwork LOCALVERSION= modules
make CC=gcc-9 -j$(nproc) INSTALL_MOD_PATH=${KERNELSRCDIR}/debwork LOCALVERSION= modules_install

INSTALLED_SIZE=$(du -ks debwork|awk '{print $1}')

mkdir -p ${KERNELSRCDIR}/debwork/DEBIAN
cat > ${KERNELSRCDIR}/debwork/DEBIAN/control << EOF
Package: linux-module-${KERNELVER}
Priority: extra
Section: kernel
Installed-Size: ${INSTALLED_SIZE}
Maintainer: $(whoami)@$(hostname)
Architecture: amd64
Version: ${LINUX_VERSION}-${LINUX_RELEASE}
Provides: linux-module
Description: module files (zfs-${ZFS_VERSION}) for WSL linux kernel
 Enable modules:
 CONFIG_ZFS=m$(test -f ${SCRIPTDIR}/add_module_config && echo &&
sed 's/^/ /' ${SCRIPTDIR}/add_module_config)
EOF

cat > ${KERNELSRCDIR}/debwork/DEBIAN/postinst << EOF
#!/bin/sh
depmod ${KERNELVER}
EOF
chmod 755 ${KERNELSRCDIR}/debwork/DEBIAN/postinst

fakeroot dpkg-deb --build debwork ${SCRIPTDIR}

set +x
echo '================================================================================================='
echo '# edit /etc/wsl.conf'
echo '$ cat /etc/wsl.conf
[boot]
command=modprobe zfs
'
echo '# install deb packages for zfs'
echo '$ sudo dpkg -i' linux-module-$(echo ${KERNELVER}|tr A-Z a-z)_${LINUX_VERSION}-${LINUX_RELEASE}_amd64.deb
echo '$ sudo dpkg -i' zfs_${ZFS_VERSION}-${ZFS_RELEASE}_amd64.deb
echo ''
echo '# check zfs'
echo '$ sudo zfs version'
echo '================================================================================================='
```
</div></details>

ここ先は古い情報なので[build_wsl_module.sh](https://raw.githubusercontent.com/qawsed90/mod_zfs_on_wsl/main/build_wsl_module.sh)を使ってください (5.15.79.1-microsoft-standard-WSL2で確認済み)。

## WSL2 バージョンの確認
Windowsのバージョン:

```shell-session
Microsoft Windows [Version 10.0.22621.1105]
```
WSL2のカーネルバージョン(Windows Subsystem for Linux Preview):

```shell-session
$ uname -r
5.15.79.1-microsoft-standard-WSL2
```

## 作業ディレクトリを作成
```shell-session
$ mkdir ${HOME}/wsl2kernel
```

## kernelのソースコードを取得
WSL2のカーネルバージョンと一致するソースコードを取得する。

```shell-session
$ cd ${HOME}/wsl2kernel
$ git clone https://github.com/microsoft/WSL2-Linux-Kernel.git
$ cd WSL2-Linux-Kernel
$ git tag | grep 5.15.79.1
linux-msft-wsl-5.15.79.1
$ git checkout linux-msft-wsl-5.15.79.1
```

## kernelの準備
 * LOCALVERSION= の理由は[ここ](https://stackoverflow.com/questions/19333918/dont-add-to-linux-kernel-version)を参照
 * コンパイルに時間がかかるので注意

```shell-session
$ make mrproper
$ cp Microsoft/config-wsl .config
$ make oldconfig
$ make LOCALVERSION= modules -j12
```

## ZFSのソースコードを取得
```shell-session
$ cd ${HOME}/wsl2kernel
$ git clone https://github.com/openzfs/zfs.git
$ cd zfs
$ git checkout zfs-2.1.6
```

## ZFSのビルド及びインストール
スクリプト([debwork_module.sh](https://raw.githubusercontent.com/qawsed90/QiitaAttachments/main/202102/debwork_module.sh),[debwork_zfs.sh](https://raw.githubusercontent.com/qawsed90/QiitaAttachments/main/202102/debwork_zfs.sh))でdebパッケージを作る

```shell-session
$ sh autogen.sh
$ mkdir ../zfs-2.1.1_build
$ cd ../zfs-2.1.1_build
$ ../zfs-2.1.1/configure --prefix=/usr --sysconfdir=/etc --libdir=/lib --includedir=/usr/include --datarootdir=/usr/share --enable-linux-builtin=no --with-linux=${HOME}/wsl2kernel/WSL2-Linux-Kernel --with-linux-obj=${HOME}/wsl2kernel/WSL2-Linux-Kernel
$ make -j12
$ sh debwork_zfs.sh #version, release番号等 スクリプトを編集する
$ cd ../WSL2-Linux-Kernel
$ sh debwork_module.sh #version, release番号等 スクリプトを編集する
$ cd ../zfs-2.1.1_build
$ sudo dpkg -i zfs_2.1.1-2_amd64.deb
$ sudo dpkg -i ../WSL2-Linux-Kernel/linux-module-5.10.60.1-microsoft-standard-wsl2_5.10.60.1-2_amd64.deb
```

## ZFSの動作確認
```shell-session
$ sudo modprobe zfs
$ sudo zfs version
zfs-2.1.1-1
zfs-kmod-2.1.1-1
```

## wsl.confの編集
wsl 起動時にmodprobeを実行するようにする。

```shell-session
$ sudo vi /etc/wsl.conf
$ cat /etc/wsl.conf
[boot]
command=/sbin/modprobe zfs
```

# おまけ
ZFSなHDDにインストール済みのUbuntuをwslから使う。

## DriveNameの確認
PowerShellコマンドでHDDのドライブ名を調べる。\\\\.\\PHYSICALDRIVE1 と \\\\.\\PHYSICALDRIVE2 がHDDのドライブ名。

```shell-session
$ /mnt/c/Windows/system32/WindowsPowerShell/v1.0/powershell.exe \
        -NoProfile -ExecutionPolicy unrestricted \
        -Command Get-CimInstance Win32_DiskDrive
--------           -------                ---------- ----          -----
\\.\PHYSICALDRIVE2 WDC WD40EZRZ-00GXCB0   5          4000784417280 WDC WD40EZRZ-00GXCB0
\\.\PHYSICALDRIVE1 WDC WD40EZRZ-00GXCB0   5          4000784417280 WDC WD40EZRZ-00GXCB0
\\.\PHYSICALDRIVE0 WDC WDS500G1B0A-00H9H0 4          500105249280  WDC WDS500G1B0A-00H9H0
```

## HDDのマウント
管理者権限でwsl.exeを実行, \\\\.\\PHYSICALDRIVE1 と \\\\.\\PHYSICALDRIVE2をマウントする。

```shell-session
$ /mnt/c/Windows/system32/WindowsPowerShell/v1.0/powershell.exe \
        -NoProfile -ExecutionPolicy unrestricted \
        -Command Start-Process powerShell.exe -Wait \
        -ArgumentList \"-Command wsl --mount \\\\.\\PHYSICALDRIVE1 --bare\; wsl --mount \\\\.\\PHYSICALDRIVE2 --bare\" -Verb runas
```

## zpool import
注意: cacheなしのため、importに時間がかかる。

```shell-session
$ sudo mkdir /mnt/rpool
$ sudo zpool import -R /mnt/rpool rpool
$ sudo zpool import -R /mnt/rpool bpool
```

cacheがある場合:

```shell-session
$ sudo zpool import -R /mnt/rpool -c /root/zpool.cache rpool
$ sudo zpool import -R /mnt/rpool -c /root/zpool.cache bpool
```

import時、"cannot import 'rpool': one or more devices is currently unavailable"のエラーでimport出来ないとき: device path が変わっているのでcacheを作り直す:

```shell-session
$ sudo zpool import -R /mnt/rpool rpool -o cachefile=/root/zpool.cache_saved
$ sudo zpool import -R /mnt/rpool bpool -o cachefile=/root/zpool.cache_saved
$ sudo cp /root/zpool.cache_saved /root/zpool.cache
$ sudo zpool set cachefile="" rpool
$ sudo zpool set cachefile="" bpool
$ sudo zpool export bpool
$ sudo zpool export rpool
$ sudo rm /root/zpool.cache_saved
```

## poolの確認
poolが正しくimportできたか確認する。

```shell-session
$ sudo zpool status
  pool: bpool
 state: ONLINE
status: The pool is formatted using a legacy on-disk format.  The pool can
        still be used, but some features are unavailable.
action: Upgrade the pool using 'zpool upgrade'.  Once this is done, the
        pool will no longer be accessible on software that does not support
        feature flags.
  scan: scrub repaired 0B in 0 days 00:00:12 with 0 errors on Sun Nov  8 00:24:14 2020
config:

        NAME        STATE     READ WRITE CKSUM
        bpool       ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            sdb4    ONLINE       0     0     0
            sdc4    ONLINE       0     0     0

errors: No known data errors

  pool: rpool
 state: ONLINE
  scan: scrub repaired 0B in 0 days 01:57:21 with 0 errors on Thu Dec 10 23:03:06 2020
config:

        NAME        STATE     READ WRITE CKSUM
        rpool       ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            sdb5    ONLINE       0     0     0
            sdc5    ONLINE       0     0     0

errors: No known data errors
```

## zpool.cacheの取得
```shell-session
$ sudo cp /mnt/rpool/etc/zfs/zpool.cache /root
```

## chroot
ネットワークが使えるよう、/etc/resolv.confをコピーしておく。

```shell-session
$ sudo mv /mnt/rpool/etc/resolv.conf /mnt/rpool/etc/resolv.conf_
$ sudo cp /etc/resolv.conf /mnt/rpool/etc/resolv.conf
$ sudo mount -o bind /dev /mnt/rpool/dev
$ sudo mount -o bind /dev/pts /mnt/rpool/dev/pts
$ sudo mount -o bind /mnt/wslg/.X11-unix /mnt/rpool/tmp/.X11-unix
$ sudo mount -t proc proc /mnt/rpool/proc
$ sudo mount -t sysfs sys /mnt/rpool/sys
$ sudo mount /dev/sdb2 /mnt/rpool/boot/grub #device idがずれてる場合は、/dev/sdc2等に修正する
$ sudo chroot /mnt/rpool/ /bin/su - name_of_user_at_zpool
```

## hostidの確認
.wslconfigで設定する値を調べておく。

```shell-session
$ hostid # ZFS HDD上のUbuntu
7a95e9bb
```

## chrootから抜ける
```shell-session
$ exit # ZFS HDD上のUbuntu
$ sudo umount /mnt/rpool/boot/grub
$ sudo umount /mnt/rpool/sys
$ sudo umount /mnt/rpool/proc
$ sudo umount /mnt/rpool/tmp/.X11-unix
$ sudo umount /mnt/rpool/dev/pts
$ sudo umount /mnt/rpool/dev
$ sudo rm /mnt/rpool/etc/resolv.conf
$ sudo mv /mnt/rpool/etc/resolv.conf_ /mnt/rpool/etc/resolv.conf
```
## zpool export
```shell-session
$ sudo zpool export bpool
$ sudo zpool export rpool
```

## HDDのアンマウント
管理者権限でwsl.exeを実行, \\\\.\\PHYSICALDRIVE1 と \\\\.\\PHYSICALDRIVE2をアンマウントする。

```shell-session
$ /mnt/c/Windows/system32/WindowsPowerShell/v1.0/powershell.exe \
        -NoProfile -ExecutionPolicy unrestricted \
        -Command Start-Process powerShell.exe -Wait \
        -ArgumentList \"-Command wsl --unmount \\\\.\\PHYSICALDRIVE2\; wsl --unmount \\\\.\\PHYSICALDRIVE1\" -Verb runas
```

## .wslconfigの編集
インポートするシステムのhostidをコマンドライン引数spl.spl_hostidで設定する。

```shell-session
$ vi /mnt/c/Users/name_of_user/.wslconfig
$ cat /mnt/c/Users/name_of_user/.wslconfig
[wsl2]
kernelCommandLine=spl.spl_hostid=0x7a95e9bb  # カーネルコマンド引数を指定する
memory=6GB                                   # WSL2の軽量仮想マシンで使用する最大メモリサイズを指定する
processors=6                                 # WSL2の軽量仮想マシンで使用するCPU数を指定する
swap=0                                       # WSL2の軽量仮想マシンで使用するスワップファイルのサイズを指定する
                                             # 0を指定した場合はスワップファイルを使用しない
#swapFile=<path>                             # スワップファイルに使用するVHDファイルの(Windows上の)パスを指定する
localhostForwarding=true                     # WSLのネットワークポート待ち受けを、ホストマシンにフォワーディングする

```

# スクリプトfor Ubuntu on ZFS HDD
下記スクリプトを/root/ubuntu_hdd.shに保存。
[ubuntu_hdd.sh](https://raw.githubusercontent.com/qawsed90/QiitaAttachments/main/202102/ubuntu_hdd.sh)
<details><summary>ubuntu_hdd.sh</summary><div>

```shell
#/bin/sh

ubuntu_hdd_import()
{
    echo zpool import -R /mnt/rpool -c /root/zpool.cache rpool
    zpool import -R /mnt/rpool -c /root/zpool.cache rpool
    echo zpool import -R /mnt/rpool -c /root/zpool.cache bpool
    zpool import -R /mnt/rpool -c /root/zpool.cache bpool
    echo mv /mnt/rpool/etc/resolv.conf /mnt/rpool/etc/resolv.conf_
    mv /mnt/rpool/etc/resolv.conf /mnt/rpool/etc/resolv.conf_
    echo cp /etc/resolv.conf /mnt/rpool/etc/resolv.conf
    cp /etc/resolv.conf /mnt/rpool/etc/resolv.conf
    echo mount -o bind /dev /mnt/rpool/dev
    mount -o bind /dev /mnt/rpool/dev
    echo mount -o bind /dev/pts /mnt/rpool/dev/pts
    mount -o bind /dev/pts /mnt/rpool/dev/pts
    echo mount -o bind /mnt/wslg/.X11-unix /mnt/rpool/tmp/.X11-unix
    mount -o bind /mnt/wslg/.X11-unix /mnt/rpool/tmp/.X11-unix
    echo mount -t proc proc /mnt/rpool/proc
    mount -t proc proc /mnt/rpool/proc
    echo mount -t sysfs sys /mnt/rpool/sys
    mount -t sysfs sys /mnt/rpool/sys
    echo mount /dev/sdb2 /mnt/rpool/boot/grub
    mount /dev/sdb2 /mnt/rpool/boot/grub
    echo chroot /mnt/rpool/ /bin/su - $1
    chroot /mnt/rpool/ /bin/su - $1
}

ubuntu_hdd_export()
{
    echo umount /mnt/rpool/boot/grub
    umount /mnt/rpool/boot/grub
    echo umount /mnt/rpool/sys
    umount /mnt/rpool/sys
    echo umount /mnt/rpool/proc
    umount /mnt/rpool/proc
    echo umount /mnt/rpool/tmp/.X11-unix
    umount /mnt/rpool/tmp/.X11-unix
    echo umount /mnt/rpool/dev/pts
    umount /mnt/rpool/dev/pts
    echo umount /mnt/rpool/dev
    umount /mnt/rpool/dev
    echo rm /mnt/rpool/etc/resolv.conf
    rm /mnt/rpool/etc/resolv.conf
    echo mv /mnt/rpool/etc/resolv.conf_ /mnt/rpool/etc/resolv.conf
    mv /mnt/rpool/etc/resolv.conf_ /mnt/rpool/etc/resolv.conf
    echo zpool export bpool
    zpool export bpool
    echo zpool export rpool
    zpool export rpool
}

/mnt/c/Windows/system32/WindowsPowerShell/v1.0/powershell.exe \
	-NoProfile -ExecutionPolicy unrestricted \
	-Command Start-Process powerShell.exe -Wait \
	-ArgumentList \"-Command wsl --mount \\\\.\\PHYSICALDRIVE1 --bare\; wsl --mount \\\\.\\PHYSICALDRIVE2 --bare\" -Verb runas
ubuntu_hdd_import $1
ubuntu_hdd_export
/mnt/c/Windows/system32/WindowsPowerShell/v1.0/powershell.exe \
	-NoProfile -ExecutionPolicy unrestricted \
	-Command Start-Process powerShell.exe -Wait \
	-ArgumentList \"-Command wsl --unmount \\\\.\\PHYSICALDRIVE2\; wsl --unmount \\\\.\\PHYSICALDRIVE1\" -Verb runas
```
</div></details>

## ZFSなHDD上のUbuntuに入る

```shell-session
$ sudo sh /root/ubuntu_hdd.sh name_of_user_at_zpool
zpool import -R /mnt/rpool -c /root/zpool.cache rpool
zpool import -R /mnt/rpool -c /root/zpool.cache bpool
mv /mnt/rpool/etc/resolv.conf /mnt/rpool/etc/resolv.conf_
cp /etc/resolv.conf /mnt/rpool/etc/resolv.conf
mount -o bind /dev /mnt/rpool/dev
mount -o bind /dev/pts /mnt/rpool/dev/pts
mount -o bind /mnt/wslg/.X11-unix /mnt/rpool/tmp/.X11-unix
mount -t proc proc /mnt/rpool/proc
mount -t sysfs sys /mnt/rpool/sys
mount /dev/sdb2 /mnt/rpool/boot/grub
chroot /mnt/rpool/ /bin/su - name_of_user_at_zpool
$ # ZFS HDD上のUbuntu
```

## ZFSなHDD上のUbuntuから出る

```shell-session
$ exit # ZFS HDD上のUbuntu
ログアウト
umount /mnt/rpool/boot/grub
umount /mnt/rpool/sys
umount /mnt/rpool/proc
umount /mnt/rpool/tmp/.X11-unix
umount /mnt/rpool/dev/pts
umount /mnt/rpool/dev
rm /mnt/rpool/etc/resolv.conf
mv /mnt/rpool/etc/resolv.conf_ /mnt/rpool/etc/resolv.conf
zpool export bpool
zpool export rpool
```