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

29 KiB
Raw Blame History

Сборка ядра 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:

sudo tar -czf /tmp/boot-backup.tar.gz /boot

Проверим, что архив создался:

ls -al /tmp/boot-backup.tar.gz

Увидим что архив создался:

-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). Скачиваю в неё архив:

scp opi@opi5plus-3.local:/tmp/boot-backup.tar.gz ~/backup/opi5plus-3-boot-backup.tar.gz

Что в архиве?

Если что-то пойдет не так, нам надо знать какие файлы в /boot важны и для чего предназначены. Вот список файлов ('ls -al /boot'):

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 — Изображения для экрана загрузки (не влияют на работу системы).

Устанавливать инструменты для сборки ядра

Обновим репозитории и установим минимальный инструментарий для сборки ядра:

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):

git clone --depth 1 https://github.com/orangepi-xunlong/linux-orangepi -b orange-pi-6.1-rk35xx ~/linux-orangepi

После клонирования репозитория, переходим в каталог с ним:

cd ~/linux-orangepi

И первым делом в Makefile установим EXTRAVERSION (модификатор версии ядра). Узнаем текущую версию ядра:

uname -r

Я на своем Orange Pi 5 Plus вижу (у вас может быть другая версия):

6.1.43-rockchip-rk3588

Открываем Makefile в текстовом редакторе:

nano Makefile

И устанавливаем модификатор версии ядра, строку XTRAVERSION = (у меня это пятая строчка):

EXTRAVERSION = -rockchip-rk3588

Затем копируем конфиг текущего ядра в конфиг для сборки.

zcat /proc/config.gz > .config

.config содержит все текущие настройки ядра. Это очень удобно, так как нужно добавить только поддержку нужных модулей (в нашем случае iSCSI), а не настраивать всё с нуля.

Настройка конфига с iSCSI

Теперь нужно отредактировать, .config чтобы включить iSCSI. Заходим в интерфейс конфигуратора ядра menuconfig:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

Используя стрелки на клавиатуре, чтобы двигаться по пунктам меню.

  1. Перейди в Device DriversSCSI device supportSCSI Transports.
  2. Найти внутри iSCSI Transport Attributes, с помощью стрелок выбрать его.
  3. Нажимает M (для модуля) — появится <M> рядом с пунктом. Это означает, что модуль будет собираться как модуль, а не встраиваться в ядро. Модуль (iscsi_tcp.ko) проще протестировать без перезагрузки.
  4. В нижнем меню выбрать <Save> и подтвердим сохранение в .config.
  5. Вернуться в меню выше SCSI device support (через нижнее меню <Exit>).
  6. Зайти в раздел SCSI low-level drivers.
  7. Выбрать iSCSI Initiator over TCP/IP и нажать M (для модуля).
  8. Снова сохраняем конфиг в .config (через нижнее меню <Save>).
  9. Выйти из menuconfig (через нижнее меню <Exit>, три раза).
✎ Может быть полезно:
На моём Orange Pi 5 Plus загрузка идет с NVMe диска (см. как настроить), и мне было полезно так же включить ещё и систему мониторинга NVMe: Device DriversNVME Support, найти пункт SNVMe hardware monitoring и включить его. В нижнем меню выбрать <Save> и подтвердим сохранение в .config. Выйти из menuconfig (через нижнее меню <Exit>, три раза). Теперь у меня будет возможность отслеживать состояние NVMe-диска (температуру, износ и т.д.) через инструменты вроде nvme-cli.

Проверим, что iSCSI включён:

grep -E "ISCSI_TCP|SCSI_ISCSI_ATTRS|ISCSI_BOOT" .config

Должны увидеть что-то типа:

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

Компиляция ядра и модулей

Запускаем компиляцию ядра и модулей:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8

-j8 — это количество потоков, используем столько, сколько у нас ядер. На Orange Pi 5 Plus восемь ядер. Но, например, если у вас четыре ядра, то -j4.

Компиляция займёт 20-40 минут (Orange Pi 5 Plus).

Установим модули ядра:

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 соответствующие файлы там же).

Проверим, что ядро скомпилировалось:

ls -l arch/arm64/boot/Image

Ожидаемый размер: около 40 МБ:

-rw-rw-r-- 1 opi opi 40579584 Mar 22 19:09 arch/arm64/boot/Image

Размер должен почти совпасть (или полностью совпадать) с размером текущего ядра:

ls -l /boot/Image
-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):

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):

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

Устанавливаем новые ядро и дерево:

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, если текущий работает, — его замена может сломать загрузку системы.

Все готово.

Перезагрузка в новое ядро

Тут все просто:

sudo reboot

Если что-то пошло не так и система не загрузилась

Если вы все делали правильно, то такого быть не должно. Но, тем не менее, если загрузка не произошла, то это может выглядеть двумя способами:

  • Система зависает на этапе загрузки: синенький огонек на Orange Pi не загорается и Ethernet тоже не мигает — _вы неправильно собрали ядро или испортили загрузчик.
  • Система, вроде как, грузится, но все никак… огоньки весело мигают, но не получается подключиться ни по SSH, ни другим способом, пинги на IP-адрес не проходят — вы забыли подключить модули, накосячили с конфигом или с .dtb_.

Чтобы починить, загружайтесь с MicroSD-карты (не забудьте отключить питание перед тем как вставить MicroSD-карту). Затем смонтируйте, в зависимости где у вас система, eMMC:

mkdir -p /mnt/emmc
mount /dev/mmcblk2p1 /mnt/emmc
cd /mnt/emmc

…или NVMe:

mkdir -p /mnt/nvme
mount /dev/nvme0n1p1 /mnt/nvme
cd /mnt/nvme

И восстанавливаем старое ядро и дерево описания:

sudo cp Image-original Image
sudo cp dtb/rockchip/rk3588-orangepi-5-plus.dtb-original dtb/rockchip/rk3588-orangepi-5-plus.dtb

Выключаем систему:

sudo poweroff

Вынимаем MicroSD-карту, включаем, и загрузиться старая система.

Проверка нового ядра

Если же иситма поле обновления ядра загрузилась, проверим текущую версию ядра:

uname -r

Она должна остаться той же:

6.1.43-rockchip-rk3588

Проверим, работает ли iSCSI:

sudo systemctl status iscsid

Увидим что-то вроде:

● 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.

ВСË!

А, да, не забудьте удалить репозиторий с исходниками ядра, если он вам больше не нужен:

rm -rf ~/linux-orangepi