NAPI-C (RK3308): подготовка ядра и системы к поиску причин паники и перезагрузки
Что настроить заранее, чтобы при падении или зависании платы получить текст ошибки, а не «плата перезагрузилась, причина неи звестна». Без этих настроек упавшая под нагрузкой плата не оставляет ни строчки: проверки в ядре срабатывают, но текст ошибки некуда сохранить.
0. Принцип: цепочка из четырёх звеньев
Каждое падение должно пройти всю цепочку, иначе отладка бесполезна:
- Обнаружить — ядро должно заметить ошибку (проверки, детекторы зависаний).
- Превратить в панику — тихое зависание или WARN должны стать паникой с текстом, иначе плату просто перезагрузит аппаратный сторож без единого слова.
- Сохранить — текст паники должен пережить перезагрузку (ramoops/pstore) или уйти наружу по каналу, который работает даже в момент паники (последовательная консоль).
- Не затереть — после перезагрузки плата должна загрузить ту же систему и прочитать дамп, а не другое ядро, которое перепишет память.
Если ошибки «с лучайные» и задевают не связанные между собой объекты (чужие процессы, файлы в
кэше, initrd), до отладки ядра стоит проверить саму плату: memtester на 30 мин при
остановленной нагрузке и, если есть, такая же вторая плата под той же нагрузкой.
1. Ядро: опции конфигурации
Что есть в штатном ядре Armbian 6.18 и что стоит включить в отладочную сборку:
| Опция | Штатно | Зачем |
|---|---|---|
CONFIG_PSTORE, CONFIG_PSTORE_RAM | y, m | основа: дамп паники в RAM, переживает тёплую перезагрузку |
CONFIG_PSTORE_CONSOLE | нет | весь консольный вывод последних секунд, а не только kmsg_dump при панике |
CONFIG_PSTORE_PMSG | нет | /dev/pmsg0: пользовательские метки (blackbox) прямо в pstore |
CONFIG_SOFTLOCKUP_DETECTOR | нет | CPU завис в ядре > 2×watchdog_thresh → сообщение/паника |
CONFIG_HARDLOCKUP_DETECTOR + _BUDDY | нет | зависание с выключенными прерыв аниями; на RK3308 (GIC-400, нет pseudo-NMI) работает только «buddy»-вариант: соседний CPU замечает замёрзший |
CONFIG_DETECT_HUNG_TASK | нет | задача в D-состоянии > N секунд |
CONFIG_KFENCE | нет | дешёвый (можно держать в работе) выборочный детектор use-after-free и выходов за границы; ловит редкие UAF за часы работы |
CONFIG_SLUB_DEBUG | y | включается параметром slub_debug= без пересборки |
CONFIG_KASAN (generic) | нет | самый точный детектор UAF, но ×2–3 по памяти и CPU; на 512 МБ — только для коротких прогонов |
CONFIG_DEBUG_LIST, CONFIG_BUG_ON_DATA_CORRUPTION | нет | порча списков (типично при UAF URB) → сразу BUG с местом, а не падение позже |
CONFIG_DEBUG_OBJECTS_WORK/_TIMERS | нет | освобождение работающего work/timer — родственный класс ошибок |
CONFIG_PROVE_LOCKING (lockdep) | нет | ошибки блокировок; тяжёлый, для отдельного прогона |
CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC | нет | у dw_wdt есть pretimeout: за N секунд до аппаратного сброса — паника с дампом. Превращает «молчаливый» сброс сторожем в текст |
CONFIG_KALLSYMS_ALL | нет | име на и данных в стеке |
CONFIG_DEBUG_INFO | y | сохранять vmlinux и модули с символами от каждой сборки, иначе стек не расшифровать |
CONFIG_NETCONSOLE, CONFIG_USB_MON, CONFIG_MAGIC_SYSRQ | m, m, y | есть |
Для поиска одной конкретной ошибки лучше две сборки: «долгая» (KFENCE, детекторы зависаний, DEBUG_LIST, pretimeout — почти без замедления, чтобы не спугнуть гонку) и «точная» (KASAN/lockdep — короткие прогоны).
2. Device Tree: память для ramoops
В DT Armbian для NAPI-C нет reserved-memory для ramoops, поэтому pstore не работал.
Решение — пользовательский оверлей /boot/overlay-user/napi-ramoops.dtbo, в armbianEnv.txt:
user_overlays=napi-ramoops.
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target-path = "/";
__overlay__ {
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
ramoops@f000000 {
compatible = "ramoops";
reg = <0x0 0x0f000000 0x0 0x100000>; /* 1 МиБ на 240 МиБ */
record-size = <0x20000>;
console-size = <0x20000>;
max-reason = <2>; /* oops и panic */
};
};
};
};
};
Сборка на плате: dtc -@ -I dts -O dtb -o /boot/overlay-user/napi-ramoops.dtbo napi-ramoops.dts.
⚠ Не загружать ramoops без зарезервированной памяти. modprobe ramoops mem_address=... на
системе, где этот участок не вынесен в reserved-memory, пишет поверх памяти, которой уже
пользуется ядро, и портит работающую систему. Только через оверлей.
Модуль: echo ramoops > /etc/modules-load.d/napi-ramoops.conf.
Адрес выбран так, чтобы его не трогал U-Boot (он перемещает себя в верх памяти, ядро грузит с
0x00280000, initrd около 0x0a200000). Признак успеха в dmesg:
ramoops: using 0x100000@0xf000000.
Важно: при загрузке systemd-pstore.service переносит файлы из /sys/fs/pstore в
/var/lib/systemd/pstore/ — смотреть надо там, а не в /sys/fs/pstore.
3. Параметры загрузки (armbianEnv.txt, extraargs)
rcupdate.rcu_cpu_stall_timeout=10— RCU stall через 10 с (по умолчанию 21 с, позж е сторожа).slub_debug=FZPU,kmalloc-1k,kmalloc-2k— проверки только нужных кешей (здесь kmalloc-1k/2k); полныйslub_debug=FZPUдорог на 512 МБ.kfence.sample_interval=10(если KFENCE собран) — чаще выборка, выше шанс поймать.ftrace_dump_on_oops+ трассировка нужной подсистемы в кольцевой буфер — при панике хвост трассы уходит в консоль/pstore (нуженPSTORE_CONSOLEи запас размера).printk.devkmsg=on— запись меток в/dev/kmsgбез ограничения частоты.kasan_multi_shot(если собран KASAN) — по умолчанию KASAN сообщает только первую ошибку и замолкает: если первой окажется безобидная находка при загрузке, настоящую ошибку KASAN уже не покажет. Сkasan_multi_shot— все отчёты (но может засыпать консоль, если безобидная ошибка повторяется).
4. sysctl (/etc/sysctl.d/)
kernel.panic = 10 # перезагрузка через 10 с после паники
kernel.panic_on_oops = 1
kernel.panic_on_warn = 0 # 0, пока нужен текст WARN в журнале; 1 — если важнее дамп в pstore
kernel.panic_on_rcu_stall = 1
kernel.softlockup_panic = 1 # если собран детектор
kernel.hardlockup_panic = 1 # если собран детектор
kernel.hung_task_panic = 1 # если собран детектор
kernel.watchdog_thresh = 5 # soft lockup через 10 с — раньше 30-секундного сторожа
kernel.panic_print = 0x47 # при панике: задачи, память, таймеры + бэктрейс всех CPU
Компромисс panic_on_warn: при 1 любое WARN (например, refcount_t: addition on 0) сразу даёт дамп в
pstore, но плата перезагружается и тест обрывается; при 0 WARN только в журнале, а порча памяти
идёт дальше. Для поиска use-after-free — 1, если журнал не сохраняется надёжно.
5. systemd и журнал
- Журнал на диск, без ramlog. На Armbian журнал по умолчанию в RAM (
armbian-ramlog) и сбрасывается на диск раз в сутки — при падении теряется всё. Сделать:ENABLED=falseв/etc/default/armbian-ramlog, и/etc/systemd/journald.conf.d/90-napi-persistent.conf:[Journal] Storage=persistent SyncIntervalSec=10s. Сообщения ядра уровня crit и выше journald пишет на диск сразу. - Аппаратный сторож:
/etc/systemd/system.conf.d/90-watchdog.conf:RuntimeWatchdogSec=30s,RebootWatchdogSec=2min. Плюс pretimeout (п. 1):echo 10 > /sys/class/watchdog/watchdog0/pretimeout, governorpanic. - Чёрный ящик — скрипт, раз в секунду пишущий в файл состояние (IRQ/с, загрузку, память,
потоки шлюза) с
sync -dпосле каждой строки. Показывает, умерла плата мгновенно или что-то нарастало. СPSTORE_PMSGего можно писать и в/dev/pmsg0.