본 글은 The Linux Kernel 을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.


하드 디스크

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=capemay&logNo=220221154613

  • 하드 디스크는 작동기(actuator)로 원반 표면 위에서 헤드를 움직이게 하며, 이 원반(platter)은 가운데 축(spindle)에 연결되어 일정한 속도로 회전하는데 이 원반은 하나 이상 존재
    • 회전 속도는 3000RPM ~ 10000RPM 사이 다양함
  • 읽기/쓰기 헤드(read/write head)는 원반 표면에 있는 미세한 알갱이에 자성을 띄워서 디스크에 자료를 기록하고, 이 자성을 감지하여 자료를 읽음
  • 각 원반의 윗면과 아랫면에 각각 헤드가 존재하고, 읽기/쓰기 헤드는 물리적으로 원반 표면을 건드리지 않고 아주 얕게 원반 위에 떠있으며, 모든 읽기/쓰기 헤드는 원반 표면에서 동일하게 움직임
  • 원반의 각 표면은 트랙(track)이라는 작은 동심원으로 나누어지며, 바깥쪽에 있을 수록 작은 번호, 중심에 가까울수록 큰 번호의 트랙
  • 실린더(cylinder)는 동일한 번호를 가진 트랙의 집합으로, 원반 양면의 k번 트랙은 모두 k번 실린더
  • 각 트랙은 섹터(sector)로 나뉘며, 섹터는 자료를 디스크에 저장하고 읽어들이는 최소 단위로, 디스크 블럭 크기와 동일 (보통 512바이트로, 이 크기는 디스크 제작 후 포맷 시 지정됨)
    • 터미널에서 출력했을 때 보여지는 디스크 용량이 더 작은 이유는 섹터 중 일부는 디스크 파티션 정보를 저장하므로 제외되기 때문
  • 디스크는 보통 기하학 구조로 표현되며, 부팅 시 IDE 디스크는 다음과 같이 나타낼 수 있음
    • hdb: Conner Peripherals 540MB-CFS540A, 516MB w/64kB Cache, CHS=1050/16/63
    • 디스크 1050개의 실린더(트랙), 16개의 헤드(8개의 원반), 각 트랙에는 63개의 섹터가 있음을 의미
    • 디스크 저장 용량은 516MB
  • 어떤 디스크들은 자동으로 배드 섹터(bad sector)를 찾아내서 디스크가 제대로 작동하도록 인덱스를 다시 부여하기도 함
  • 하드 디스크는 특별한 목적을 위해 할당된 섹터들의 그룹인 파티션(partition) 단위로 쪼개질 수 있고, 파티셔닝은 디스크를 여러 OS에게 나눠주는 등의 이유로 사용
  • 많은 리눅스 시스템은 하나의 디스크에 3개의 파티션을 포함: DOS 파일 시스템, EXT2 파일 시스템, 스왑 파티션
    • 이러한 파티션 정보는 파티션 테이블에 나와 있으며, 이 테이블의 각 엔트리는 파티션의 시작과 끝에 해당되는 헤드와 섹터, 실린더 번호를 포함
    • fdisk로 DOS로 포맷된 디스크는 4개의 1차 디스크 파티션(primary disk partition)을 가질 수 있고, 파티션 테이블의 4개 엔트리 모두 쓰일 필요는 없음
    • fdisk는 3가지 유형의 파티션을 지원: 1차(primary), 확장(ㄷxtended), 논리(logical) 파티션
    • 확장 파티션은 진짜 파티션이 아니며, 여러 논리 파티션을 가지고 있는 것
    • 다음은 2개의 1차 파티션을 갖는 디스크에 fdisk를 실행한 결과: 첫번째 파티션이 헤드 1, 섹터 1, 실린더 0에서 시작하며, 헤드 63, 섹터 32, 실린더 477 까지 있음을 의미. 두번째 파티션은 스왑 파티션으로 다음 실린더 478에서 시작하여 디스크 가장 안쪽 실린더까지 포함 (원반 표면의 바깥에서 안쪽 방향으로 각 파티션들이 위치함)

