QNAP QTS Kernel ビルド

## はじめに

QNAPのうち、GPLとなっている部分のソースコードは公開されていますが、ビルド方法などについてのドキュメントはありません。この記事では、公開されているソースコードを元にできる限りQNAPに近い環境を構築します。configureオプションなどがtarボールの中のログに残っている場合はそれに倣っています。

あくまで、検証用・作業用環境を想定した手順であるため、実運用するサーバでは適切でない設定、お作法が含まれている点はご了承ください。実際の QNAP の動作をどこまで再現できているかは分からないため、検証等で使用する場合には自己責任にてお願いいたします。

環境として近いと思われるDebian8を使用しています。他のディストリビューション、バージョンでもおそらく似たような手順で構築可能ではないかと思います。

https://sourceforge.net/projects/qosgpl/

## 使用ファイルするファイル

* https://cdimage.debian.org/cdimage/archive/8.11.1/amd64/iso-dvd/
debian-8.11.1-amd64-DVD-1.iso
* https://sourceforge.net/projects/qosgpl/files/QNAP%20NAS%20Tool%20Chains/
Cross Toolchain SDK (x86) 20180115.tgz

* https://sourceforge.net/projects/qosgpl/files/QNAP%20NAS%20GPL%20Source/QTS%205.1.0/
QTS_OSS_5.1.0.20230808.tar.gz.0
QTS_OSS_5.1.0.20230808.tar.gz.1
QTS_OSS_5.1.0.20230808.tar.gz.2
QTS_OSS_5.1.0.20230808.tar.gz.3
QTS_OSS_5.1.0.20230808.tar.gz.4
上記5ファイルを順番に連結し、`QTS_OSS_5.1.0.20230808.tar.gz`とする。
* https://sourceforge.net/projects/qosgpl/files/QNAP%20NAS%20GPL%20Source/QTS%205.1.0/
QTS_Kernel_5.1.0.20230808.tar.gz.0
QTS_Kernel_5.1.0.20230808.tar.gz.1
上記2ファイルを順番に連結し、`QTS_Kernel_5.1.0.20230808.tar.gz`とする。

* https://www.linx-info.com/mirrors/mirrors-6.0.80/pool/main/e/elfutils/
libelf-dev_0.159-4.2_amd64.deb

手順に必要なファイルはOSインストール後、/dataに配置します。

## OS (Debian8) インストール
### インストーラの設定
基本的にはデフォルトで良いと思いますが、必要に応じて変更してください。

| 項目 | 設定 |
|:-|:-|
| 言語 | 日本語 |
| ホスト名  | qnap  |
| ユーザ | test  |
| ディスクのパーティショニング | 「ガイド－ディスク全体を使う」→「すべてのファイルを１つのパーティションに」 |
| ソフトウェアの選択 | SSHサーバ、標準システムユーティリティ |
| その他  | MBRにGRUBをインストール |

### OS初期設定
ネットワーク設定は適宜読み替えてください。データ置き場として/dataを作成しています。
```
root@qnap:~# cat /etc/network/interfaces
iface eth0 inet static
  address 10.0.2.200
  netmask 255.255.255.0
  gateway 10.0.2.2
  dns-nameservers 8.8.8.8
root@qnap:~# systemctl restart ifup@eth0
root@qnap:~# apt-get update
root@qnap:~# apt-get install sudo
root@qnap:~# vi /etc/sudoers
（以下を追加）
test     ALL=(ALL:ALL) ALL
root@qnap:~# exit
test@qnap:~$ sudo mkdir /data
test@qnap:~$ sudo chmod 777 /data
```

## 必要なツールをインストール

### パッケージインストール
```
test@qnap:~$ sudo apt install build-essential
test@qnap:~$ sudo apt-get install bison flex libelf1 rsync libncurses-dev libssl-dev
test@qnap:~$ sudo dpkg -i /data/libelf-dev_0.159-4.2_amd64.deb
```

### クロスコンパイル環境インストール
```
test@qnap:~$ cd /usr/local/
test@qnap:/usr/local$ sudo tar zxvf /data/Cross\ Toolchain\ SDK\ \(x86\)\ 20180115.tgz
test@qnap:/usr/local$ vi ~/.profile
（以下を追加）
PATH=$PATH:/usr/local/x86_64-QNAP-linux-gnu/cross-tools/bin
export CROSS_COMPILE=x86_64-QNAP-linux-gnu-
```

