1 / 76

13 장 . 입출력 장치 관리

리눅스 커널의 이해 중에서. 13 장 . 입출력 장치 관리. 장재필 시스템 소프트웨어 실험실. 목차. Part I : 입출력 아키텍처. Part II : 파일을 입출력 장치와 연관시키기. Part III : 장치 드라이버. Part IV : 문자 장치 처리. Part IV : 블록 장치 처리. Part V : 페이지 입출력 연산. Part I :. 입출력 아키텍쳐. 입출력 아키텍처. 버스

peigi
Download Presentation

13 장 . 입출력 장치 관리

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 리눅스 커널의 이해 중에서 13장. 입출력 장치 관리 장재필 시스템 소프트웨어 실험실

  2. 목차 Part I : 입출력 아키텍처 Part II : 파일을 입출력 장치와 연관시키기 Part III : 장치 드라이버 Part IV : 문자 장치 처리 Part IV : 블록 장치 처리 Part V : 페이지 입출력 연산

  3. Part I : 입출력 아키텍쳐

  4. 입출력 아키텍처 • 버스 CPU(들), 램 그리고 개인용 컴퓨터에 연결할 수 있는 여러 입출력 장 사이에 정보가 흘러갈 수 있는 경로 • 데이터 버스(data bus) • 데이터를 병렬로 전송하는 라인 모임 (펜티엄은 64비트 폭의 데이터 버스) • 주소버스 (address bus) • 주소를 병렬로 전송하는 라인 모임 (펜티엄은 32비트 폭의 주소 버스) • 제어버스 (control bus) • 연결된 회로에 제어 정보를 전송하는 라인 모임

  5. 입출력 아키텍처 • PC의 입출력 아키텍쳐

  6. 입출력 아키텍처 • 입출력 포트 • I/O 버스에 연결된 각 장치마다 자신만의 I/O 주소 집합 • in, ins, out, outs를 통해 CPU는 값을 읽거나 쓸 수 있다. • 요청한 입출력 포트를 선택하기 위해 주소버스 사용 • 데이터를 전송하기 위해 데이터 버스 사용 • 물리 주소 공간의 주소로 매핑 가능 • 어셈블리 명령으로 입출력 장치와 통신 • DMA와 결합할 수 있다

  7. 입출력 아키텍처 • 특수 입출력 포트

  8. 입출력 아키텍처 • 입출력 인터페이스 • 입출력 포트 그룹과 장치 제어기 사이에 들어가는 하드웨어 회로 • 입출력 포트 값을 장치용 명령과 데이터로 변환 • IRQ라인을 통해 프로그램 가능한 인터럽트 제어기(PIC)에 연결 • 장치를 대신해서 인터럽트 요청을 발생

  9. 입출력 아키텍처 • 전용 입출력 인터페이스 • 키보드 인터페이스 • 그래픽 인터페이스 • 디스크 인터페이스 • 버스 마우스 인터페이스 • 네트워크 인터페이스 • 범용 입출력 인터페이스 • 병렬포트 • 직렬포트 • 범용 직렬 버스 • PCMCIA 인터페이스 • SCSI 인터페이스

  10. 입출력 아키텍처 • 장치 제어기 • 입출력 인터페이스에서 받은 고수준 명령을 해석하고, 적절한 전기 신호를 장치에 보내 특정 작업 수행 • 장치에서 받은 전기 신호를 변환하고 적절히 해석한 다음, 상태 레지스터 값을 변경

  11. 입출력 아키텍처 • DMA • 램과 입출력 장치 사이에서 데이터를 전송 • CPU로 활성화한 후 DMAC는 스스로 데이터 전송 관리 • 데이터 전송 완료시 인터럽트 발생 • CPU와 DMAC 충돌시 중재자(arbiter)가 해결 • DMAC 초기 설정 시간이 길다 • 전송양이 많을경우 효과적

  12. Part 2 : 파일을 입출력 장치와 연관시키기

  13. 파일을 입출력 장치와 연관시키기 • 장치 파일 • 유형 • 블록(block) 또는 문자(character) • 주 번호 • 장치 유형을 나타내는 1~255 범위 숫자 • 부 번호 • 같은 주 번호를 공유하는 장치 그룹에서 특정 장치를 나타냄

  14. 파일을 입출력 장치와 연관시키기 • 장치 파일 예

  15. 파일을 입출력 장치와 연관시키기 • 일반적으로 장치파일은 하드웨어 장치 또는 디스크 파티션과 같은 하드웨어 장치의 물리적 또는 논리적인 부분과 관련 • 가상적인 논리적 장치를 나타내는 경우도 있다 • /dev/null은 ‘블랙홀’에 대응하는 장치파일 • 기록되는 모든 데이터는 사라진다 • 파일은 언제나 비어있는 것처럼 보인다(읽는 경우 언제나 NULL값) • /tmp/disk, ‘블록’유형의 주번호 3, 부번호 0인 장치파일 • /dev/had와 같은 파일

  16. 파일을 입출력 장치와 연관시키기 • 블록과 문자 장치 비교 • 블록장치 • 입출력 연산 한 번으로 고정된 크기의 블록 데이터 전송 • 장치에 저장한 블록은 임의대로 참조 • 하드디스크, 플로피디스크, CD-ROM, 램 디스크 • 문자 장치 • 입출력 연산 한 번으로 임의의 크기만큼 데이터 전송 • 프린터 : 1바이트, 테이프 : 가변적인 크기의 데이터 블록 • 문자를 순서대로 참조

  17. 파일을 입출력 장치와 연관시키기 • 네트워크 카드 • 대응하는 장치 파일이 없다 • 서로 다른 기호 이름(symbolic name)을 할당한다 • 장치명과 네트워크 주소 사이관계를 설정 • Socket(), bind(), listen(), accept(), connect() 시스템 콜 기반

  18. 파일을 입출력 장치와 연관시키기 • 장치 파일의 VFS 처리 • 장치 파일 클래스 티스크립터 • 장치 클래스명인 name과 파일 연산 테이블에 대한 포인터인 fops 필드를 포함 • 모든 문자 장치 파일에 대한 device_struct 디스크립터는 chrdevs 테이블에 있다 • 테이블은 사용할 수 있는 주 번호에 해당하는 255개 항목을 포함한다 • 블록 장치 파일에 대한 255개 디스크립터 모두 blkdevs 테이블에 있다 • 주번호가 0일 수 없으므로, 두 테이블의 첫째 항목은 언제나 비어있다 • chrdevs와 blkdevs 테이블은 최초 비어있는 상태 • register_chrdev()와 register_blkdev() 함수를 사용하여 각 테이블에 새로운 항목을 삽입 • unregister_chrdev()와 unregister_blkdev()를 사용하여 항목을 삭제 • 만약 장치 드라이버를 커널에 정적으로 포함시켰다면 대응하는 장치 파일 클래스를 시스템 초기화 과정동안 등록하지만 장치 드라이버를 모듈로 동적으로 로드한다면 대응하는 장치 파일 클래스를 모듈을 로드할 때 등록하고, 모듈을 언로드 할때 등록을 해지한다

  19. Part III : 장치 드라이버

  20. 장치 드라이버 • 커널 지원 수준 • 지원하지 않음 • 애플리케이션 프로그램은 적절한 in, out 어셈블리어 명령을 통해서 장치의 입출력 포트와 직접 상호 작용한다 • X 윈도우 시스템 • 입출력 장치에서 만드는 하드웨어 인터럽트를 활용하지 못하게 막는다 • iopl()과 ioperm() 시스템 콜은 프로세스에게 입출력 포트에 접근할 수 있는 권한 • 실행 파일의 fsuid 필드를 수퍼유저 UID인 0으로 설정하면 일반사용자도 가능

  21. 장치 드라이버 • 최소 지원 • 커널은 하드웨어 장치를 인식하지 않고 단지 그 입출력 인터페이스만 인식 • 사용자 프로그램은 일련의 문자열을 읽고 쓸 수 있는 순차적인 장치로 다룬다 • 범용 입출력 인터페이스에 연결된 외부 하드웨어 장치에 주로 쓰임 • 커널은 장치파일을 제공하여 입출력 인터페이스 관리 • 애플리케이션 프로그램은 장치 파일을 읽고 써서 외부 하드웨어 장치를 처리 • 커널 크기를 작게 유지할 수 있다(확장지원 방법에 비해 선호) • 범용 입출력 인터페이스중 직렬 포트만 이 접근 방법으로 처리 • 확장 지원 • 커널은 하드웨어 장치를 인식한다 • 입출력 인터페이스를 직접 처리 • 내부 하드디스크같이 입출력 버스에 직접 연결한 모든 하드웨어 • 직렬포트 이외의 모든 범용 입출력 인터페이스와 연결하는 외부장치(병렬, USB, PCMCIA, SCSI 인터페이스등)

  22. 장치 드라이버 • 입출력 연산 모니터링 • 풀링 모드(polling mode) • 상태 레지스터 값이 연산 종료 시그널을 담을 때까지 계속 검사 • 기다리는 시간이 너무 길고, 드라이버가 타임아웃 시간도 기억해야한다 • 인터럽트 모드(interrupt mode) • 입출력 제어기가 IRQ 선을 통해 입출력 연산이 끝났음을 알려줄 수 있을때 사용 • 입출력 장치 대기 큐에 대한 포인터를 매개변수로 넘겨서 interruptibla_sleep_on()또는 sleep_on()을 호출 • 인터럽트가 발생하면 인터럽트 핸들러는 wake_up()을 호출 • 깨어난 장치 드라이버는 입출력 연산 결과를 검사 • 타임아웃 제어는 정적/동적 타이머(5장 참조)로 구형

  23. 장치 드라이버 • 입출력 포트 접근 • in, out, ins, outs 어셈블리 언어에 보조 함수를 포함한다 • inb(), inw(), inl() • 입출력 포트에서 각각 연속하는 1, 2, 4바이트를 읽는다 • byte(8비트), word(16비트), long(32비트)를 나타낸다 • inb_p(), inw_p(), inl_p() • 위 작업 수행 후, 잠깐 쉬기(pause) 실행 • outb(), outw(), outl() • 각각 연속하는 1, 2, 4바이트를 입출력 포트에 쓴다 • outb_p(), outw_p(), outl_p() • 위 작업 수행 후, 잠깐 쉬기(pause)실행 • insb(), insw(), insl() • 연속하는 바이트 열을 1, 2, 4바이트 단위로 입출력 포트에서 읽는다 • 열 길이는 함수의 매개변수로 지정 • outsb(), outsw(), outsl() • 연속하는 바이트 열을 1, 2, 4바이트 단위로 입출력 포트에 쓴다

  24. 장치 드라이버 • request_region() • 주어진 입출력 포트 범위를 입출력 장치에 할당 • check_region() • 주어진 입출력 포트의 범위가 비어있는지, 그 중 일부를 이미 입출력 장치에 할당했는지 검사 • release_region() • 이전에 입출력 장치에 할당했던 입출력 포트 범위를 해제 ※ 현재 입출력 장치에 할당한 입출력 주소는 /proc/ioports 파일에 서 얻을 수 있다

  25. 장치 드라이버 • IRQ요청 • 사용 카운터가 현재 장치 파일에 접근하고 있는 프로세스 개수를 기억한다 • 카운터는 장치 파일의 open 메소드에서 증가하고, release 메소드에서 감소 • open 메소드는 값이 증가하기 전에 사용 카운터 값을 검사 • 카운터가 0이면, 장치 드라이버는 IRQ를 할당하고, 하드웨어 장치에 대한 인터럽트를 활성화 해야 한다. • request_irq()를 호출하고, 입출력 제어기를 설정 • Release 메소드는 값을 감소시킨 후 카운터 값을 검사 • 카운터가 0이면, 하드웨어 장치를 사용하는 프로세스가 하나도 없음 • free_irq()를 호출하여 IRQ 선을 해제하고, 제어기에 대한 인트럽트 비활성

  26. 장치 드라이버 • DMA 가동 • 연산 속도를 높이기 위해 활용 • 데이터 전송을 위해 장치의 입출력 제어기와 상호 작용 • 커널은 선형 주소를 버스 주소로 또는 그 반대로 변환 • Virt_to_bus, bus_to_virt 매크로 제공 • IRQ와 마찬가지로 DMAC도 요청하는 드라이버에 동적으로 할당

  27. 장치 드라이버 • ISA버스에 대한 DMA • 장치 파일의 open() 메소드에서 장치의 사용 카운터를 증가 • 증가시키기 전의 값이 0이면, 드라이버는 다음과 같이 동작 • request_irq()를 호출하여 ISA DMAC가 사용할 IRQ 선을 할당 • request_dma()를 호출하여 DMA 채널을 할당 • 하드웨어 장치에 DMA를 사용해야 하며, 인터럽트 발생사실을 알린다 • DMA 버퍼를 위한 저장 공간을 할당

  28. 장치 드라이버 • DMA 연산을 시작할 때 다음과 같은 연산을 수행 • set_dma_mode()를 호출하여 채널을 읽기/쓰기 모드로 설정 • set_dma_addr()을 호출하여 DMA 버퍼의 버스 주소를 설정 • set_dma_count()를 호출하여 전송할 바이트 수를 설정 • enable_dma()를 호출하여 DMA 채널을 활성화 한다 • 현재 프로세스를 장치의 대기 큐에 넣고, 이를 보류한다. DMA가 전송연산을 종료하며, 장치의 입출력 제어기가 인터럽트를 발생시키고, 해당 인터럽트 핸들러가 잠든 프로세스를 깨운다 • disable_dma()를 호출하여 DMA 채널을 비활성화 한다 • get_dma_residue()를 호출하여 모든 바이트를 전송했는지 검사 • 카운터가 0이 되면, 다음 연산을 수행한다 • DMA와 하드웨어 장치에서 해당 인터럽트를 비활성화한다 • free_dma()를 호출하여 DMA 채널을 해제한다 • free_irq()를 호출하여 DMA에 사용한 IRQ 선을 해제한다

  29. 장치 드라이버 • PCI버스에 대한 DMA • DMA 연산의 종료를 알리기 위해 사용할 IRQ선을 할당해야 한다 • DMA 채널을 할당할 필요는 없다 • DMA 버퍼의 버스주소, 전송방향, 데이터 크기 등을 기록 • release 메소드가 IRQ선을 해제

  30. 장치 드라이버 • 장치 제어기의 지역 메모리 • 주소 매핑 • ISA 버스에 연결된 장치의 대부분 • 물리주소 범위 0xa0000에서 0xfffff에 대응한다. 이 범위는 2장의 ‘예약된 페이지 프레임’에서 언급한 640KB에서 1MB 사이의 ‘구멍’에 해당 • VESA 지역버스(VLB)를 사용하는 오래된 장치 • 입출력 공유 메모리 주소 범위 0xe00000에서 0xffffff에 대응한다. 즉 14MB에서 16MB 범위이다. 페이징 테이블의 초기화를 복자바게 만듦 • PCI 버스에 연결된 장치 • 입출력 공유 메모리는 램의 물리 주소 범위를 훨씬 초과한 큰 물리 주소 영역에 대응

  31. 장치 드라이버 • 입출력 공유 메모리 접근 • PAGE_OFFSET보다 큰 주소로 나타내야 한다 • PAGE_OFFSET이 0xc0000000이라고 가정한다(3GB~4GB) • t1에 물리적 주소 0xc000b0fe4인 입출력 위치값을 저장 • t2에 물리적 주소 0xfc000000인 입출력 위치 값을 저장해야 한다고 가정 t1=*((unsigned char *)(0xc00b0fe4)); t2=*((unsigned char *)(0xfc000000)); • t1의 주소는 640KB에서 1MB사이의 ISA 구멍부분에 해당하므로 잘 동작 • t2는 시스템 램의 마지막 물리 주소보다 크므로 물리 주소를 대응시키는 선형 주소를 포함하도록 바꿔야 함 • ioremap() 함수를 호출하여 처리/매핑 제거시 iounmap() io_mem = ioremap(0xfb000000, 0x200000); t2 = *((unsigned char *)(io_mem + 0x100000)); • 0xfb000000에서 시작하는 새로운 2MB 선형 주소 범위를 생성 • 0xfc000000 주소로 메모리 위치를 읽는다

  32. 장치 드라이버 • Readb, readw, readl • 입출력 공유 메모리 위치에서 각각 1, 2, 4바이트를 읽는다 • Writeb, writew, writel • 입출력 공유 메모리 위치에 각각 1, 2, 4바이트를 쓴다 • Memcpy_fromio, memcpy_toio • 입출력 공유 메모리 위치에서 동적 메모리로 혹은 그 반대로 데이터 블록을 복사 • Memset_io • 입출력 공유 메모리 영역을 특정 값으로 채운다 0xfc000000 입출력 위치에 접근하는 방법은 io_mem = ioremap(0xfb000000, 0x200000); t2 = readb(io_mem + 0x100000); ※ 이 매크로로 플랫폼별 호환성을 높일수 있다

  33. Part IV : 문자 장치 처리

  34. 문자 장치 처리 • 데이터 버퍼링, 디스크 캐시 불필요 • 복잡한 통신 프로토콜을 구현한다 • 하드웨어 장치의 입출력 포트에서 값을 읽는다

  35. 문자 장치 처리 • 로지텍 버스 마우스의 드라이버 동작 • 장치 드라이버는 /dev/logibm 문자 장치 파일에 대응 • 주 번호 10, 부 번호 0을 갖는다 • 파일 객체의 f_op필드는 bus_mouse_fops 테이블을 가리키고,open_mouse() 함수를 호출 • 버스 마우스를 열결했는지 검사 • 버스 마우스가 사용하는 IRQ 선, 즉 IRQ 5를 요청하고, mouse_interrupt() 등록 • Mouse_status 유형의 mouse라는 작은 자료 구조를 초기화버튼 클릭/포인트 이동 정보저장 • 0x23e제어 레지스터에 0을 쓴다 • 마우스 사용시 마다 mouse_interrupt() 함수를 활성화한다. • 버스 마우스 상태 확인 0x23e제어 레지스터에 적절한 명령 기록0x23c입력 레지스터에서 해당 값을 읽는다 • Mouse 자료 구조를 갱신 • 0x23e 제어 레지스터에 0을 기록

  36. 문자 장치 처리 • /dev/logibm 파일을 읽어 마수으 상태를 얻는다read() 시스템 콜은 파일 연산의 read 메소드와 관련한 read_mouse() 호출 • 프로세스가 적어도 3바이트를 요청했는지 검사하고, 아니라면 –EINVAL을 반환 • /dev/logibm에 대한 마지막 읽기 연산 이후 마우스 상태가 바뀌었는지 검사그렇지 않으면 –EAGAIN을 반환 • disable_riq()를 호출하여 IRQ5의 인터럽트 처리를 비활성, mouse자료구조의 값enalbe_irq()를 호출하여 IRQ5의 인터럽트 처리를 다시 활성화 • 마지막 읽기 연산 이후에 마우스 상태를 나타내는 3바이트를 사용자 모드 버퍼에 기록 • 프로세스가 3바이트 이상을 요청했다면, 나머지 사용자 모드 버퍼를 0으로 채운다 • 기록한 바이트 수를 반환

  37. Part V : 블록 장치 처리

  38. 블록 장치 처리 • VFS를 통한 단일화된 인터페이스 제공 • 디스크 데이터에 대한 효율적인 미리 읽기 구현 • 데이터에 대한 디스크 캐싱 제공

  39. 블록 장치 처리 • 버퍼 입출력 연산 • 전송한 데이터는 버퍼에 남아있다 • 각 버퍼를 장치 번화와 블록 번호로 표현할 수 있는 특수한 블록에 대응 • 실제로 버퍼 입출력 연산은 비동기적으로 이루어진다 • 프로세스가 블록 장치 파일을 직접 읽거나 커널이 파일 시스템의 특정 유형 블록을 읽을 때 주로 사용 • 디스크 기반의 일반 파일을 기록할 때 사용(리눅스 2.2)

  40. 블록 장치 처리 • 페이지 입출력 연산 • 전송된 데이터는 페이지 프레임에 남아있다 • 각 페이지 프레임에는 일반 파일에 속한 데이터가 있다 • 파일의 아이노드와 파일 내 오프셋으로 표현 • ‘비동기적 입출력 연산’이라 한다 • 일반 파일을 읽거나 파일 메모리 매핑, 스와핑을 위해 사용 ※ 두 종류의 입출력 데이터 전송 모두 블록 장치에 접근하기 위해 동일한 드라이버를 사용하지만, 커널은 이들에 대해 서로 다른 알고리즘과 버퍼링 기법을 사용한다

  41. 블록 장치 처리 • 섹터, 블록, 버퍼 • 블록 장차에 대한 각 데이터 전송 연산을 섹터라는 연속 바이트 그룹에 따라 수행 • 대개 디스크 장치의 섹터 크기는 512바이트 • 여러 인접 섹터를 한 번에 전송할 수 있지만, 한 섹터보다 작은 자료는 결코 전송할 수 없다 • hardsect_size[3][2]는 /dev/hda2를 나타낸다 • hardsect_size[M]이 NULL인 경우, 주 번호 M을 공유하는 모든 블록 장치는 섹터 크기가 표준인 512바이트이다. • 섹터는 하드웨어 장치에 대한 데이터 전송의 기본 단위 • 블록은 장치 드라이버가 요청하는 입출력 연산과 관련한 인접한 바이트 그룹 • 리눅스 내 블록 크기는 반드시 2의 제곱, 페이지 프레임보다 작다

  42. 블록 장치 처리 • 블록에는 섹터가 정수 개 있기 때문에, 반드시 섹터 크기 배수여야 한다 • 각 블록 장치는 자신만의 고유한 크기로 블록을 제한 • 커널은 blksize_size라는 테이블에 블록 크기를 저장 • blksize_size[M]이 NULL이면, 주 번호 M을 공유하는 모든 블록 장치는 표준 블록 크기가 1024바이트 이다 • 커널이 블록의 내용을 저장하기 위해 사용하는 램 메모리 영역을 요청 • 장치 드라이버가 디스크에서 블록을 읽을 때, 하드웨어 장치에서 얻은 값을 사용하여 해당 버퍼를 채운다 • 장치 드라이버가 디스크에 블록을 기록할 때, 버퍼의 실제 값을 사용하여 하드웨어 장치의 연속 바이트를 갱신한다 • 버퍼 크기는 언제나 대응하는 블록 크기와 일치

  43. 블록 장치 처리 • 버퍼 입출력 연산에 대한 블록 장치 핸들러 아키텍처

  44. 블록 장치 처리 • 버퍼 입출력 연산 개요 • 자신만을 위한 고 수준 장치 드라이버를 요구한다 • 플로피디스크의 장치 드라이버 • 마지막으로 디스크에 접근한 다음에 사용자에 의해 드라이브 내부에 있는 디스크가 변경되지 않았는지 검사 • 새로운 디스크가 삽입했다면, 장치 드라이버는 이전 디스크의 데이터로 채워져 있는 모든 버퍼를 무효화해야 한다 • 고 수준 장치 드라이버는 자신의 read와 write 메소드가 있는 경우에도, 일반적으로 block_read()와 block_wirte()를 호출 • getblk() 함수를 호출하여 블록을 이미 읽었는지, 남아있는지 검사 • 캐쉬에 없을경우 getblk()는 ll_rw_block()을 호출 • VFS가 블록 장치의 특정 블록에 직접 접근할 때도 발생 • 언제나 비동기적으로 이루어 진다 • 저 수준 장치 드라이버는 DMAC와 디스크 제어기를 프로그래밍하고 종료 • 전송을 마치면 인터럽트가 발생하여 저 수준 장치 드라이버를 두 번째로 활성화하여 입출력 연산과 관련한 자료 구조를 지운다

  45. 블록 장치 처리 • 미리 읽기의 역할 • 블록 장치의 여러 인접 블록을 요청하기 전에 미리 익어두는 기법 • 적은 명령어로 인접한 섹터를 좀더 큰 섹터 그룹을 읽도록 한다 • 시스템의 응답성(responsiveness)도 좋아진다 • 블록 장치에 대한 임의(random) 접근의 경우, 쓸모없는 정보를 저장하여 공간을 낭비할 수도 있다 • 가장 최근에 요청한 입출력 접근이 이전과 비교해 순차적이지 않다면 미리 읽기를 중단한다 • 파일 객체의 f_reada필드는 파일에 대해 미리 읽기를 활성화 하면 1로 설정하고 그렇지 않으면 0인 플래그 이다. • 미리 읽을 바이트 수인 read_ahead테이블에 저장한다 • 0값은 기본 값 값인 512바이트 섹터 8개(4KB)

  46. 블록 장치 처리 • block_read()와 black_write()함수 • 프로세스가 장치 파일에 대해 읽기나 쓰기 연산을 요청할 때 • 고 수준 장치 드라이버에서 호출 • 매개변수 • Flip : 장치 파일과 관련한 파일 객체 주소 • Buf : 사용자 모드 주소 공간에 있는 메모리 영역 주소 • block_read()는 블록 장치에서 읽은 데이터를 이 메모리 영역에 쓴다 • block_write()는 반대로 이 메모리 영역에서 블록 장치에 쓸 데이터를 읽는다 • count : 전송할 바이트 수

  47. 블록 장치 처리 • ppos : 장치 파일 오프셋을 포함한 변수 주소(flip->f_pos) • flip->f_dentry->d_inode->i_rdev로 부터 블록 장치의 주 번호와 부 번호 획득 • blksize_size에서 장치 파일의 블록 크기를 얻는다. • *ppos와 블록 크기를 사용하여 장치에서 읽어올 첫째 블록의 연속 번호를 계산이 블록 내부에서 읽어야 하는 첫째 바이트 오프셋도 계산 • 블록 하드웨어 장치 크기를 얻는다(blk_size에 값 저장)장치 파일의 주 번호와 부 번호로 참조하며, 1024바이트 단위필요시 count를 변경하여 장치의 끝을 지나면 읽기 연산을 수행하지 못하게한다 • 장치에서 읽을 블록 수를 count, 블록 크기, 첫째 블록 안의 오프셋 등으로 계산filp->f_reada를 설정했다면, read_ahead 테이블에 지정된 미리 읽을 블록 수도 함께 고려 • 읽고자 하는 각 블록에 대해 다음 연산을 수행 • getblk()함수를 사용하여 버퍼 캐시에서 블록을 찾아본다그렇지 않으면 새로운 버퍼가 할당하여 캐시에 삽입 • 버퍼에 유요한 데이터를 포함하지 않으면 ll_rw_block() 함수로 읽기 연산 시작현재 프로세스는 데이터를 버퍼에 전송할때까지 보류 • 프로세스가 블록을 요청했다면, 즉 미리읽기로 읽지 않았다면, 버퍼 내용을 buf가 가리키는 사용자 메모리 영역에 복사 • *ppos에 사용자 메모리 영역에 복사한 바이트 수를 더한다

  48. 블록 장치 처리 8. Flip->f_reada 플래그를 1로 설정하여 다음 번에 미리 읽기 메커니즘을 사용할 수 있게 한다 9. 사용자 메모리 영역에 복사한 바이트 수를 반환 • block_write()함수와 block_read()함수의 차이 • Write연산을 시작하기 전에 block_write()함수는 블록 하드웨어 장치가 읽기 전용이 아닌지 반드시 검사하고 읽기 전용인 경우 에러코드를 반환 • block_write() 함수는 첫째 블록 안에 기록할 첫째 바이트 오프셋을 검사해야 한다. 오프셋이 0이 아니고, 이미 버퍼 캐시에 첫째 블록에 대한 유효 데이터가 없다면, 함수는 기록하기 전에 디스크에서 블록을 읽어야 한다 • Block_write() 함수는 디스크에 기록하기 위해 반드시 ll_rw_block()을 호출하지는 않는다

  49. 블록 장치 처리 • bread()와 breada()함수 • bread() • 특정한 블록이 버퍼 캐시에 있는지 검사하고, 없다면 블록 장치에서 블록을 읽는다 • 파일시스템은 디스크에서 비트맵, 아이노드, 다른 블록 기반의 자료 구조를 읽기 위해 광범위하게 사용(프로세스가 블록 장치 파일을 읽을경우 block_read()사용) • 장치 식별자, 블록 번호, 블록 크기를 매개변수로 받아들여 다음 연산을 수행 • getblk()함수를 호출하여 버퍼 캐시에서 블록을 찾고, 없다면 getblk()는 새로운 버퍼를 할당 • 버퍼에 최신 데이터가 있으면, 함수를 마친다 • ll_rw_block()을 호출하여 읽기 연산을 시작 • wait_on_buffer()라는 함수를 호출하여 데이터 전송이 끝날 때까지 기다린다current 프로세스를 b_wait 대기큐에 넣고, 버퍼가 락에서 풀릴 때까지 보류 • breada() • 요청한 블록에 추가하여 블록 몇 개를 미리 읽는다 • 디스크에 어떤 블록을 직접 쓰는 함수는 없다(쓰기연산은 언제나 뒤로 연기)

  50. 블록 장치 처리 • 버퍼 헤드 • 각 버퍼와 관련한 buffer_head 유형 디스크립터 • 커널은 각 버퍼에 대해 처리하기 전에 버퍼헤드를 검사 • b_data 필드에는 해당 버퍼의 시작 주소를 저장 • b_this_page는 페이지 내 다음 버퍼의 버퍼 헤드를 가리킨다 • 전체 페이지 프레임을 저장하고 검색하는데 쓰인다 • b_blocknr는 논리적 블록 번호, 즉 디스크 파티션 내의 블록 인덱스를 저장 • b_dev필드가 가상 장치를 나타내는 반면 b_rdev 필드는 실제 장치를 나타낸다. RAID 스토리지를 나타내기 위해 도입 • b_blocknr로 논리적인 블록 번호를, b_rdev로 특정 디스크 유닛을, b_rsector로 대응하는 섹터 번호를 나타낸다

More Related