fdisk 결과

  • 리눅스는 초기화할 때 하드 디스크의 배치도를 메모리에 매핑하는데, 먼저 시스템에 디스크 개수와 각 디스크의 종류를 파악하여 각 디스크 파티션이 나누어지는 구조를 탐색
  • IDE 같은 개별 디스크 서브시스템은 초기화할 때 찾은 디스크를 gendisk 구조체로 기술하며, gendisk_head 포인터가 이 구조체들의 리스트를 참조
    • 각 gendisk 구조체는 블럭 특수 장치의 메이저 번호와 일치하는 고유한 번호를 가짐
    • 아래 그림의 맨 앞 gendisk는 SCSI 디스크 서브시스템의 것이고, 다음은 IDE 디스크 서브시스템의 것으로, 첫번째 IDE 컨트롤러는 "ide0"
    • gendisk 구조체는 리눅스가 파티션을 검사할 때만 쓰이며, 각 디스크 서브시스템은 장치의 메이저와 마이너 장치 번호를 물리 디스크에 있는 파티션과 매핑시킬 수 있도록 각자의 자료구조를 구축함
    • 블럭 장치가 버퍼 캐시나 파일 연산을 통해 읽혀지거나 쓰일 때, 커널은 이 연산을 블럭 장치 특수 파일(e.g., /dev/sda2)에서 발견한 메이저 장치 번호를 이용하여 올바른 장치로 보냄
    • 마이너 장치 번호를 물리 장치에 연결하는 것은 개별 디스크 드라이버나 서브시스템의 역할 (마이너 장치 번호로 장치를 구별)

