← Work

Case study

다중 카메라 7시간 뒤 죽는 보드 — VI5 캡처 경로 커널 디버깅

2026 · Autonomous Computing Platform based on NVIDIA Jetson

요약

JetPack 5.1.6(L4T R35.6.4) 기반 커스텀 보드에서 GMSL 카메라 5대를 장시간 스트리밍하면 약 7시간 뒤 캡처가 죽고, 커널 스레드가 CPU를 다 먹다가 워치독 리부트로 이어지는 문제. vendor 커널의 VI5 캡처 경로까지 내려가 두 개의 커널 결함(무한 스핀, DMA 누수) 을 찾아 패치했고, 현장 보드에 플래시 없이 배포하는 도구까지 만들어 마무리했다.

증상

다중 카메라 장시간 스트리밍 중 단계적으로 악화:

  1. uncorr_err: request timed out after 2500 ms — 에러 복구(err_rec) 사이클 반복
  2. 몇 시간 뒤 vi capture setup failed + fatal: error recovery failed
  3. 이후 vi-output 커널 스레드가 코어당 100% CPU 점유 (카메라 수만큼 누적)
  4. 이 상태에서 앱을 종료하면 보드 하드락 → CCPLEX 워치독(120초)이 강제 리부트

실측: 5캠 FHD@30 스트리밍 약 7시간 후 fatal, 3개 코어 99.9%, load ~11. 한 번의 부팅에서 err_rec 사이클 15,268회 기록.

원인 추적

결함 1 — 에러 상태를 모르는 대기 조건 (무한 스핀)

fatal: error recovery failed 시 dequeue 커널 스레드는 종료되는데, capture_stateCAPTURE_ERROR로 남는다. 문제는 enqueue 스레드의 대기 조건이 “큐에 버퍼가 있는가”뿐이라는 것. 버퍼가 있으니 즉시 깨어나고, 에러 상태라 버퍼를 소비하지 못한 채 다시 대기 — 무한 스핀.

NVIDIA 포럼(244257, 233703)에서 인정만 되고 수정되지 않은 버그였다. 대기 조건에 capture_state != CAPTURE_ERROR를 추가하는 자체 패치로 차단.

결함 2 — 에러 복구가 반복될수록 새는 DMA (fatal의 원인)

capture_setup()이 캡처 request 링을 dma_alloc_coherent로 할당하는데 해제 경로가 없다. 에러 복구가 setup을 재진입하는 구조라서 err_rec 사이클마다 링이 하나씩 누수 — 수천 사이클 뒤 할당 실패가 곧 fatal이었다.

NVIDIA가 뒤늦게 공개한 공식 패치(포럼 310963)를 R35.6.4에 맞게 각색하고, 공식판에 없는 복구 재진입 시 이전 링 해제 가드를 추가했다. 포럼의 나머지 공식 패치 3건은 R35.6.4에 이미 동등 반영된 것을 확인하고 제외 — 필요한 것만 넣었다.

검증

같은 보드에서 패치 전/후 soak 테스트:

항목 패치 전 패치 후
5캠 FHD@30 장시간 스트리밍 ~7시간 후 fatal → 스핀 → 워치독 리부트 66시간 무사고
fatal / err_rec 횟수 발생 / 15,268회 0 / 0
에러 사이클 중 vi-output CPU 코어당 100% 합계 0.7~1.8%
err_rec 19회 강제 유도 사이클당 DMA 링 누수 CmaFree 변동 0 · 잔존 스레드 0

에러를 일부러 19회 유도해서 DMA 메모리 잔량(CmaFree)에 변동이 없는 것까지 확인했다.

플래시 없는 현장 배포

이미 나가 있는 보드들에 recovery 모드 플래시를 요구할 수 없어서, /boot/Image 한 파일만 교체하는 self-contained field patch 도구를 만들었다:

같은 프로젝트에서 함께 잡은 것들

vendor 커널의 에러 복구 경로는 복구가 수천 번 반복되는 상황까지는 검증돼 있지 않은 경우가 많다. 이번 건도 증상(스핀)과 원인(누수)이 서로 다른 위치에 있어서, 두 쪽을 모두 수정한 뒤에야 해결됐다.