### QNAP向けに変更されたツールのインストール
必要なソースコードを展開します。基本は/usr/localにインストールします。
```
test@qnap:~$ cd /data
test@qnap:/data$ tar zxvf QTS_OSS_5.1.0.20230808.tar.gz GPL_QTS/src/expat-2.0.0/ GPL_QTS/src/libaio-0.3.109/ GPL_QTS/src/boost_1_53_0/ GPL_QTS/src/thin-provisioning-tools-v0.4.1/ GPL_QTS/src/lvm2-2_02_138/ GPL_QTS/src/mdadm-3.3/ GPL_QTS/src/e2fsprogs-1.43.9/ GPL_QTS/src/util-linux-2.19/ GPL_QTS/src/bzip2-1.0.4 
```

```:expat-2.0.0
test@qnap:~$ cd /data/GPL_QTS/src/expat-2.0.0/
test@qnap:/data/GPL_QTS/src/expat-2.0.0$ ./configure --host=x86_64-QNAP-linux-gnu --build=x86_64-linux --disable-static --enable-shared --disable-nls
test@qnap:/data/GPL_QTS/src/expat-2.0.0$ sudo make install
```

```:ibaio-0.3.109
test@qnap:~$ cd /data/GPL_QTS/src/libaio-0.3.109/
test@qnap:/data/GPL_QTS/src/libaio-0.3.109$ sudo make prefix=/usr/local install
```

```:boost-1.53.0
test@qnap:~$ cd /data/GPL_QTS/src/boost_1_53_0/
test@qnap:/data/GPL_QTS/src/boost_1_53_0$ tar jxvf boost_1_53_0.tar.bz2
test@qnap:/data/GPL_QTS/src/boost_1_53_0$ cd boost_1_53_0/
test@qnap:/data/GPL_QTS/src/boost_1_53_0$ vi ./tools/build/v2/user-config.jam
（以下を追加）
using gcc : x86_64 : /usr/local/x86_64-QNAP-linux-gnu/cross-tools/bin/x86_64-QNAP-linux-gnu-g++ ;
test@qnap:/data/GPL_QTS/src/boost_1_53_0/boost_1_53_0$ ./bootstrap.sh
test@qnap:/data/GPL_QTS/src/boost_1_53_0/boost_1_53_0$ ./b2 toolset=gcc-x86_64
test@qnap:/data/GPL_QTS/src/boost_1_53_0/boost_1_53_0$ sudo ./b2 toolset=gcc-x86_64 install
```

```:thin-provisioning-tools-v0.4.1
test@qnap:~$ cd cd /data/GPL_QTS/src/thin-provisioning-tools-v0.4.1/
test@qnap:/data/GPL_QTS/src/thin-provisioning-tools-v0.4.1$ CPPFLAGS=-I/usr/local/include ./configure  --host=x86_64-QNAP-linux-gnu --prefix=/usr/local --enable-caching
test@qnap:/data/GPL_QTS/src/thin-provisioning-tools-v0.4.1$ LD_RUN_PATH=/usr/local/lib CXXFLAGS=-I/usr/local/include make
test@qnap:/data/GPL_QTS/src/thin-provisioning-tools-v0.4.1$ sudo PATH=$PATH make install
```

```:lvm
test@qnap:~$ cd /data/GPL_QTS/src/lvm2-2_02_138/
test@qnap:/data/GPL_QTS/src/lvm2-2_02_138$ make distclean
test@qnap:/data/GPL_QTS/src/lvm2-2_02_138$ ./configure --prefix=/usr/local --host=x86_64-QNAP-linux-gnu --disable-selinux --disable-readline --with-optimisation=-O2 --with-default-pid-dir=/var/run --with-default-dm-run-dir=/var/run --with-default-run-dir=/var/run/lvm --with-thin=internal --with-thin-check=/usr/local/sbin/thin_check --with-thin-dump=/usr/local/sbin/thin_dump --with-device-mode=0660 --with-thin-repair=/usr/local/sbin/thin_repair --with-thin-restore=/usr/local/sbin/thin_restore --with-cache-check=/usr/local/sbin/cache_check --with-cache-dump=/usr/local/sbin/cache_dump --with-cache-repair=/usr/local/sbin/cache_repair --with-cache-restore=/usr/local/sbin/cache_restore --enable-lvmetad --enable-128gb-thin-metadata
test@qnap:/data/GPL_QTS/src/lvm2-2_02_138$ LD_RUN_PATH=/usr/local/lib CFLAGS="-I/usr/include -I/usr/include/x86_64-linux-gnu -L/usr/lib/x86_64-linux-gnu -lpthread -lrt" make
test@qnap:/data/GPL_QTS/src/lvm2-2_02_138$ sudo make install
```