디스크 커널 자료구조
https://www.twblogs.net/a/5ca59651bd9eee5b1a0720f4

  • IDE(Intergrated Disk Electronics) 디스크
    • IDE는 SCSI 같은 I/O 버스가 아닌 디스크 인터페이스
    • 각 IDE 컨트롤러는 2개의 디스크까지 지원: 주 디스크(master), 종속 디스크(slave)
    • IDE는 1초에 3.3 Mbytes의 데이터를 전송, 디스크 최대 크기는 538MB
    • 확장 IDE(Extended IDE, EIDE)는 디스크 크기를 최대 8.6GB로 가지며, 전송 속도를 초당 16.6MB로 올린 것
    • IDE/EIDE 디스크는 SCSI 디스크보다 저렴하며 대부분 PC는 IDE 컨트롤러를 포함
    • 리눅스는 IDE 디스크의 이름을 컨트롤러(최대 2개)를 발견한 순서에 따라 부여함
      • 1차 IDE 컨트롤러의 주 디스크는 /dev/hda 이고 종속 디스크는 /dev/hdb
      • 2차 IDE 컨트롤러의 주 디스크는 /dev/hdc
    • IDE 서브시스템은 커널에 IDE 컨트롤러를 등록하지만 디스크를 등록하지는 않음
    • 1차 IDE 컨트롤러의 메이저 장치 번호는 3이고, 2차 IDE 컨트롤러의 것은 22일 때, blk_dev와 blkdevs 배열의 3번과 22번 인덱스에 IDE 서브시스템 엔트리가 저장됨
    • 커널은 블럭 특수 파일을 관리하는 IDE 서브시스템에 대한 파일 연산이나 버퍼 캐시 연산을 메이저 장치 번호를 인덱스로 사용하여 알아낸 IDE 서브시스템으로 전달하며, 어떤 디스크에 대한 요청인지는 IDE 서브시스템이 마이너 장치 번호를 사용하여 판별
    • IDE 서브시스템 초기화
      • 커널은 시스템의 CMOS 메모리에 디스크 정보를 살펴보고, 발견한 디스크의 기하학 정보를 BIOS로부터 알아내 이 정보를 각자의 ide_hwif_t 구조체를 설정하는데 사용함
      • 최근 PCI EIDE 컨트롤러를 포함하는 경우 PCI 칩셋을 사용하는데, 여기서 PCI BIOS 콜백을 이용해서 컨트롤러를 찾음
      • IDE 컨트롤러가 발견되면, 연결된 디스크를 반영하여 ide_hwif_t가 설정됨
      • IDE 드라이버가 I/O 메모리 공간에 있는 IDE 명령 레지스터에 쓰면서 동작하는데, 각 컨트롤러는 리눅스 블럭 버퍼 캐시와 가상 파일 시스템에 자신을 등록 (blk_dev와 blkdevs 배열에 추가되는 것)
      • 추가로, 인터럽트에 대한 제어권을 요청하고, 부팅 시 발견된 컨트롤러마다 gnedisk 구조체를 생성해 gendisk_head 포인터가 참조하는 리스트에 추가 (이 리스트는 디스크의 파티션을 찾는데 사용됨)
  • SCSI(Small Computer System Interface) 디스크
    • SCSI 버스 하나 이상의 호스트를 포함하여 버스마다 8개까지의 장치를 지원할 수 있는 1:1 데이터 버스
    • 각 장치는 고유 식별자를 가지며, 대개 디스크에 있는 점퍼로 설정됨
    • 버스에 있는 두 장치 사이에는 동기적 또는 비동기적 데이터 전송이 가능하며, 32비트 크기로 초당 40MB까지 허용
    • SCSI 버스는 데이터 뿐만 아니라 상태 정보도 전송
    • 전송 시작(initator)과 전송 대상(target) 사이의 하나의 트랜잭션은 8개의 서로 다른 상태를 가지며, SCSI 버스의 현재 상태는 5개의 신호로부터 알 수 있음
      • BUS FREE 버스에 대한 제어권을 가진 장치 또는 트랜잭션이 없음
      • ARBITRATION 어떤 장치가 자신의 식별자를 보내 SCSI 버스에 대한 제어권을 얻는 중(중재), 동시에 발생할 경우 더 높은 번호에 제어권이 주어짐
      • SELECTION 장치가 중재를 통해 제어권을 얻으면, SCSI 요청을 받을 대상에게 명령을 보낼 준비라는 신호를 전달
      • COMMAND 6/10/12 바이트의 명령을 전송 시작자에서 전송 대상으로 전달
      • DATA IN, DATA OUT 데이터가 전달되는 상태
      • STATUS 모든 명령을 완료한 상태로, 성공과 실패를 나타내는 바이트를 응답해야 함
      • MESSAGE IN, MESSAGE OUT 추가적인 정보 전달
    • SCSI 서브시스템의 2가지 요소(호스트와 장치)는 각 자료구조로 표현됨
    • 호스트(host) SCSI 컨트롤러, 같은 종류의 컨트롤러가 하나 이상 존재하면 각각 별도의 호스트로 표현
      • SCSI 디바이스 드라이버는 컨트롤러가 여러개 일 때 제어 가능
      • SCSI 호스트는 대부분 SCSI 명령의 전송 시작자
    • 장치(device) 가장 일반적인 장치 유형으로 SCSI 디스크가 있으며, 테이프나 CD-ROM 같은 여러 종류를 지원하기도 함.
      • 각 장치는 서로 다르게 취급되며, SCSI 장치는 대부분 SCSI 명령의 전송 대상

