doc_memo/raspberry-and-orange-pi/opi5plus-rebuilding-linux-kernel-for-iscsi.md
2025-03-25 16:04:39 +03:00

399 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Сборка ядра Linux для Orange Pi 5 Plus (и других устройств на Rockchip RK3588) с поддержкой iSCSI
Для моего проекта (k3s на Orange Pi 5 Plus) потребовалась поддержка система управления блочным хранилищем 'longhorn'
(longhorn.io). _Longhorn_ позволяет создавать надёжные тома для контейнеров, автоматически реплицируя их между узлами
и обеспечения высокую доступности приложений (если один узел выходит из строя, данные остаются доступны на репликах
на других узлах).
Для _longhorn_ нужен `iSCSI` (**Internet Small Computer System Interface**) — сетевой протокол, который по TCP/IP
подсоединяет удалённые диски так, будто они подключены физически. Longhorn через iSCSI обеспечивает передачу
данных между узлами по сети.
В ядре Linux поддержка _iSCSI_ реализована через модули, такие как `iscsi_tcp` и `scsi_transport_iscsi`. Однако,
в большинстве дистрибутивов для одноплатных компьютеров, включая и Orange Pi 5 Plus, эти модули отключены. Это делают
для экономии ресурсов, да и в целом, это нетипичный сценарий использования Orange Pi. В версии Ubuntu 22.04
для Orange Pi 5 Plus (в ядре от Xunlong), поддержка iSCSI тоже отключена, и это делает невозможным запуск Longhorn
из коробки.
**А значит нужно компиляция ядра (сбока)**
Мы вручную включим поддержку _iSCSI_ (модули `iscsi_tcp` и `scsi_transport_iscsi`), и cможем настроить
ядро под свои задачи. Однако компиляция и его замена требует осторожности и внимательности, ошибка в процессе может
привести к тому, что система не загрузится (но мы сделаем резервную копию текущего ядра, загрузчика, чтобы можно
было восстановить систему).
Обновления системы (например, через `apt`) с новым ядром будет проходить, как обычно: пакеты, утилиты и приложения
обновятся без проблем. Однако пересобранное ядро больше не будет автоматически обновляться через стандартные средства
дистрибутива. Если выйдет новая версия ядра, то придётся вручную повторить процесс компиляции. К счастью,
поставщик (это Xunlong) обновляет ядро не часто.
| ✎ Заметка |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Orange Pi 5 Plus использует процессор **Rockchip RK3588** (как и многие другие устройства под брендом Orange). Процесс компиляции ядра для всех RK35xx почти идентичен, и базируется на одном и том же дистрибутиве. Однако, разные периферийные устройства: например, GPIO, USB или Ethernet-контроллеры могут отличаться. Мы будем использовать `.config` от текущего, рабочего ядра, так что настройки будут актуальны. Но следует иметь в виду, что возможно, в будущем могут появиться изменения в конфигурации, дистрибутива и т.п. Следует учитывать, это и **никто ничего не гарантирует**. |
## План сборки ядра с iSCSI
* Резервное копирование текущего ядра, загрузчика, дерева устройств, /boot и т.п.
* Установить инструментарий для настройки и компиляции ядра
* Скачать исходники.
* Настроить конфиг для включения модулей iSCSI (и мониторинга NVMe).
* Скомпилировать ядро и модули.
* Установить новое ядро.
* Перезагрузиться в новое ядро.
* Проверка.
## Резервное копирование текущего ядра и /boot
Архивируем том `/boot` на нашем Orange Pi 5 Plus во временный каталог `/tmp`:
```bash
sudo tar -czf /tmp/boot-backup.tar.gz /boot
```
Проверим, что архив создался:
```bash
ls -al /tmp/boot-backup.tar.gz
```
Увидим что архив создался:
```text
-rw-r--r-- 1 root root 62116591 мар 23 20:33 /tmp/boot-backup.tar.gz
```
Теперь нам нужно скопировать его на какой-нибудь внешний хост (или носитель, но я буду копировать на хост другого
компьютера). Если что-то пойдёт не так (например, после обновления ядра система не загрузится) можно будет восстановить
файлы из этого архива. Мой Orange Pi 5 Plus, на котором я буду компилировать ядро имеет хост — `opi5plus-3` (замени
на свой хост), а имя пользователя от которого я работаю — `opi` (замени на свой). На рабочем компьютере, с которого
я захожу по SSH на Orange, у меня есть папка `~/backup/` (`mkdir -p ~/backup`). Скачиваю в неё архив:
```bash
scp opi@opi5plus-3.local:/tmp/boot-backup.tar.gz ~/backup/opi5plus-3-boot-backup.tar.gz
```
### Что в архиве?
Если что-то пойдет не так, нам надо знать какие файлы в `/boot` важны и для чего предназначены. Вот список файлов
('ls -al /boot'):
```text
drwxr-xr-x 4 root root 4096 янв 1 1970 ./
drwxr-xr-x 19 root root 4096 фев 16 19:59 ../
-rwxr-xr-x 1 root root 230456 ноя 21 09:56 boot.bmp*
-rwxr-xr-x 1 root root 3341 ноя 21 09:55 boot.cmd*
-rwxr-xr-x 1 root root 3413 ноя 21 10:04 boot.scr*
-rwxr-xr-x 1 root root 230393 ноя 21 07:08 config-6.1.43-rockchip-rk3588*
drwxr-xr-x 3 root root 4096 ноя 21 09:55 dtb/
drwxr-xr-x 3 root root 4096 ноя 21 09:55 dtb-6.1.43-rockchip-rk3588/
-rwxr-xr-x 1 root root 40579584 ноя 21 07:08 Image*
-rwxr-xr-x 1 root root 15462140 мар 21 16:36 initrd.img-6.1.43-rockchip-rk3588*
-rwxr-xr-x 1 root root 1152056 ноя 21 09:56 logo.bmp*
-rwxr-xr-x 1 root root 0 ноя 21 09:55 .next*
-rwxr-xr-x 1 root root 178 фев 16 19:59 orangepiEnv.txt*
-rwxr-xr-x 1 root root 1542 ноя 21 09:56 orangepi_first_run.txt.template*
-rwxr-xr-x 1 root root 6209932 ноя 21 07:08 System.map-6.1.43-rockchip-rk3588*
-rwxr-xr-x 1 root root 15462204 мар 21 16:36 uInitrd*
-rwxr-xr-x 1 root root 40579584 ноя 21 07:08 vmlinuz-6.1.43-rockchip-rk3588*
```
Ключевые файлы:
* `Image` — собственно ядро Linux (в данном случае версия 6.1.43 для Rockchip RK3588). При старте компьютера загрузчик
U-Boot загрузит его в память и передаст ему управление. Без этого файла система не запустится.
* `vmlinuz-6.1.43-rockchip-rk3588` — копия ядра (в системе уже есть резервная копия).
* `dtb/` — Каталог файлами **Device Tree Blob** (`DTB`). Это бинарные файлы, описывающие аппаратное обеспечение устройства.
Для Orange Pi 5 Plus используется файл вроде `rk3588-orangepi-5-plus.dtb` (находится в подкаталоге `dtb/rockchip/`).
DTB передаётся ядру, чтобы оно знало, как работать с процессором (количество ядер, частоты), памятью (RAM, её объём
и адреса), периферией (UART, I2C, SPI, Ethernet, USB, GPIO, прерывания и тому подобное). На ARM-устройствах
(в отличие от x86, где есть ACPI) нет стандартного способа обнаружения оборудования. DTB решает эту проблему,
предоставляя ядру "карту" железа. U-Boot загружает DTB из `/boot/dtb/ `и передаёт его ядру при старте. Кстати,
в подкаталоге dtb/rockchip/ есть `overlay/` — это дополнительные файлы, которые могут использоваться для добавления
и/или изменения функциональности устройства. Например, можно добавить поддержку новых периферийных устройств (камеру,
дисплей и т.п.).
* `uInitrd` — Начальный RAM-диск (initrd), адаптированный для U-Boot. Содержит модули и скрипты, необходимые для
пред-загрузки (выбор накопителя, монтирование корневой файловой системы и т.п.). Если он повреждён или несовместим
с ядром, загрузка может упасть на этапе инициализации.
* `orangepiEnv.txt` — Конфигурационный файл для U-Boot. Здесь задаются параметры загрузки, такие как путь расположение
дерева DTB, UUID корневой файловой системы, тип файловой системы… Без правильных настроек в этом файле U-Boot не
найдёт нужные для загрузки файлы.
* `boot.scr` — Скрипт загрузки для U-Boot. Содержит команды для загрузки ядра, initrd и DTB. U-Boot выполняет его
при старте системы. Этот файл создаётся из `boot.cmd` с помощью утилиты `mkimage`. Если он повреждён или отсутствует,
U-Boot не сможет загрузить систему.
* `dtb-6.1.43-rockchip-rk3588/` — Копия каталога `dtb/`, обычно появляется, когда ядро устанавливается или обновляется
через пакетный менеджер (например, `apt`). Она привязана к конкретной версии ядра — в данном случае
`6.1.43-rockchip-rk3588`, для того, чтобы: Хранить DTB-файлы, соответствующие этой версии ядра и избегать конфликты
между DTB от разных версий ядра (если используется несколько ядер на одной системе).
Менее критичные, но полезные файлы:
* `config-6.1.43-rockchip-rk3588` — Конфигурация ядра, использованная при его сборке (он нам понадобится, чтобы
пересобрать ядро с iSCSI).
* `System.map-6.1.43-rockchip-rk3588` — Карта меток (символов) ядра, полезна для отладки.
* `initrd.img-6.1.43-rockchip-rk3588` — Обычный initrd, из которого генерируется uInitrd.
* `boot.bmp` и `logo.bmp` — Изображения для экрана загрузки (не влияют на работу системы).
## Устанавливать инструменты для сборки ядра
Обновим репозитории и установим минимальный инструментарий для сборки ядра:
```bash
sudo apt update
sudo apt install -y build-essential bc flex bison libssl-dev libncurses-dev git
```
Нам понадобятся следующие пакеты:
* `build-essential` — Включает `gcc` (для ARM64, make и другие базовые инструменты компиляции.
* `bc` — Утилита для точных математических вычислений в командной строке. Используется для вычислений в скриптах сборки ядра.
* `flex` и `bison` — генератор лексических анализаторов и парсер. Нужны для обработки конфигурационных файлов ядра.
* `libssl-dev` — Для поддержки криптографии в ядре и `OpenSSL`.
* `libncurses-dev` — Библиотека для создания текстовых интерфейсов в терминале. Необходимо для работы интерфейса
`menuconfig` при настройке параметров ядра.
* `git` — Для клонирования исходного кода ядра из репозитория Xunlong.
> **Примечание:** Если вы хотите собрать ядро на x86-системе, установите кросс-компилятор `gcc-aarch64-linux-gnu` (`sudo apt install gcc-aarch64-linux-gnu`) и используйте его вместо обычного gcc в командах сборки. Он позволит собрать ядро для ARM64-архитектуры на x86-системе.
## Скачивание и подготавливаем исходники ядра
Клонируем репозиторий Orange Pi для ядра 6.1 из репозитория Xunlong. Мы будем брать ветку (branch)
`orange-pi-6.1-rk35xx`. Это ветка с исходниками для всех устройств на базе Rockchip RK35xx (включая Orange Pi 5 Plus):
```bash
git clone --depth 1 https://github.com/orangepi-xunlong/linux-orangepi -b orange-pi-6.1-rk35xx ~/linux-orangepi
```
После клонирования репозитория, переходим в каталог с ним:
```bash
cd ~/linux-orangepi
```
И первым делом в `Makefile` установим `EXTRAVERSION` (модификатор версии ядра). Узнаем текущую версию ядра:
```bash
uname -r
```
Я на своем Orange Pi 5 Plus вижу (у вас может быть другая версия):
```text
6.1.43-rockchip-rk3588
```
Открываем `Makefile` в текстовом редакторе:
```bash
nano Makefile
```
И устанавливаем модификатор версии ядра, строку `XTRAVERSION =` (у меня это пятая строчка):
```text
EXTRAVERSION = -rockchip-rk3588
```
Затем копируем конфиг текущего ядра в конфиг для сборки.
```bash
zcat /proc/config.gz > .config
```
`.config` содержит все текущие настройки ядра. Это очень удобно, так как нужно добавить только поддержку нужных модулей
(в нашем случае `iSCSI`), а не настраивать всё с нуля.
## Настройка конфига с iSCSI
Теперь нужно отредактировать, `.config` чтобы включить `iSCSI`. Заходим в интерфейс конфигуратора ядра `menuconfig`:
```bash
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
```
Используя стрелки на клавиатуре, чтобы двигаться по пунктам меню.
1. Перейди в `Device Drivers` → `SCSI device support` → `SCSI Transports`.
2. Найти внутри `iSCSI Transport Attributes`, с помощью стрелок выбрать его.
3. Нажимает `M` (для модуля) — появится `<M>` рядом с пунктом. Это означает, что модуль будет собираться как модуль,
а не встраиваться в ядро. Модуль (`iscsi_tcp.ko`) проще протестировать без перезагрузки.
4. В нижнем меню выбрать `<Save>` и подтвердим сохранение в `.config`.
6. Вернуться в меню выше `SCSI device support` (через нижнее меню `<Exit>`).
7. Зайти в раздел `SCSI low-level drivers`.
8. Выбрать `iSCSI Initiator over TCP/IP` и нажать `M` (для модуля).
9. Снова сохраняем конфиг в `.config` (через нижнее меню `<Save>`).
10. Выйти из `menuconfig` (через нижнее меню `<Exit>`, три раза).
| ✎ Может быть полезно: |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| На моём Orange Pi 5 Plus загрузка идет с NVMe диска ([см. как настроить](opi5plus-move-system-to-nvme-or-emmc.md)), и мне было полезно так же включить ещё и систему мониторинга NVMe: `Device Drivers` → `NVME Support`, найти пункт `SNVMe hardware monitoring` и включить его. В нижнем меню выбрать `<Save>` и подтвердим сохранение в `.config`. Выйти из `menuconfig` (через нижнее меню `<Exit>`, три раза). Теперь у меня будет возможность отслеживать состояние NVMe-диска (температуру, износ и т.д.) через инструменты вроде `nvme-cli`. |
Проверим, что iSCSI включён:
```bash
grep -E "ISCSI_TCP|SCSI_ISCSI_ATTRS|ISCSI_BOOT" .config
```
Должны увидеть что-то типа:
```text
CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_ISCSI_TCP=m
# CONFIG_ISCSI_BOOT_SYSFS is not set
```
| ✎ Проверка, что включен мониторинг NVMe (если включали): |
|---------------------------------------------------------------|
| `grep -E "NVME_HWMON" .config` и увидим `CONFIG_NVME_HWMON=y` |
## Компиляция ядра и модулей
Запускаем компиляцию ядра и модулей:
```bash
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8
```
`-j8` — это количество потоков, используем столько, сколько у нас ядер. На Orange Pi 5 Plus восемь ядер. Но, например,
если у вас четыре ядра, то `-j4`.
Компиляция займёт 20-40 минут (Orange Pi 5 Plus).
Установим модули ядра:
```bash
sudo make modules_install
```
После завершения ядро будет находиться в каталоге `~/linux-orangepi/arch/arm64/boot/` (файл `Image`), а дерево описания
устройства в `~/linux-orangepi/arch/arm64/boot/dts/rockchip/` (наш файл для Orange Pi 5 Plus --
`rk3588-orangepi-5-plus.dtb`, дле версий 5, 5 Max, AI, Ultra соответствующие файлы там же).
Проверим, что ядро скомпилировалось:
```bash
ls -l arch/arm64/boot/Image
```
Ожидаемый размер: около 40 МБ:
```text
-rw-rw-r-- 1 opi opi 40579584 Mar 22 19:09 arch/arm64/boot/Image
```
Размер должен почти совпасть (или полностью совпадать) с размером текущего ядра:
```bash
ls -l /boot/Image
```
```text
-rwxr-xr-x 1 root root 40579584 Nov 21 07:08 /boot/Image
```
И это не ошибка. Мы добавили только `CONFIG_ISCSI_TCP=m` и `CONFIG_SCSI_ISCSI_ATTRS=m`. Это подключит модули (`iscsi_tcp.ko`),
но само ядро (`Image`) почти не увеличивается, ведь `.ko`-модуль iSCSI не встраивается в ядро (мы выбрали `<M>`,
а не `<*>`). Кроме того, Linux выравнивает размеры файлов по блокам (например, 4 Кб), и добавление
пары небольших модулей могут не повлиять на итоговый размер.
## Устанавливаем новое ядро рядом со старым
Мы должны скопировать два файла в `/boot`. Первый — это `Image`. Это само ядро, и оно скомпилировалось в каталог
`~/linux-orangepi/arch/arm64/boot/`. Второй файл — это `rk3588-orangepi-5-plus.dtb`. Он находится
в `~/linux-orangepi/arch/arm64/boot/dts/rockchip/`. Как было сказано выше, это дерево описания оборудования
(Device Tree Blob), и нужно при загрузке ядра. Кстати, при компиляции мы получили `.dtb` для всех моделей Orange Pi 5
(5, 5 Plus, 5 Max, AI, Ultra). Для моей модели (Orange Pi 5 Plus) нужен `rk3588-orangepi-5-plus.dtb`, а вы можете
взять другой, для своей модели.
Копируем новые файлы в `/boot` с уникальными именами (с суффиксом `-iscsi`):
```bash
sudo cp ~/linux-orangepi/arch/arm64/boot/Image /boot/Image-iscsi
sudo cp ~/linux-orangepi/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dtb /boot/dtb/rockchip/rk3588-orangepi-5-plus.dtb-iscsi
```
Старое ядро и дерево описания переименуем (это будет резервная копия, с суффиксом `-original`):
```bash
sudo mv /boot/Image /boot/Image-original
sudo mv /boot/dtb/rockchip/rk3588-orangepi-5-plus.dtb /boot/dtb/rockchip/rk3588-orangepi-5-plus.dtb-original
```
Устанавливаем новые ядро и дерево:
```bash
sudo cp /boot/Image-iscsi /boot/Image
sudo cp /boot/dtb/rockchip/rk3588-orangepi-5-plus.dtb-iscsi /boot/dtb/rockchip/rk3588-orangepi-5-plus.dtb
```
> **Важно**: Не обновляйте `uInitrd`, если текущий работает, — его замена может сломать загрузку системы.
Все готово.
## Перезагрузка в новое ядро
Тут все просто:
```bash
sudo reboot
```
#### Если что-то пошло не так и система не загрузилась
Если вы все делали правильно, то такого быть не должно. Но, тем не менее, если загрузка не произошла, то это может
выглядеть двумя способами:
* Система зависает на этапе загрузки: синенький огонек на Orange Pi не загорается и Ethernet тоже не мигает —
_вы неправильно собрали ядро или испортили загрузчик.
* Система, вроде как, грузится, но все никак… огоньки весело мигают, но не получается подключиться ни по SSH, ни
другим способом, пинги на IP-адрес не проходят — вы забыли подключить модули, накосячили с конфигом или с `.dtb`_.
Чтобы починить, загружайтесь с MicroSD-карты (не забудьте отключить питание перед тем как вставить MicroSD-карту).
Затем смонтируйте, в зависимости где у вас система, eMMC:
```bash
mkdir -p /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
cd /mnt/emmc
```
…или NVMe:
```bash
mkdir -p /mnt/nvme
mount /dev/nvme0n1p1 /mnt/nvme
cd /mnt/nvme
```
И восстанавливаем старое ядро и дерево описания:
```bash
sudo cp Image-original Image
sudo cp dtb/rockchip/rk3588-orangepi-5-plus.dtb-original dtb/rockchip/rk3588-orangepi-5-plus.dtb
```
Выключаем систему:
```bash
sudo poweroff
```
Вынимаем MicroSD-карту, включаем, и загрузиться старая система.
## Проверка нового ядра
Если же иситма поле обновления ядра загрузилась, проверим текущую версию ядра:
```bash
uname -r
```
Она должна остаться той же:
```text
6.1.43-rockchip-rk3588
```
Проверим, работает ли iSCSI:
```bash
sudo systemctl status iscsid
```
Увидим что-то вроде:
```text
● iscsid.service - iSCSI initiator daemon (iscsid)
Loaded: loaded (/lib/systemd/system/iscsid.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2025-03-24 17:51:59 MSK; 28min ago
TriggeredBy: ● iscsid.socket
Docs: man:iscsid(8)
Main PID: 1070 (iscsid)
Tasks: 2 (limit: 18977)
Memory: 4.6M
CPU: 94ms
CGroup: /system.slice/iscsid.service
├─1069 /sbin/iscsid
└─1070 /sbin/iscsid
мар 24 17:51:58 opi5plus-3 systemd[1]: Starting iSCSI initiator daemon (iscsid)...
мар 24 17:51:59 opi5plus-3 iscsid[1061]: iSCSI logger with pid=1069 started!
мар 24 17:51:59 opi5plus-3 iscsid[1069]: iSCSI daemon with pid=1070 started!
мар 24 17:51:59 opi5plus-3 systemd[1]: Started iSCSI initiator daemon (iscsid).
```
Как видим, `active (running)`, значит iSCSI работает.
| ✎ Заметка |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Если вы включили мониторинг NVMe, то проверим и его. Установим nvme-cli: `sudo apt install nvme-cli` и проверим состояние нашего накопителя `sudo nvme smart-log /dev/nvme0n1`. |
**ВСË!**
А, да, не забудьте удалить репозиторий с исходниками ядра, если он вам больше не нужен:
```bash
rm -rf ~/linux-orangepi
```