mdadm は /usr/local でなく、OS標準のパスに上書きインストールします。
```diff:mdadm
test@qnap:~$ cd /data/GPL_QTS/src/mdadm-3.3/
（super-intel.cを以下のように修正）
test@qnap:/data/GPL_QTS/src/mdadm-3.3$ diff -u super-intel.c.orig super-intel.c
--- super-intel.c.orig  2023-08-08 01:00:00.000000000 +0900
+++ super-intel.c       2023-08-28 21:07:29.759605599 +0900
@@ -5058,7 +5058,7 @@
        spare->num_disks = 1,
        spare->num_raid_devs = 0,
        spare->cache_size = mpb->cache_size,
-       spare->pwr_cycle_count = __cpu_to_le32(1),
+       spare->pwr_cycle_count = __cpu_to_le32(1);

        snprintf((char *) spare->sig, MAX_SIGNATURE_LENGTH,
                 MPB_SIGNATURE MPB_VERSION_RAID0);
test@qnap:/data/GPL_QTS/src/mdadm-3.3$ make
test@qnap:/data/GPL_QTS/src/mdadm-3.3$ sudo make install
```

```:e2fsprogs-1.43.9
test@qnap:~$ cd /data/GPL_QTS/src/e2fsprogs-1.43.9/
test@qnap:/data/GPL_QTS/src/e2fsprogs-1.43.9$ ./configure --host=x86_64-QNAP-linux-gnu --prefix=/usr/local --enable-elf-shlibs
test@qnap:/data/GPL_QTS/src/e2fsprogs-1.43.9$ LD_RUN_PATH=/usr/local/lib make
test@qnap:/data/GPL_QTS/src/e2fsprogs-1.43.9$ make check 
error: s_reserved size 384 should be 392
test@qnap:/data/GPL_QTS/src/e2fsprogs-1.43.9$ sudo PATH=$PATH make install
test@qnap:/data/GPL_QTS/src/e2fsprogs-1.43.9$ sudo PATH=$PATH make install-libs
```
`make check`でエラーが出るが無視します。ソースコードを見ると、QNAP拡張で予約領域に情報を追加しているようですが、それがテストコードに反映されていないのではないかと思います。

```:util-linux-2.19
test@qnap:~$ cd /data/GPL_QTS/src/util-linux-2.19/
test@qnap:/data/GPL_QTS/src/util-linux-2.19$ make distclean
test@qnap:/data/GPL_QTS/src/util-linux-2.19$ ./configure --host=x86_64-QNAP-linux-gnu --prefix=/usr/local --disable-static --enable-shared --disable-nls --without-ncurses
test@qnap:/data/GPL_QTS/src/util-linux-2.19$ make
test@qnap:/data/GPL_QTS/src/util-linux-2.19$ sudo PATH=$PATH make install
```

```:bzip2-1.0.4
test@qnap:~$ cd /data/GPL_QTS/src/bzip2-1.0.4
test@qnap:/data/GPL_QTS/src/bzip2-1.0.4$ make clean
test@qnap:/data/GPL_QTS/src/bzip2-1.0.4$ make all
test@qnap:/data/GPL_QTS/src/bzip2-1.0.4$ sudo make install
```


## QTS Kernel 5.1.0ビルド
```
test@qnap:~$ cd /data
test@qnap:/data$ tar zxvf QTS_Kernel_5.1.0.20230808.tar.gz GPL_QTS/src/linux-5.10/  GPL_QTS/kernel_cfg/
test@qnap:/data$ cd GPL_QTS/src/linux-5.10
test@qnap:/data/GPL_QTS/src/linux-5.10$ make mrproper
test@qnap:/data/GPL_QTS/src/linux-5.10$ vi Makefile
（先頭に以下の2行を追加）
include cflag_kernel_qnap.mk
KCPPFLAGS=$(CFLAGS_KERNEL_QNAP)
test@qnap:/data/GPL_QTS/src/linux-5.10$ sed -i.orig -e 's/-DNFS_QLOG //' cflag_kernel_qnap.mk
test@qnap:/data/GPL_QTS/src/linux-5.10$ cp ../../kernel_cfg/TS-X66/linux-5.10-x86_64.config .config
（構築したい環境に近いconfigコピーする）
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --disable CONFIG_VIRTUAL_DISK
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --disable CONFIG_VIRTUAL_DISK_EX
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --enable CONFIG_VIRTUAL_JBOD
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --disable CONFIG_VIRTUAL_JBOD_DEBUG
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --disable CONFIG_ISCSI_TARGET
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --disable CONFIG_TARGET_CORE

test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --module CONFIG_E1000
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --enable CONFIG_VMWARE_PVSCSI
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --enable CONFIG_VMXNET3
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --enable CONFIG_FUSION
test@qnap:/data/GPL_QTS/src/linux-5.10$ scripts/config --file .config --enable CONFIG_FUSION_SPI

```
機能的に不要であっても、ソースコードを見る限り CONFIG_VIRTUAL_JBOD を enable にしないとエラーになりそうです。CONFIG_E1000、CONFIG_VMWARE_PVSCSI、CONFIG_VMXNET3、CONFIG_FUSION、CONFIG_FUSION_SPI などは構築する環境で必要な場合に追加してください。QTSカーネルは不要なドライバは無効にしてあるようなので、SCSIドライバが不足しているとカーネル入れ替え後の起動時に以下のような画面で停止して起動できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3568423/6f6ff781-8e04-bae2-9984-6f1cefc5bbfd.png)

