Ошибки PCIe (Peripheral Component Interconnect Express) неизбежны в любом масштабном развертывании: глюки питания, перегрев, дефекты кабелей, радиационные сбои и ошибки протокола приводят к повреждению TLP (Transaction Layer Packets) или DLLP (Data Link Layer Packets). Архитектура PCIe предусматривает многоуровневую систему обнаружения и восстановления, но её поведение по умолчанию в Linux не всегда оптимально для продакшн-нагрузок. Понимание механизмов восстановления позволяет снизить время недоступности устройств от минут до миллисекунд и предотвратить каскадные сбои.
Разберём иерархию ошибок PCIe, механизмы AER (Advanced Error Reporting), политики восстановления ядра, настройку DPC (Downstream Port Containment) и практические приёмы операций.
Иерархия ошибок PCIe и их классификация
PCIe определяет три уровня ошибок с разной семантикой и стратегиями восстановления:
Correctable Errors (исправимые ошибки)
Ошибки, которые протокол исправляет самостоятельно без вмешательства ПО: ошибки CRC в TLP/DLLP, ошибки sequencing (неправильный номер последовательности), таймауты повторной передачи (replay timer timeout). Аппаратное обеспечение повторно передает поврежденные пакеты, приложение об ошибке даже не узнает. Счётчики таких ошибок накапливаются в регистрах устройства и доступны через lspci -vvv (Advanced Error Reporting Capability). Постоянный рост счётчиков correctable errors - признак деградации физического канала (плохой контакт, изношенный кабель, перегрев), требующего планового обслуживания. Важно понимать, что correctable errors не безвредны: их накопление сигнализирует о физической деградации связи, и если не реагировать на рост счётчиков вовремя, неизбежно следует uncorrectable error, который уже требует вмешательства.
Uncorrectable Non-Fatal Errors (неисправимые нефатальные ошибки)
Ошибки, которые протокол не может исправить сам, но не требуют сброса линка: ошибки ECRC (End-to-End CRC) в TLP, ошибки poisoned TLP (явно помеченных как поврежденных), completion timeout (ожидание ответа превысило таймаут), unexpected completion (ответ без запроса), receiver overflow (переполнение буфера приёмника), flow control error. Эти ошибки сообщаются драйверу через AER interrupt, драйвер может попытаться восстановить транзакцию (повторный запрос, сброс completion) или перевести устройство в безопасное состояние без полного сброса. Такие ошибки часто возникают при перегрузке шины или временных сбоях питания, и грамотная реакция драйвера позволяет продолжить работу без видимого для приложения сбоя.
Uncorrectable Fatal Errors (неисправимые фатальные ошибки)
Ошибки, требующие полного сброса линка (link reset) или даже горячего сброса (hot reset): training sequence error (ошибка обучения линка), DL protocol error (ошибка протокола Data Link Layer), surprise down (неожиданное отключение), data parity error (ошибка контроля чётности данных). После таких ошибок линк падает в состояние Detect, драйвер инициирует полную переинициализацию (link retrain), устройство временно исчезает из системы, все очереди сбрасываются, приложение получает ошибки ввода-вывода. Это самый тяжёлый класс ошибок, после которого без грамотной политики восстановления система может остаться в нерабочем состоянии на секунды или минуты.
AER (Advanced Error Reporting) в Linux
AER - стандартный механизм отчётности об ошибках PCIe в Linux. Ядро предоставляет инфраструктуру drivers/pci/pcie/aer.c, которая:
- Регистрирует обработчик прерываний AER для каждого Root Complex / Switch / Endpoint.
- При возникновении ошибки оборудование генерирует AER interrupt, ядро считывает регистры статуса ошибки (Uncorrectable Error Status, Correctable Error Status), маскирует повторные прерывания по той же ошибке (во избежание шторма прерываний).
- Вызывает callbacks драйверов устройств (
pci_driver->err_handler), позволяя драйверам устройств (nvme, mlx5, nvidia, amdgpu) инициировать восстановление на уровне устройства. - Логирует событие в
dmesg/journalctlс детализацией: тип ошибки, устройство (BDF), severity, registers dump.
Политики восстановления ядра
По умолчанию ядро использует консервативную политику: при любой uncorrectable ошибке инициируется полный сброс устройства (reset). Это безопасно, но долго - секунды до десятков секунд недоступности. Начиная с ядра 4.10+ доступны более тонкие политики через sysfs:
/sys/bus/pci/devices/<BDF>/aer_policy
Значения: reset (полный сброс, дефолт), reset_link (сброс только линка, быстрее), reset_device (сброс устройства через FLR/Function Level Reset), none (нет автоматического восстановления, драйвер сам решает).
Для NVMe-накопителей рекомендуется reset_device (FLR), который сохраняет состояние контроллера и не требует полной переинициализации линка. Для GPU (NVIDIA, AMD) - reset_device или none с ручным восстановлением через драйвер (nvidia/amdgpu умеют восстанавливать контекст без полного сброса).
DPC (Downstream Port Containment) и изоляция ошибок
DPC - механизм аппаратной изоляции ошибок на уровне Switch/Root Port. Если устройство за пределами DPC-домена генерирует uncorrectable fatal ошибку, аппаратное обеспечение изолирует только этот порт (Downstream Port), не сбрасывая весь линк и не затрагивая другие устройства за тем же Switch. В Linux DPC включён по умолчанию на поддерживаемом железе (Intel Skylake+, AMD Zen2+). Статус DPC:
cat /sys/bus/pci/devices/<BDF>/dpc_status
Для продакшн-кластеров критически важно, чтобы Switch/Root Port поддерживал DPC и он был включён в BIOS/UEFI. Без DPC одна неисправимая ошибка на одном NVMe сбрасывает весь линк Switch'а, отключая все NVMe за ним на время переобучения (link retrain).
Настройка таймаутов и масок ошибок
Completion Timeout
Время, в течение которого Requester ждёт Completion от Completer. По умолчанию 16-55 мс (зависит от реализации). Для долгих операций (GPU kernel, NVMe admin commands) таймаут может истечь ложно. Настройка через Extended Capability:
# Увеличить completion timeout до 1-4 секунд
setpci -s <BDF> CAP_EXP+0xC.w=0x3F # 16-55 ms -> 1-4 sec (значения зависят от кодировки)
Для GPU-компьютинга (kernel длительностью секунды) и NVMe admin commands (format, firmware update) рекомендуется ставить максимум.
ECRC (End-to-End CRC)
Проверка целостности TLP от отправителя до получателя. По умолчанию часто отключена для производительности. Включение:
# Включить генерацию и проверку ECRC
setpci -s <BDF> CAP_EXP+0xC.w=0xXXXX # бит ECRC Generation Enable / ECRC Check Enable
Для продакшн-кластеров с длинными кабелями и высокой нагрузкой ECRC рекомендуется включить на всех устройствах, поддерживающих эту фичу.
Error Masking
Маскировка отдельных типов ошибок от генерации AER interrupt:
# Замаскировать correctable errors (чтобы не спамить dmesg)
echo 1 > /sys/bus/pci/devices/<BDF>/aer_correctable_mask
Не рекомендуется маскировать uncorrectable errors - это скрывает проблемы до каскадного сбоя.
Восстановление на уровне драйверов устройств
NVMe
NVMe-драйвер в ядре (drivers/nvme/host/pcie.c) реализует err_handler:
- При correctable error - увеличивает счётчик, продолжает работу.
- При uncorrectable non-fatal - пытается повторно отправить команду (retry), если команда idempotent (read, flush). Для write - возвращает ошибку приложению (EIO).
- При fatal error - инициирует controller reset через NVMe Admin Command (Controller Reset), затем переинициализирует очереди, восстанавливает namespace'ы.
NVMe 2.0 добавляет Persistent Event Log и Controller Reset с сохранением namespace'ов, что ускоряет восстановление.
GPU (NVIDIA / AMD)
GPU-драйверы (nvidia.ko, amdgpu.ko) реализуют сложную логику восстановления контекста:
- NVIDIA: при uncorrectable error сбрасывает только зависший контекст (CUDA context), остальные контексты продолжают работать. Поддерживает
nvidia-smi -r(GPU reset) без перезагрузки. - AMD:
amdgpu_device_gpu_recoverпытается восстановить только зависшие IP-блоки (GFX, SDMA, UVM) без полного сброса GPU.
Оба драйвера поддерживают reset_device политику AER.
Сетевые адаптеры (mlx5, ice, iavf)
Mellanox mlx5: при ошибке сбрасывает только зависшую QP (Queue Pair) через FW recovery, остальные QP продолжают работать. Поддерживает reset_device (FLR).
Intel Ice/Iavf: сброс VF через PF (Physical Function), VF получает reset notification и переинициализирует очереди.
Практический порядок настройки и чек-лист готовности
Полный цикл подготовки кластера к PCIe ошибкам сводится к шести ключевым действиям:
- Включить DPC в BIOS/UEFI (обязательно для кластеров с Switch) и проверить его статус через
cat /sys/bus/pci/devices/<BDF>/dpc_status. Убедиться, что все Root Ports и Switch Ports поддерживают DPC и режим containment активен - это единственный способ локализовать фатальную ошибку одним портом.
- Настроить
aer_policy=reset_deviceдля всех NVMe и GPU через sysfs (/sys/bus/pci/devices/<BDF>/aer_policy). Для NVMe это даст FLR с сохранением namespace'ов, для GPU - сброс только зависшего контекста без перезагрузки всего устройства. Проверить применение политики черезcat /sys/bus/pci/devices/<BDF>/aer_policy.
- Увеличить completion timeout для GPU/ML до 1-4 секунд через
setpci -s <BDF> CAP_EXP+0xC.w=0x3F. Для GPU kernel'ов длительностью секунды и NVMe admin commands (format, firmware update) дефолтные 16-55 мс недостаточны - выставляйте максимум. Проверить применение черезsetpci -s <BDF> CAP_EXP+0xC.w.
- Включить ECRC на всех устройствах кластера, поддерживающих эту фичу:
setpci -s <BDF> CAP_EXP+0xC.w=0xXXXX(биты ECRC Generation Enable и ECRC Check Enable). Для продакшн-кластеров с длинными кабелями и высокой нагрузкой ECRC обязателен - отключение ради производительности ведёт к silent data corruption в ML-пайплайне.
- Настроить systemd-юниты сервисов на автоматический рестарт при ошибках ввода-вывода (
Restart=on-failure,RestartSec=5) и настроить мониторинг счётчиков AER черезnode_exporterс--collector.pci. Настроить алерты: рост correctable errors > 1000/мин - плановое обслуживание; uncorrectable non-fatal > 0 - расследование; fatal > 0 - инцидент.
- Провести плановые проверки кабелей и портов при росте correctable errors, настроить автовосстановление сервисов (
Restart=on-failure), включить ECRC на всех устройствах, проверитьaer_policy=reset_deviceдля NVMe/GPU, увеличить completion timeout до 1-4 сек, включить DPC в BIOS/UEFI, настроить алерты в Prometheus/Grafana по счётчикам AER.
Типичные ошибки эксплуатации
- Игнорирование роста correctable errors до критического уровня - кабель выходит из строя в пиковую нагрузку.
- Отключение ECRC для производительности - скрытые повреждения данных в ML-пайплайне (silent data corruption).
- Политика
resetдля всех устройств - каскадные сбросы GPU при ошибке на одном NVMe. - Отключение DPC в BIOS - каскадные сбросы всего Switch'а при ошибке на одном порту.
Чек-лист готовности к PCIe ошибкам
- DPC включён в BIOS/UEFI и виден в
dpc_status. aer_policy=reset_deviceдля всех NVMe/GPU.- Completion timeout >= 1 сек для GPU/ML.
- ECRC включено на всех устройствах.
- DPC включён в BIOS/UEFI.
- Мониторинг счётчиков AER в Prometheus/Grafana.
- Скрипты автовосстановления сервисов при I/O ошибках (
Restart=on-failure). - Плановые проверки кабелей/порт при росте correctable errors.
Заключение по восстановлению PCIe
Ошибки PCIe неизбежны, но их влияние на доступность можно свести к минимуму: правильная настройка AER политик, включение DPC, включение ECRC, увеличение completion timeout для долгих операций и грамотное восстановление на уровне драйверов позволяют ограничить влияние ошибки одним устройством и миллисекундами времени восстановления. Инвестиция в настройку этих параметров на этапе проектирования кластера окупается первым предотвращённым каскадным сбоем.