2015년 6월 30일 화요일

[리눅스 커널] 리눅스 커널의 블록 디바이스 I/O 과정

리눅스 커널의 블록 디바이스 I/O 과정의 기본적인 흐름



사용자 프로세스 -> 표준 C 라이브러리 -> 시스템콜 인터페이스 -> 가상파일시스템 -> ext4 파일시스템 -> 블록 디바이스 드라이버 -> 블록 디바이스(디스크)

블록 디바이스 -> (인터럽트) -> 블록 디바이스 드라이버 -> ext4 파일시스템 -> ... 역순

1. 사용자 프로세스는 실행 도중 파일을 읽기 위해 fread()라는 표준 C 라이브러리 함수를 호출
2. 이 함수는 read() 시스템콜로 구현되어 있으므로 read() 시스템콜을 호출, 커널에 파일 읽기 동작을 요청
3. 소프트웨어 인터럽트(=시스템콜)가 발생해 커널에 진입하면 호출한 시스템콜 번호에 따라 해당 시스템콜 종류를 판별, 현재는 read() 시스템콜이므로 리눅스 커널의 가상 파일 시스템(Virtual File System, VFS)에 파일(디스크) 읽기 요청을 하게 된다.
4. VFS가 ext4 파일시스템에게 읽기 동작을 요청
5. ext4 파일시스템의 read() operation은 파일시스템 관련 처리를 한 뒤 블록 디바이스 드라이버에 읽기 요청
6. 읽기 요청 받은 블록 디바이스 드라이버는 읽을 파일에 해당하는 블록 디바이스의 블록 단위 데이터를 메모리로 읽어오려고 하드웨어를 제어. 따라서 현재 프로세스는 블록 디바이스의 I/O 동작을 완료하기 전까지 sleep하게 됨. 즉 현재 프로세스 상태를 대기 상태(wait state)로 변경하고 스케줄러를 호출해 다른 프로세스를 실행함
7. 하드디스크가 읽기 요청을 받으면 메모리에 있는 리눅스 커널의 캐시 영역에 요청받은 데이터를 전송. 블록 I/O 연산은 대부분 DMA로 이루어짐.
8. 데이터 전송 완료하면 인터럽트 발생시켜 디바이스 드라이버에게 읽기 동작이 끝났음을 알려줌
9. 디바이스 드라이버에 등록된 인터럽트 핸들러 실행
10. 인터럽트 핸들러가 읽기 동작을 완료하면 대기하던 프로세스가 깨어나 실행상태(Running state)로 변경됨.
11. 블록 디바이스에서 읽은 파일 데이터는 현재 커널 영역에 있으므로, 사용자영역에서 접근할 수 없음. 그래서 커널 영역에서 사용자 영역의 표준 C 라이브러리 버퍼로 데이터를 복사해야 함. 사용자 영역으로 데이터 복사를 완료하면 커널의 read() 시스템콜 처리가 모두 끝났으므로 프로세스를 사용자 영역으로 전환함
12. 표준 C 라이브러리는 사용자 프로세스가 요청한 버퍼에 데이터를 복사함으로써 fread() 함수 처리를 끝내게 됨.



가상화 환경은 어떻게 다를까?
1. 전가상화 환경: 모든 단계가 동일하며 단지 블록 디바이스가 에뮬레이션한 가상의 블록 디바이스가 될 뿐임 -> IOMMU나 SR-IOV 등의 하드웨어 지원 가상화 기능을 사용하면 가상 머신이 디바이스에 직접 접근할 수도 있음.
2. 반가상화 환경: 블록 디바이스 드라이버에서 블록 디바이스에 접근하는 과정과 메커니즘이 다름.  (DomU 프론트엔드 드라이버 -> Dom0 백엔드 드라이버 -> Dom0 블록 디바이스 드라이버)


Reference
[1] Xen으로 배우는 가상화 기술의 이해, I/O 가상화. 한빛미디어(2014)