SCSI 디스크 커널 자료구조

  • SCSI 서브시스템 초기화
    • 먼저 시스템에 있는 SCSI 컨트롤러(호스트)를 찾은 뒤, SCSI 버스를 검사하여 모든 장치를 탐색
    • 각 장치를 초기화: 일반 파일 연산과 버퍼 캐시 블럭 장치 연산을 매핑하여 나중에 사용될 수 있게 함
    • 커널을 빌드할 때 SCSI 호스트 어댑터(컨트롤러) 중 제어할 하드웨어의 것을 찾음
    • 커널에 포함된 호스트들은 builtin_scsi_hosts 배열에 Scsi_Host_Template 엔트리를 가지며, 이 구조체는 각 SCSI 호스트에 어떤 SCSI 장치가 연결되었는지 알기 위해 호스트마다 고유 루틴에 대한 포인터를 포함
    • SCSI 서브시스템은 자신을 설정하는 동안 이 루틴들을 호출하는데 루틴은 각 호스트에 대한 SCSI 디바이스 드라이버의 일부
    • 실제 장치가 연결된 호스트는 자신의 Scsi_Host_Template 구조체를 활성화된 호스트 목록인 scsi_hosts 리스트에 추가
    • 감지된 호스트 유형에 해당하는 호스트는 scsi_hostlist 리스트에 있는 Scsi_Host 구조체로 기술됨
    • 모든 호스트를 발견하면, SCSI 버스에 있는 장치로 TEST_UNIT_READY 명령을 전달해 버스에 연결된 장치들을 탐색
    • 장치가 응답하면 ENQUIRY 명령을 보내 신원 확인을 통해 커널에 제작자 이름과 장치 모델명 및 개정 이름을 전달
    • SCSI 명령은 Scsi_Cmnd 구조체로 기술되며, Scsi_Host_Template 구조체 있는 디바이스 드라이버 루틴을 호출할 때 Scsi_Cmnd 구조체가 전달됨
    • SCSI 장치는 Scsi_Device 구조체로 기술되며, 각각 부모 Scsi_Host 구조체를 참조하는데, 모든 Scsi_Device 구조체는 scsi_devices 리스트에 추가됨
    • 장치의 유형은 4가지가 존재: 디스크, 테이프, CD, 일반
      • 메이저 블럭 장치 유형으로 커널에 별도로 등록
      • 각 유형마다 장치 테이블을 관리하며, 이 테이블은 커널의 블럭 연산(파일, 버퍼 캐시)을 올바른 디바이스 드라이버나 SCSI 호스트로 보내는데 사용됨
      • 유형별로 Scsi_Device_Template 구조체를 생성하며, 이는 장치에 대한 정보 및 다양한 작업을 수행하는 루틴들의 주소를 포함. SCSI 서브시스템은 이 구조체를 이용해 장치의 유형별 루틴을 호출
      • 어떤 유형을 갖는 SCSI 장치가 하나 이상 발견되면 Scsi_Type_Template 구조체가 scsi_Devicelist 리스트에 추가됨
      • 초기화의 마지막 상태는 등록된 각 Scsi_Device_Template 구조체로부터 종료 함수를 부르는 것으로, SCSI 디스크 유형의 경우 발견한 모든 디스크를 회전시켜 각 디스크 구조를 기록한 뒤, 모든 SCSI 디스크를 나타내는 gendisk 구조체를 디스크 구조체 리스트에 추가
  • 블럭 장치 요청 전달
    • SCSI 서브시스템을 초기화하면 SCSI 장치들을 사용할 수 있으며, 정상 동작하는 장치 유형은 커널에 자신을 등록하여 블럭 장치 요청이 들어올 때마다 해당 장치 유형으로 전달되게 함
    • 요청은 blk_dev 배열을 인덱싱하여 버퍼 캐시 요청이나 blkdevs 배열을 인덱싱하여 파일 연산 요청으로 나뉨
    • SCSI 디스크에서 하나 이상의 EXT2 파일 시스템 파티션을 가지는 경우, 디바이스 드라이버는 파티션 중 하나를 마운트할 때 커널 버퍼 요청을 올바른 파일 시스템으로 전달
    • SCSI 디스크 파티션에서 한 블럭의 데이터를 읽고 쓰는 요청은 SCSI 디스크의 current_request 리스트에 새로운 request 구조체를 추가하여 처리됨. 처리중이면 버퍼 캐시는 다른 일을 할 필요가 없으며, 처리중이 아니면, 계속 요청 큐를 하나씩 처리
      • SCSI 디스크 파티션의 마이너 장치 번호 중 일부를 사용하여 blk_dev 배열을 인덱싱하며, 얻은 자료구조의 일부에 current_request 포인터가 존재
      • 각 Scsi_Disk 구조체는 이 장치를 나타내는 Scsi_Device 구조체에 대한 포인터를 가짐
      • Scsi_Device 구조체는 각자 소유한 Scsi_Host 구조체를 순서대로 참조
    • 버퍼 캐시로부터 온 request 구조체는 Scsi_Cmnd 구조체로 변환되고, 이 구조체는 Scsi_Host 구조체의 큐에 추가됨
    • 한 번 데이터 블럭을 읽거나 쓰고 나면, 이 요청들은 개별 SCSI 디바이스 드라이버에 의해 처리됨

