[리눅스 커널 내부구조] Chapter 08 - 디바이스 드라이버

gom·2024년 4월 24일
post-thumbnail

1. 디바이스 드라이버 일반

파일

  • 유닉스 계열 시스템에서 모든 것은 파일로 취급
  • 정규파일 : 디스크에 저장되어 있는 파일
  • 장치파일 : 장치를 가리키는 파일 (키보드, 마우스 등등)

사용자 태스크 관점에서의 디바이스 드라이버

  • VFS 가 제공하는 파일 객체 = 사용자 태스크가 접근하는 장치 파일
  • 사용자 태스크가 구조체에 정의되어 있는 함수를 통해 장치파일에 접근 할 때 호출할 함수를 정의하고 구현해 주는 것
  • 각 디바이스 드라이버에게 주 번호 지정
    • 리눅스는 시스템에 존재하는 여러 개의 디바이스 드라이버를 구분하기 위한 고유한 번호
    • 4096개의 주 번호 지원
  • 각 장치는 자신을 나타내는 장치 파일을 가짐
  • 장치 파일을 관리하는 아이노드 객체에 주 번호가 기록됨
    • 주 번호(12bit)과 부 번호(20bit) 기록

      ** 부 번호 : 같은 디바이스 드라이버를 사용하는 장치가 복수 개 있을 때 이들을 서로 구분하기 위해 사용

      ** 장치 파일 : 사용자 태스크에게 디바이스 드라이버 내부 함수를 호출 할 수 있는 진입점(entry point) 제공

  • 디바이스 드라이버를 선택하는 것은 주 번호를 통해서만 이뤄짐
  • 종류
    • 문자 디바이스 드라이버 : read(), write()함수와 1:1로 매칭되어 디바이스 드라이버 함수 호출
    • 블록 디바이스 드라이버 : 큐를 통해 ‘페이지캐시’와 통신
    • 네트워크 디바이스 드라이버

개발자 입장에서 디바이스 드라이버

  • 디바이스 드라이버
    • 하드웨어로써 존재하는 디바이스를 구동시키기 위한 소프트웨어

    • 어느 운영체제이건, 운영체제가 없는 환경에서도 동작되어야 함

      디바이스 드라이버 작성 시 디바이스를 구동시키기 위해 필요한 ‘하드웨어와 밀접한 코드’ 와 ‘운영체제와 관련된 코드’를 분리하는 것이 바람직함

  • 리눅스 디바이스 드라이버 구성
    • 디바이스 드라이버 코어
      • 특정 하드웨어를 위한 것
      • 하드웨어 매뉴얼을 참조하여 해당 하드웨어의 특성에 맞도록 작성
    • 래퍼 (wrapper)
      • 코어를 리눅스에서 사용가능한 형태로 만들어주기 위한 것
      • 작성된 코어를 커널에 등록시킨 후 사용자 태스크가 호출할 함수들과 코어의 함수를 연결

리눅스 디바이스 드라이버 관리 구조

  • 사용자 태스크
    • 시스템 호출을 통해 장치 파일에 접근

    • 호출 가능한 함수는 파일 오퍼레이션 구조체에 정의 되어 있음

      → 일관된 구조를 가질 수 있음

  • 디바이스 드라이버 개발자
    • 파일 오퍼레이션 구조체에 정의되어 있는 함수를 디바이스 드라이버 내에 구현

디바이스 드라이버를 리눅스에 추가하는 과정

  1. 디바이스 드라이버 코어 함수 구현
  2. 작성된 코어 함수를 리눅스에 등록시키기 위한 래퍼 작성
  3. 디바이스 드라이버 커널 등록
  4. 디바이스 드라이버를 호출하기 위한 진입점에 해당하는 장치 파일 생성

2. 문자 디바이스 드라이버 구조

→ 실습

3. 블록 디바이스 드라이버 구조

블록 디바이스 드라이버

  • 파일 시스템에서 논리적인 블록에 대한 읽기/쓰기 요청이 발생했을 때 이 논리적인 블록을 물리적인 주소로 변환하여 실제 데이터를 주 메모리로 읽어옴
  • 디스크에서 사건의 발생을 알렸을 때 그 사건을 처리함
  • 문자 디바이스 드라이버와 달리 사용자의 read()/write() 함수와 1:1로 연결되지 않음 → 대신 리눅스 페이지캐시와 통신

리눅스 I/O 스케줄러

  1. CFQ (Completely Fair Queuing) 정책
    • 기본적으로 64개의 큐 유지
    • 태스크의 PID 해쉬 값을 인덱스로 하여 I/O 요청을 각 큐에 나누어 저장
    • 각 큐에서 공평하게 I/O 요청을 꺼내어 디바이스 드라이버의 큐에 넣음
  2. Deadline 정책
    • 읽기 요청과 쓰기 요청이 완료되어야 하는 시간(deadline)을 지정하여 특정 I/O 요청이 병합이나 순서 변경 등의 이유로 장시간 대기하는 것을 방지
  3. Anticipatory
    • deadline + 시스템 성능 향상을 위해 두가지 기법 추가
  4. NOOP
    • 아무 일도 하지 않음
    • I/O 스케줄링으로 인한 성능 향싱이 적은 SSD등의 저장장치가 존재하기 때문에 존재

이 글은 아래의 책을 공부 및 정리한 내용입니다.
리눅스 커널 내부구조 - 예스24

profile
탐험하는 개발자

0개의 댓글