```
test@qnap:/data/GPL_QTS/src/linux-5.10$ make oldconfig
test@qnap:/data/GPL_QTS/src/linux-5.10$ make prepare
test@qnap:/data/GPL_QTS/src/linux-5.10$ make -j4
test@qnap:/data/GPL_QTS/src/linux-5.10$ make modules -j4
test@qnap:/data/GPL_QTS/src/linux-5.10$ make bindeb-pkg
test@qnap:/data/GPL_QTS/src/linux-5.10$ cd ..
test@qnap:/data/GPL_QTS/src$ sudo dpkg -i linux-headers-5.10.60-qnap_5.10.60-qnap-1_amd64.deb
test@qnap:/data/GPL_QTS/src$ sudo dpkg -i linux-libc-dev_5.10.60-qnap-1_amd64.deb
test@qnap:/data/GPL_QTS/src$ sudo dpkg -i linux-image-5.10.60-qnap_5.10.60-qnap-1_amd64.deb
test@qnap:/data/GPL_QTS/src$ sudo grub-mkconfig -o /boot/grub/grub.cfg
test@qnap:/data/GPL_QTS/src$ sudo vi /boot/grub/grub.cfg
        linux   /boot/vmlinuz-5.10.60-qnap root=UUID=1c2c5d2d-0f82-4657-bd89-7fa842da755c ro  quiet
　　　　　↓
        linux   /boot/vmlinuz-5.10.60-qnap root=/dev/sda1 ro console=tty0
test@qnap:/data/GPL_QTS/src$ sudo vi /etc/fstab
UUID=39a88e18-ca2c-4724-b7e5-29a90cc4ac48 none            swap    sw              0       0
↓
#UUID=39a88e18-ca2c-4724-b7e5-29a90cc4ac48 none            swap    sw              0       0

test@qnap:/data/GPL_QTS/src$ sudo reboot
```

grub.cfgのrootパーティションをUUIDではなくデバイス名で記述します。また、スワップ領域がある場合は起動時にデバイスを認識できずにタイムアウトまでに時間がかかるため、設定をコメントアウトしておきます。

## まとめ

何か検証するのであれば実機で検証するのが一番かと思いますが、どうしても実機で検証できないような事情があればこのような環境でいろいろ試してみるのも良いかと思います。

QNAPはLVMで独自拡張（セグメントタイプが thick）を行っているようで、QNAPのディスクをそのままLinux環境に接続してもうまく読めないようです。この環境であれば、おそらく普通に作成、読み書きできると思います（カーネルモジュール`dm_thin_pool`読み込みが必要）。

QNAP対応のデータ復旧ツールはQNAPを起動してSSH経由で接続するものも多いようですが、起動してしまうとジャーナルログにも影響して復旧率が下がると思いますが…。QNAPディスクをそのまま認識してデータ復旧できるようなツールはどのようにしているのでしょうね。


## 参考

* [Ubuntuで最新のカーネルをお手軽にビルドする方](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0526)
* [Linuxカーネルビルド大全](https://qiita.com/progrunner/items/d2ab0a85b3881a4b7ed8)
* [QNAPフォーラムへのビルド方法の投稿](https://forum.qnap.com/viewtopic.php?t=93862#p500457)
* [Debian8での構築例](https://271328.com/1048/)
* [Systemd かつ UEFI boot な Linux で Swap をOffにする方法 ～ fstab が全てとは限らない](https://qiita.com/10yama/items/1ab36a638c6e5c11c136)
* [QNAPのLVMは拡張してあり普通のLinuxで扱えない場合があるっぽい](https://taiyakon.com/2020/10/qnap-extended-lvm.html)