네트워크 장치

  • 네트워크 디바이스 드라이버는 커널이 부팅하면서 초기화하는 동안 제어하는 장치를 커널에 등록하는데, 네트워크 장치는 device 구조체로 표현되며, 각 구조체는 장치 정보 및 리눅스에서 네트워크 프로토콜들이 장치의 서비스를 이용할 수 있는 (대부분 장치를 통한 데이터 전송과 관련된) 함수들의 주소를 포함
  • 네트워크 장치 특수 파일은 초기화 과정에서 차례로 생성되며, 이들 이름은 장치 유형을 나타내는 표준 이름이며 0부터 시작하는 번호가 뒤에 붙어서 식별됨
    • 이더넷 장치: /dev/eth0, /dev/eth1, /dev/eth2
    • SLIP 장치: /dev/sl0, /dev/sl1, /dev/sl2
    • PPP 장치: /dev/ppp0, /dev/ppp1, /dev/ppp2
    • 루프백 장치: /dev/lo
  • device 구조체가 포함한 장치 정보 등 모든 정보는 부팅 시 초기화될 때 설정됨
    • 버스 정보 디바이스 드라이버가 장치를 제어하기 위한 것
    • IRQ 번호 장치가 사용하는 인터럽트 번호
    • 베이스 주소 장치의 제어 레지스터 및 상태 레지스터가 있는 I/O 공간의 주소
    • DMA 채널 네트워크 장치가 사용하는 DMA 채널 번호
    • 인터페이스 플래그 네트워크 장치의 특징과 능력을 설명

인터페이스 플래그

  • 프로토콜 정보 네트워크 프로토콜 게층이 장치를 제어하는 방법을 나타냄
    • MTU 링크 계층에서 붙이는 헤더를 제외하고 전송 가능한 최대 패킷 크기
    • Family 장치가 지원할 수 있는 프로토콜 계열 e.g., AF_INET: 인터넷 주소
    • Type 하드웨어 인터페이스 유형으로, 장치에 연결된 매체 e.g., 이더넷
    • Address device 구조체는 IP 주소를 포함하여 여러 주소를 가짐
  • 패킷 큐(Packet Queue) 네트워크 장치가 전송하기를 기다리는 sk_buff 구조체의 리스트
    • 보내고 받는 모든 네트워크 데이터(패킷)은 sk_buff 구조체로 기술됨
  • 각 장치는 프로토콜 계층에서 호출 가능한 표준 함수 집합을 제공하여 전송받은 데이터를 올바른 프로토콜 계층으로 전달
  • 이는 셋업하고 프레임을 전송하는 루틴 외에 표준 프레임 헤더를 추가하고 통계 정보를 모으는 루틴도 포함되어 있으며, 통계 정보는 ifconfig 명령으로 출력 가능
  • 네트워크 장치 초기화
    • 네트워크 게층은 장치에 고유한 작업을 수행할 때 device 구조체에 있는 서비스 루틴을 호출
    • 단, device 구조체는 최초에 초기화나 장치를 탐사(probe)하는 루틴의 주소만 가짐
    • 장치의 초기화 루틴을 호출하면, 구동할 컨트롤러가 존재하는지 나타내는 상태값을 얻게 되고, 아무런 장치도 못찾으면 dev_base 포인터가 참조하는 device 리스트에 있는 엔트리가 제거됨
    • 장치를 찾게 되면, device 구조체의 나머지 부분을 장치 정보 및 드라이버가 지원하는 함수들로 설정
    • 장치 리스트에는 eth0 부터 eht7 까지 8개의 표준 엔트리가 있는데, 초기화 코드는 장치를 찾을 때까지 이더넷 디바이스 드라이버를 하나씩 시도
    • 이더넷 장치를 찾으면 device 구조체의 내용을 채우고, 제어할 하드웨어를 초기화한 뒤 사용할 IRQ 번호 및 DMA 채널 등을 알아냄. 8개 모두 할당되면 이더넷 장치를 더 이상 찾지 않음
  • 네트워크 장치 파일은 실제로 장치가 존재하는 경우에만 생성되나, 보통 문자 장치나 블럭 장치는 실제로 장치가 존재하지 않더라도 장치 특수 파일이 존재함

 

+ Recent posts