From 0a45e0536c6b53a3bdde4be1624f0117108bc7e0 Mon Sep 17 00:00:00 2001 From: kaffa Date: Tue, 5 May 2026 11:47:31 +0900 Subject: [PATCH] =?UTF-8?q?AMD-Vi=20(IOMMU)=20Completion-Wait=20timeout=20?= =?UTF-8?q?=EB=A9=94=EC=BB=A4=EB=8B=88=EC=A6=98=20=EC=A0=95=EB=B3=B8=20?= =?UTF-8?q?=EC=8B=A0=EC=84=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit incus-kr2 freeze 사건 분석으로 확정된 IOMMU 부분 hang 메커니즘과 운영 규칙(`iommu=pt` 선제 적용)을 별도 reference 문서로 분리. 호스트 사연(history)과 메커니즘(reference)을 분리해 다른 AMD Ryzen 호스트 도입 시 재사용 가능한 정본으로 정리. - infra/compute/amd-vi-iommu.md 신규 (메커니즘 + 차단 + 운영 규칙) - compute _index.md, hosts/incus-kr2.md, history 문서에 링크 --- history/2026-05-04-amd-iommu-freeze.md | 1 + infra/compute/_index.md | 3 +- infra/compute/amd-vi-iommu.md | 132 +++++++++++++++++++++++++ infra/compute/hosts/incus-kr2.md | 14 +-- 4 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 infra/compute/amd-vi-iommu.md diff --git a/history/2026-05-04-amd-iommu-freeze.md b/history/2026-05-04-amd-iommu-freeze.md index ae6af46..5deb7aa 100644 --- a/history/2026-05-04-amd-iommu-freeze.md +++ b/history/2026-05-04-amd-iommu-freeze.md @@ -84,6 +84,7 @@ ro usbcore.autosuspend=-1 quiet iommu=pt ## 관련 문서 +- [[amd-vi-iommu]] — AMD-Vi 부분 hang 메커니즘 정본 (왜 일부 프로세스만 죽는가, `iommu=pt`가 왜 해결하는가) - [[infra/compute/hosts/incus-kr2|incus-kr2]] - [[2026-04-04-usb-25g-hang]] — 직전 freeze (USB) - [[infra/compute/infra-hosts]] diff --git a/infra/compute/_index.md b/infra/compute/_index.md index f0d8b85..58abfb6 100644 --- a/infra/compute/_index.md +++ b/infra/compute/_index.md @@ -1,6 +1,6 @@ --- title: compute 인덱스 -updated: 2026-04-16 +updated: 2026-05-05 tags: [moc, compute] --- @@ -9,5 +9,6 @@ tags: [moc, compute] | 문서 | 설명 | |------|------| | [[infra-hosts]] | 인프라 호스트 및 네트워크 (SSH 접속, Incus, Tailscale) | +| [[amd-vi-iommu]] | AMD-Vi (IOMMU) Completion-Wait timeout 부분 hang 메커니즘과 차단 (`iommu=pt`) | | [[k3s-migration]] | K3s PostgreSQL 백엔드 이전 기록 | | [[zlambda]] | zlambda Linode 도쿄 NixOS VM | diff --git a/infra/compute/amd-vi-iommu.md b/infra/compute/amd-vi-iommu.md new file mode 100644 index 0000000..77738ce --- /dev/null +++ b/infra/compute/amd-vi-iommu.md @@ -0,0 +1,132 @@ +--- +title: AMD-Vi (IOMMU) Completion-Wait timeout — 부분 hang 메커니즘과 차단 +updated: 2026-05-05 +tags: [infra, kernel, iommu, amd, freeze, troubleshooting] +--- + +## 개요 + +AMD Ryzen 호스트에서 발생하는 IOMMU(AMD-Vi) Completion-Wait timeout으로 인한 호스트 부분 hang 패턴 정본. 처음 만난 사례는 [[2026-05-04-amd-iommu-freeze]] (incus-kr2, Ryzen 9 6900HX). AMD Ryzen 베어메탈을 신규 도입할 때마다 선제 차단(`iommu=pt`)할 것. + +## IOMMU(AMD-Vi)가 하는 일 + +PCIe/USB 디바이스가 메모리에 DMA 할 때 **"디바이스가 보는 주소(IOVA) → 실제 물리 메모리(PA)"** 변환 수행. + +- 보안: 디바이스가 임의 메모리 접근 못 하게 격리 (e.g. 악성 USB가 RAM 덤프 못 함) +- 가상화: VFIO passthrough, SR-IOV에 필수 +- AMD에서는 `AMD-Vi`, Intel에서는 `Intel VT-d`라 부름. 동일 개념 + +## 정상 동작 + +``` +1. OS가 페이지 매핑을 바꿀 때마다 IOMMU에 invalidation 명령 전송 + → IOMMU 내부 캐시(IOTLB)를 비우라고 +2. 명령은 IOMMU의 Command Queue에 쌓임 +3. 끝에 Completion-Wait 명령으로 "여기까지 다 처리됐는지 알려줘" sync +4. OS는 이 응답을 기다림 (1초 내) +``` + +## 펌웨어 버그 발현 시 흐름 + +1. 어떤 조건에서 펌웨어/HW가 Completion-Wait 응답을 못 보냄 +2. Linux가 1초 후 타임아웃 → `dmesg`에 `AMD-Vi: Completion-Wait loop timed out` 출력 +3. **타임아웃이 나면 큐 상태가 inconsistent해져 다음 invalidation도 같은 큐에서 stuck** +4. 새 IO나 새 매핑이 필요한 모든 작업이 IOMMU 응답 대기로 hang +5. 누적될수록 hang하는 작업 범위가 넓어져 결국 호스트 사용자공간 대부분이 부분 hang + +## 부분 hang의 특이 패턴 — "왜 일부만 죽는가" + +| 영향 받는 작업 | 영향 안 받는 작업 | +|---|---| +| 새 fork (페이지 매핑) | 이미 메모리에 매핑된 프로세스 (예: nginx, node-exporter) | +| 디스크 쓰기 (NVMe DMA 셋업) | ICMP (커널 raw socket, 이미 셋업된 NIC ring buffer) | +| 새 컨테이너 시작 | LXC 컨테이너 내부에서 이미 떠 있는 서비스 | +| sshd login (utmp/journal 쓰기) | 이미 열려있는 SSH 세션 | +| containerd / incus 데몬의 신규 작업 | 라우팅·NAT처럼 커널이 자체 처리하는 트래픽 | + +→ 외부에서 보면 "ICMP 응답 OK, nginx 응답 OK, 그런데 SSH banner 직후 끊기고 K3s NotReady"라는 미스터리한 부분 hang. 동시에 OOM/디스크/NIC가 모두 멀쩡 (메트릭상 정상). [[2026-05-04-amd-iommu-freeze]] 참조. + +## 영향 받는 하드웨어 / 트리거 조건 + +- **AMD Ryzen 6000 시리즈 (Rembrandt, Zen 3+)** — 알려진 펌웨어 이슈, 다수 보고 (Linux 메일링리스트, AMD 포럼) +- **AMD Ryzen Mobile / 미니 PC** — BIOS AGESA 업데이트가 늦거나 안 되는 환경에서 더 자주 발현 +- 일부 Intel 플랫폼(VT-d)에서도 비슷한 패턴 보고 있으나 본 정본은 AMD 한정 + +트리거되는 일반 조건: +- DMA 자주 쓰는 디바이스 (NVMe, USB 컨트롤러, 10G NIC) 다수 동시 동작 +- VFIO/가상화 + LXC/Docker 같은 컨테이너 동시 동작 +- 부팅 후 일정 시간 (사례에서는 24분) 후 첫 timeout, 이후 누적 + +## 진단 신호 + +```bash +# 1차 확인 — Completion-Wait timeout 발생 여부 +sudo dmesg -T | grep -iE "AMD-Vi.*Completion-Wait|AMD-Vi.*timed out" + +# 부분 hang 의심 시 부수 증거 +ssh 'echo ok' # banner 직후 끊기면 의심 +kubectl get nodes # NotReady, container runtime is down +node_procs_blocked # 0이어도 안전 신호 아님 (IOMMU hang은 D-state 안 거침) +node_memory_* # 정상이어도 안전 신호 아님 +``` + +**핵심 함정**: `node_procs_blocked = 0`, `MemoryPressure = False`, `DiskPressure = False` 다 정상이어도 hang 가능. IOMMU layer는 OS가 노출하는 압박 메트릭에 안 잡힘. **메트릭 정상 + 외부 ICMP 응답 + 새 SSH 거부 조합이면 IOMMU 의심.** + +## 차단 옵션 + +### 1. `iommu=pt` (권장 — Passthrough 모드) + +GRUB cmdline에 추가: + +```bash +sudo cp /etc/default/grub /etc/default/grub.bak.$(date +%Y%m%d)-iommu +sudo sed -i -E 's/^(GRUB_CMDLINE_LINUX_DEFAULT="[^"]*)(")/\1 iommu=pt\2/' /etc/default/grub +sudo update-grub +sudo systemctl reboot +``` + +검증: + +```bash +cat /proc/cmdline | grep iommu=pt +sudo dmesg | grep "iommu: Default domain type" +# 기대: "iommu: Default domain type: Passthrough (set via kernel command line)" +``` + +**왜 해결되는가**: `pt` 모드는 **호스트 자신의 DMA에 대해 IOMMU 변환을 1:1 mapping으로 고정** → invalidation 거의 안 씀 → Completion-Wait 자체가 발생하지 않음 → 펌웨어 버그 트리거 안 됨. VFIO/SR-IOV 가상화는 여전히 IOMMU 사용 가능 (격리 유지). 트레이드오프는 호스트 자체 DMA 격리가 약해지는 것 — 베어메탈 + 알려진 디바이스 환경에서는 보통 수용 가능한 비용. + +### 2. `amd_iommu=off` (차선) + +IOMMU 자체를 비활성. VFIO passthrough 못 함, SEV/Confidential Computing 못 함. 가상화 안 쓰는 호스트면 가능하나 기본 권장 X. + +### 3. BIOS AGESA 업데이트 (장기 대책) + +펌웨어 fix가 들어간 AGESA 마이크로코드로 업데이트. Mini PC 제조사가 BIOS를 늦게 내거나 안 내면 불가능. 가능할 때 적용. + +### 4. 커널 업그레이드 + +Linux 6.13+에서 일부 우회 패치 머지된 사례 있음. 효과는 트리거 조건에 따라 다름. `iommu=pt`로 먼저 차단하고 부수적으로 검토. + +## 운영 규칙 (kappa 인프라) + +1. **AMD Ryzen 베어메탈 신규 도입 시 처음부터 GRUB cmdline에 `iommu=pt` 박을 것.** 사고 경험한 다음 적용은 늦음 — 첫 freeze까지 평균 2주 간격. +2. 호스트 문서(`infra/compute/hosts/.md`)의 GRUB 섹션에 `iommu=pt` 표시. +3. 기존 호스트 점검: `ssh 'cat /proc/cmdline'` 해서 `iommu=pt` 없으면 다음 정기 재부팅 시 추가. +4. 시간대 `Asia/Seoul` 강제. 잘못된 timezone(예: PDT)은 dmesg 분석 시 시간 변환 오류로 잘못된 결론 유도 ([[2026-05-04-amd-iommu-freeze]] 헤임달 1차 진단 오판 사례). +5. AMD Ryzen 호스트는 OOB 전원 제어(Tapo 또는 IPMI) 필수. 펌웨어 hang은 OS shutdown으로 못 풀고 강제 전원 차단만 가능. + +## 현재 적용 호스트 상태 + +| 호스트 | CPU | iommu=pt | 비고 | +|---|---|---|---| +| [[incus-kr2]] | AMD Ryzen 9 6900HX | ✓ (2026-05-04) | 본 사건 진원지 | +| [[incus-kr1]] | unknown | — | 점검 필요 | +| [[incus-hp1]] | Intel Xeon E5-2670 | N/A | Intel, AMD-Vi 무관 | +| [[incus-hp2]] | Intel Xeon E5-2670 | N/A | Intel, AMD-Vi 무관 | + +## 참조 + +- [[2026-05-04-amd-iommu-freeze]] — 진단 + 조치 사연 +- [[infra-hosts]] — 인프라 호스트 정본 +- Linux kernel: `drivers/iommu/amd/iommu.c` — `__domain_flush_pages`, `iommu_completion_wait` +- AMD I/O Virtualization Technology Specification (IOMMU) diff --git a/infra/compute/hosts/incus-kr2.md b/infra/compute/hosts/incus-kr2.md index 1503713..ff03ef5 100644 --- a/infra/compute/hosts/incus-kr2.md +++ b/infra/compute/hosts/incus-kr2.md @@ -1,6 +1,6 @@ --- title: incus-kr2 -updated: 2026-05-04 +updated: 2026-05-05 tags: [infra, host, incus, k3s, seoul, amd, iommu] type: host host_kind: server @@ -39,17 +39,9 @@ Incus + K3s control-plane 호스트 (서울존). Mini PC 폼팩터, AMD Ryzen 9 ## 알려진 hang 패턴 — AMD-Vi (IOMMU) Completion-Wait Timeout -호스트 freeze가 반복 발생한 근본 원인 (2026-05-04 확정, [[2026-05-04-amd-iommu-freeze]]). +호스트 freeze 반복의 근본 원인. 메커니즘 정본은 [[amd-vi-iommu]], 사건 사연은 [[2026-05-04-amd-iommu-freeze]]. -**증상**: -- ICMP/이미 매핑된 프로세스(node-exporter, LXC 컨테이너 nginx)는 응답 유지 -- containerd, incus 데몬, sshd 새 세션 fork만 동시에 hang -- kubelet `container runtime is down`, `/var/log/pods readdirent: input/output error` -- procs_blocked 0, MemoryPressure False — 자원 고갈 아님 - -**원인**: AMD Ryzen 6900HX IOMMU(AMD-Vi) Completion-Wait queue stall. `dmesg`에 `AMD-Vi: Completion-Wait loop timed out` 반복 후 누적되어 DMA 의존 디바이스(NVMe, USB 컨트롤러 등)가 stall. - -**조치 (2026-05-04 적용)**: GRUB cmdline `iommu=pt` 추가 → IOMMU passthrough 모드. dmesg `iommu: Default domain type: Passthrough` 확인. +요약: AMD Ryzen 6900HX IOMMU의 Completion-Wait queue가 stall되면서 DMA 의존 디바이스(NVMe, USB 컨트롤러 등)가 멈춤 → containerd/incus/sshd login만 죽고 ICMP/이미 매핑된 프로세스(nginx, node-exporter)는 살아남는 부분 hang. 조치: GRUB cmdline `iommu=pt` 추가 (2026-05-04 적용, 17시간 timeout 0건 검증). **과거 freeze 이력 비교**: | 일자 | 원인 | 조치 |