seungwoolee518

Recompile WSL2 Linux Kernel with `ublk` support

Note: I am not familiar with English. Please understand.


Preface

I've started to digging into ublk to replace NBD (Network Block Device).

Seems like it's fairly simple to implement using io_uring to Queue requests and response.

Before to digging into that, I need a simple (but time-consuming task depends on your machine's horsepower) tasks: "Recompile WSL2 Kernel to support ublk"

the how-to guides are derived from Microsoft's How-to use the Microsoft Linux kernel v6 on Windows Subsystem for Linux version 2 (WSL2) Documentation.

ublk is started to support Linux Kernel 6, so you should clone 6.0 version on WSL2 Kernel. Source

and there is a Release to add loadable modules, however it only supports NETFILTER_XT_TARGET_CT, NETFILTER_XT_MATCH_BPF, and NETFILTER_XT_MA. I expects if they're release 6.x version of the Kernel, they'll supports more loadable kernel. (but you should've recompile the kernel for now)

the environment is based on Ubuntu (that the original documentation is based on Ubuntu (or Debian based OS that support apt and other tools))

Build

0. Create Ubuntu Environment

  • Enable WSL.
  • Download Ubuntu from Microsoft Store.

1. Clone Microsoft's WSL2 Kernel Repository

the documentation suggest to clone whole repository's data (IDK why), but I'll takes some time depending on your Internet connectivity and machine's horsepower.

I'll add depth and branch when clone the repo to keep minimize.

$ git clone --depth=1 --branch linux-msft-wsl-6.1.y https://github.com/microsoft/WSL2-Linux-Kernel.git

2. Install dependencies.

  • don't forget to install bc and dwarves
$ sudo apt update && sudo apt install build-essential flex bison libssl-dev libelf-dev bc dwarves

3. Modify config to enable CONFIG_BLK_DEV_UBLK

  • Modify Microsoft/config-wsl to add CONFIG_BLK_DEV_UBLK=y

4. Compile!

the compile time can be slow depends on your machine's horsepower.

$ make -j$(nproc) KCONFIG_CONFIG=Microsoft/config-wsl

If the compile is success, you can see the line like this.

Kernel: arch/x86/boot/bzImage is ready  (#2)

5. Install the kernel modules and headers

$ sudo make modules_install headers_install

6. Copy bzImage to Windows root drive

  • replace ${USERNAME} to appropriate Windows Username.
  • the bzImage is located on x86_64 directory. NOT x86
cp arch/x86_64/boot/bzImage /mnt/c/Users/${USERNAME}

7. Create wslconfig to use compiled kernel

  • edit (or create) %USERPROFILE%\.wslconfig to use built kernel image.
  • usually, %USERPROFILE% is $HOME directory of Windows. (you can check via $env:USERPROFILE)
[wsl2]
kernel=C:\\Users\${USERNAME}\bzImage
  • and run wsl --shutdown to stop WSL instance as administrator.

8. Verify WSL is using compiled kernel.

  • type uname to verify WSL instance is using compiled kernel.
$ uname -a
# Linux ${USERNAME} 6.1.21.2-microsoft-standard-WSL2+ #2 SMP ${TIMESTAMP} x86_64 x86_64 x86_64 GNU/Linux

Build liburing2

liburing2 is not the latest version on Ubuntu. and ubdsrv requires liburing2 version greater than 2.2, so It requires to build on myself.

Ref: https://dev.to/amarjargal/testing-ublk-on-ubuntu-2204-9pe

Clone Liburing

$ git clone https://github.com/axboe/liburing
$ cd liburing
$ git checkout liburing-2.5

Build Liburing

$ ./configure
$ make
$ sudo make install

Build Ubdsrv

  • follow: https://github.com/ming1/ubdsrv#how-to-build-ublksrv

1. Clone Ubdsrv repository

$ git clone https://github.com/ming1/ubdsrv.git

2. Install dependencies

$ sudo apt install autoconf libtool pkg-config

3. Build and Install

$ autoreconf -i
$ ./configure   #pkg-config and libtool is usually needed
$ sudo make install

4. Add Library Path to /etc/ld.so.conf

  • when you run ublk, you'll get error like this.
$ ublk
# ublk: error while loading shared libraries: libublksrv.so.0: cannot open shared object file: No such file or directory
  • you should modify /etc/ld.so.conf to add /usr/local/lib/ and run sudo ldconfig to apply the configuration.

  • when all of the configuration is correctly applied, you can see commands list when you type ublk

$ ublk --help
ublk add -t {null|loop|qcow2|nbd}
        -n DEV_ID -q NR_HW_QUEUES -d QUEUE_DEPTH
        -u URING_COMP -g NEED_GET_DATA -r USER_RECOVERY
        -i USER_RECOVERY_REISSUE --debug_mask=0x{DBG_MASK}
        --unprivileged

        target specific command line:
           loop: -f backing_file [--buffered_io]
                default is direct IO to backing file
           qcow2: -f backing_file
           nbd: --host=$HOST [--port=$PORT] | --unix=$UNIX_PATH
ublk del -n DEV_ID [-a | --all]
ublk list [-n DEV_ID]
ublk recover [-n DEV_ID]
ublk features
ublk -v [--version]
ublk -h [--help]

Finally

you can use ublk command to configure disks (by communicating with /dev/ublk-control)

let's create 10G of the image and add that image to ublk.

Prepare image

  • you can adjust 10G to another size.
$ fallocate -l 10G hello.img

Add image to Ublk

when you run the command, the receiver is running on background to handle request on the fly. (you can verify it using ps command.)

$ sudo ublk add -t loop -f hello.img

when it success, it'll print like this. you can find device by ublkb field.

dev id 0: nr_hw_queues 1 queue_depth 128 block size 4096 dev_capacity 20971520
        max rq size 524288 daemon pid 10427 flags 0x0 state LIVE
        ublkc: 0:0 ublkb: 0:6 owner: 0:0
        queue 0: tid 10428 affinity(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 )
        target {"backing_file":"hello.img","dev_size":10737418240,"direct_io":1,"name":"loop","type":1}

also, you can list added devices using ublk list command.

Format Disk and Let it mount!

format the disk using mkfs.ext4 and mount to somewhere

$ sudo mkfs.ext4 /dev/ublkb0
# prepare mountpoint and mount
$ sudo mkdir -p /mnt/ublk-mountpoint
$ sudo mount /dev/ublkb0 /mnt/ublk-mountpoint

Remove Device

use ublk del command to remove device.

you should run ublk list first to find device number located on ublkb field. and use that number to remove the device.