운영체제 따라잡기

I/O 시스템

meellon 2026. 7. 5. 05:00

학습 목표

장치 컨트롤러레지스터·로컬 버퍼가 CPU·메모리와 어떻게 연결되는지 설명할 수 있다.

I/O 소프트웨어 계층(응용 → 시스템 콜 → 커널 I/O → 드라이버)을 설명할 수 있다.

폴링·인터럽트·DMA 방식의 차이와 OS가 왜 DMA를 쓰는지 설명할 수 있다.

블록·문자 장치장치 드라이버 역할을 구분할 수 있다.

문제 상황

  • read() 한 번에 디스크가 4KB를 읽는데 CPU는 다른 프로세스를 돌리고 있다
    • CPU가 섹터마다 바이트를 옮기지 않는 이유는?
  • NIC 패킷이 오면 인터럽트가 수천 번/초 — CPU 부하
    • NAPI, 인터럽트 coalescing이 왜 필요한지
  • USB 키보드와 NVMe SSD가 같은 read/write API인데 내부는 전혀 다르다
    • 드라이버가 장치별 차이를 흡수
  • dmesg드라이버 로드·DMA zone 메시지
    • 커널이 장치를 어떻게 붙이는지

디스크 스케줄링은 헤드 이동 순서였다. 이번엔 OS가 장치 전체를 어떻게 다루는지 — I/O 하드웨어·소프트웨어 스택이다.

1. I/O 하드웨어

CPU·메모리와 디스크·NIC·키보드 같은 장치(device) 는 속도·인터페이스가 다르다. 사이에 장치 컨트롤러(device controller) 가 있다.

구성 역할
장치 실제 물리 동작 — 플래터 회전, 패킷 송수신
컨트롤러 장치 제어 회로 + 레지스터 + 로컬 버퍼
레지스터 상태(status), 명령(command), 데이터(data) — CPU가 MMIO로 접근
버스 주소·데이터·제어선 — PCI, USB, SATA 등
  • CPU는 장치를 직접 돌리지 않고 컨트롤러 레지스터에 명령을 쓴다
  • 컨트롤러가 장치를 구동하고, 데이터는 로컬 버퍼 또는 DMA로 메모리와 주고받는다
  • 포트 I/O vs 메모리 매핑 I/O(MMIO) — x86 레거시 vs 현대 PCI 장치

2. I/O 소프트웨어 계층

응용은 장치 레지스터를 모른다. OS가 계층으로 추상화한다.

계층 역할
사용자 read(), write(), ioctl() 파일·소켓 API
시스템 콜 sys_read 유저 → 커널 전환, 권한 검사
커널 I/O VFS, block layer, socket layer 공통 큐·캐시·스케줄링
장치 드라이버 nvme, e1000, xhci 장치별 명령·인터럽트·DMA 설정
하드웨어 컨트롤러 + 장치 실제 전송
  • 인터럽트 핸들러는 드라이버 안에서 동작 — 완료 비트 확인, 대기 프로세스 깨움
  • 블록 장치(디스크): 고정 크기 블록 단위 — block layer가 요청 병합·스케줄
  • 문자 장치(키보드, 시리얼): 바이트 스트림 — 순차 접근

3. 폴링 · 인터럽트 · DMA

데이터를 옮기는 세 가지 패턴. 앞서 DMA 개요를 봤다면, 여기서는 OS 관점으로 비교한다.

방식 CPU 역할 장점 단점
폴링 완료될 때까지 상태 레지스터 반복 조회 구현 단순 CPU 낭비, 다른 작업 불가
인터럽트 요청 후 다른 일 → 완료 시 IRQ로 깨움 CPU 활용 IRQ 빈번 시 오버헤드
DMA 버퍼 주소·길이만 설정 → 컨트롤러가 메모리↔장치 전송 대용량에 유리 설정·캐시 일관성 관리 필요

전형적 흐름 (DMA + 인터럽트)

  1. 드라이버가 DMA 컨트롤러에 소스·목적지·바이트 수 프로그래밍
  2. CPU는 다른 프로세스 실행 (또는 sleep)
  3. 전송 완료 → 하드웨어 인터럽트 → 드라이버 핸들러가 I/O 완료 표시
  4. read()를 호출했던 프로세스를 ready 로 올려 스케줄
  • PIO(Programmed I/O): CPU가 데이터 레지스터로 바이트 단위 복사 — 소량·레거시
  • 버퍼 캐시 일관성: DMA 전후 dma_map_single 등으로 CPU 캐시와 메모리 동기화

4. 장치 드라이버

드라이버는 커널 모듈(또는 내장)로, 특정 컨트롤러를 다룬다.

개념 설명
초기화 부팅·modprobe 시 레지스터 탐색, IRQ·DMA 채널 할당
open/read/write VFS·block layer가 호출하는 ops 테이블
인터럽트 핸들러 top half: 최소 작업, bottom half: workqueue로 지연 처리
hotplug USB·PCI 장치 삽입 시 udev가 노드(/dev/nvme0n1) 생성
  • Linux /sys, /dev: 장치 노드·드라이버 바인딩 확인
  • 유저 공간 드라이버: 일부 장치는 커널이 최소 인터페이스만 제공하고 데몬이 처리 (예: 일부 프린터 스택)
  • NVMe: 큐 깊이 수천, MSI-X 인터럽트 — 디스크 스케줄링과 맞물림

5. I/O 요청 한 번의 여정

read(fd, buf, 4096) — 블록 장치 예시.

앱 read() → libc → syscall trap
  → VFS가 fd → inode → block device
  → block layer: 페이지 캐시 hit? → 있으면 복사 후 return
  → miss: bio 요청 큐 → I/O 스케줄러(디스크 편) → 드라이버 submit
  → DMA 설정 → 전송 → IRQ → wake process
단계 누가 비고
캐시 hit page cache 디스크 안 감 — 이후 버퍼링 편
큐잉 block layer + elevator 디스크 스케줄링 알고리즘 적용
완료 인터럽트 + 드라이버 iowait 시간에 포함
  • 동기 vs 비동기 I/O: read는 보통 블로킹 — io_uring, aio는 완료를 나중에 통지
  • spurious interrupt, IRQ affinity: 멀티코어에서 NIC·NVMe IRQ를 코어에 묶어 캐시 locality

6. 정리

  • I/O = 컨트롤러 + 레지스터 + 버스 위에서 동작하는 장치
  • OS는 시스템 콜 → VFS/block → 드라이버로 장치 차이를 숨긴다
  • 폴링은 CPU 낭비, 인터럽트로 완료 알림, DMA로 대량 전송
  • 드라이버가 IRQ·DMA·장치 명령을 담당 — 블록/문자 장치 구분
  • 다음: 버퍼링과 캐싱, 페이지 캐시·블록 I/O

다음에 다룰 것

  • 버퍼링과 캐싱
  • 페이지 캐시, 블록 I/O, sync

해당 내용은 Operating System Concepts, 10/E (Avraham Silberschatz, Peter Baer Galvin, Greg Gagne) 의 내용을 기반으로 합니다.

'운영체제 따라잡기' 카테고리의 다른 글

보호와 보안  (0) 2026.07.07
버퍼링과 캐싱  (0) 2026.07.06
디스크 스케줄링  (0) 2026.07.04
파일 시스템 개념  (0) 2026.07.03
세그멘테이션과 군집화  (0) 2026.07.02