300x250


블록 디바이스 드라이버.pptx


08. 블록 디바이스 드라이버


0. 개요

블록 디바이스 드라이버
리눅스에서 지원하는 세가지 핵심 디바이스 드라이버 중 하나
문자
블록
네트워크
하드디스크와 같은 저장 디바이스
블록단위의 입출력
일반적으로 마운트를 통해 파일시스템을 구현하는 시스템으로
사용 됨
요구 큐라는 request_queue_t 구조체를 이용해 입출력

2.4일때와 2.6일때가 전혀 다름 => 스케줄러의 향상


1. 리눅스와 블록 디바이스
하드디스크와 디바이스 파일
윈도우의 표현 방법
하나의 파티션으로 구성됨
C:, D:
물리적인 하드디스크를 표현하는 방법이 없음.
리눅스의 표현 방법
하나의 디바이스 파일로 취급
/dev/hda
/dev/hdb
디바이스 파일에 파티션을 분할
/dev/hda1
/dev/hda2
    
 •문자 드라이버와 차이점



2. 하드 디스크의 특성
하드디스크의 데이터 처리 방식
하드디스크에 데이터를 읽거나 쓰기 위해 드라이버에 명령을 줌
인터럽트로 요구된 처리가 끝났는지 확인함
쓰기
디스크 드라이버가 하드디스크에 쓰기 명령과 함께 쓸 데이터를 전달
커널에서 논리적인 섹터 번호와 써 넣을 데이터의 주소가 전달 됨
디바이스 드라이버가 실제 섹터 위치를 지정하는 값으로 변환
쓰기 완료 후 드라이버의 인터럽트 서비스 함수가 커널에 인터럽트를 발생 시킴
읽기
드라이버가 디스크에게 데이터 읽기 명령 전달
섹터 번호와 읽어올 데이터를 넣을 주소.
완료 후 인터럽트 발생

하드디스크의 데이터 처리 방식
특정 섹터를 읽은 다음 다른 섹터를 읽으려면 최소한 한바퀴의 디스크 회전이 필요.
미리 읽기
읽을 섹터를 기준으로 여분의 섹터를 더 읽음
장점
이전에 읽은 데이터를 응용에서 요구하면 디스크 접근 없이 버퍼에서 바로 읽을 수 있음.
클러스터
섹터가 아닌 클러스터 단위로 처리하는 것
e.g. 두개의 섹터를 하나의 클러스터 단위로 처리.
장점
미리 읽기시 여분의 읽기 섹터 수를 고정 처리하는 효과가 있음


3. 블록 디바이스 드라이버와 요구 큐
호출 주체에 따른 입출력 처리
호출 주체에 따라 두 가지로 나뉨
1.외부에서 블록 디바이스에 직접 접근
응용에서 디스크의 내용을 읽거나 쓸 수 있도록 드라이버에게 직접 요구
->
드라이버에서 수행
e.g.
fdisk 같은 파티션 분할 프로그램
2.블록 디바이스를 응용 프로그램에서 간접 접근
1.응용이 파일에 읽기/쓰기를 수행
2.파일 시스템에서 드라이버에 읽기/쓰기 요청
3.디바이스가 읽기/쓰기 수행


문자 드라이버와의 처리 방식의 차이점
문자 드라이버
응용에서 읽기를 시도하면 file_operationread() 함수에서 처리
블록 드라이버
응용 프로그램의 읽기에 대응하는 read()함수가 없음.

읽기 루틴 구현의 필요성

문자 드라이버와의 처리 방식의 차이점
블록 드라이버에서 읽기 요청
1.응용 프로그램에서 read 요청
2.커널이 커널 내부 버퍼에 있는지 살펴봄
3.있으면 전달, 없으면 드라이버에 요청

커널은 디바이스를 효율적으로 처리하기 위해 처리할 내용을 큐에 모아 둠
일정 시간이 지나거나 임계치에 도달하면 드라이버에 처리를 요구

커널과 드라이버간의 전달은 요구 큐와 처리 함수를 이용

문자 드라이버와 다른 점임.


4. 버전별 블록 디바이스 처리

새로운 입출력 스케줄러
읽기 요청을 우선 처리
엔터프라이즈 환경에서 읽기가 더 발생
요구 큐의 데드라인 도입



bio 구조체
진행중인 블록 IO 연산에 대한 직관적인 인터페이스 제공
블록 IO 요청이 bio 구조체로 표시됨
요청에 있는 각 블록이 bio_vec 이라는 구조체에 저장되어 배열로 관리됨
bio_vec은  <page, offset, len>과 같은 형식으로 표현 되면서 하나의 IO 연산을 나타냄.

5. 커널 2.6의 블록 디바이스 드라이버

블록 디바이스 드라이버 작성 요구 사항
블록 디바이스의 특성 정의
주 번호와 부 번호 및 디바이스명에 대한 정의
블록 디바이스 드라이버 등록
블록 디바이스 드라이버를 위한 구조체 선언
파일 오퍼레이션 구조체 처리
요구 큐에 관련된 처리 및 함수 선언
블록 디바이스 추가를 위한 gendisk 구조체 생성 및 등록

블록 디바이스의 크기 설정 및 기타 속성 처리

블록 디바이스 드라이버 등록과 해제
등록
모듈 초기화 함수
커널에 의해 호출 되는 초기화 함수
register_blkdev()
인자 : 주번호, 디바이스 이름
해제
unregister_blkdev()

인자 : 주 번호, 디바이스 이름

블록 디바이스 드라이버를 위한 구조체 선언
블록 디바이스 드라이버를 다루기 위한 내용
1.request_queue 구조체 변수
요구 처리를 위해
2.gendisk 구조체 변수
블록 디바이스 처리를 위해
3.spinlock_t 구조체 변수
request 방식을 사용할 경우 필요함

4.블록 디바이스를 위한 자체적인 정보 변수

typedef struct

{

void *priv; //자체 정보 관리 주소변수

struct request_queue *queue;

spinlock_t lock;

struct gendisk *gd;

} xxx_device;


struct block_device_operations
블록 디바이스가 동작하기 위해서는 위 구조체를 이용해 동작을 위한 기본
함수들을 등록 해야함.
이 구조체는 gendisk 구조체의 fops 필드에 등록 됨.

add_disk() 함수에 의해 gendisk 구조체가 등록될 때 함께 등록 됨.



struct block_device_operations
메소드
struct module *owner;
파일 오퍼레이션의 소유자
open/release
디바이스가 마운트/언마운트 될 때 호출 됨.
모듈 카운트 관리
ioctl
(struct inode *inode, struct file *filp, unsigned int cmd, unsigned log arg)
인자 cmd에 들어갈 항목
BLKGETSIZE – 섹터 수로 표현되는 블록 디바이스의 크기를 응용에 전달.
BLKFLSBUF – 드라이버 내부에 저장된 버퍼의 내용을 실제 디바이스에 모두 써 넣기
BLKRAGET – 응용에서 디바이스에 설정되어 있는 읽기 값을 미리 얻어 옴
BLKRASET – 디바이스의 미리 읽기 값을 설정
BLKRRPART – 디바이스의 파티션 테이블을 다시 읽기 요청함

HDIO_GETGEO – 디바이스의 특성을 디스크 구조에 대한 형태로 응용에 제공

struct block_device_operations
메소드
media_changed
CD-ROM 처럼 제거 할 수 있는 디바이스를 다루기 위해 주기적으로 호출해 검사 함.
이를 구현 하면 revalidate_disk를 필수로 선언해야 함
revalidate_disk

디바이스가 교체 되었다면 디바이스 상태를 재설정 해야함.

요구 큐 관련 처리 및 함수
make_request 방식
램디스크, loop
request 방식
대부분의 경우



make_requst 방식
bio 구조체를 사용 하여 처리

블록 디바이스에 읽기나 쓰기 발생
->
커널이 make_request() 함수를 호출해 처리를 요구함

static int xxx_make_request(request_queue_t *q, struct bio *bio)
{
struct bio_vec *bvec;
: //
요구 유효성 검사 처리


bio_for_each_segment(bvec, bio, i)
{
: //
요구 처리
}


bio_endio(bio, bio->bi_size, 0); //
처리 종료
return 0
;


fail :bio_IO_error(bio, bio->bi_size);
return 0;
}

bio 구조체 중요 변수
bio->bi_bdev->bd_disk->private_data
디바이스 관리를 위한 구조체 메모리 주소
bio_data_dir(bio): 처리 방향
bio->bi_sector : 논리적 시작 섹터 번호

bio->bi_size : 처리해야 할 총 데이터 크기

request 방식
대부분의 블록 디바이스의 경우 request를 이용하여 처리
elv_next_request() 함수로 처리할 구조체가 없을때 종료


static void xxx_request(request_queue_t *q)
{
struct
request *xxx_req

while(1)

{

  xxx_req = elv_next_request(q);

  if(!xxx_req) return ;

  : //처리 루틴

  if(처리 성공) end_request(xxx_req, 1);

  else    end_request(xxx_req, 0);

}

}

request 구조체 중요 변수
xxx_req -> rq_disk->private_data
:
디바이스를 관리하기 위해 할당한 메모리 주소
xxx_req -> sector : 처리해야 할 논리적 섹터번호
xxx_req ->current_nr_sectors : 처리해야 하는 섹터 수

xxx_req -> buffer : 읽기나 쓰기를 처리할 데이터의 선두 주소
기타 처리 함수
get_capacity(xxx_req -> rq_disk)
처리중인 디바이스의 용량을 구함.
request 함수 초기에 처리 요구 범위가 디바이스의 크기를
넘는지 검사
rq_data_dir(xxx_req)

처리 방향을 얻음

gendisk 구조체 생성 및 등록
커널 2.6에서 드라이버가 디바이스를 처리하기 위해서는 add_disk() 함수를 이용해 등록
for(lp =0; lp<XXX_MAX_DEVICE; lp++)
{
device[lp].gd = alloc_disk(XXX_MAX_PARTITIONS);

device[lp].gd->major = XXX_DEV_MAJOR;
device[lp].gd->fops = &vhdd_fops;
device[lp].gd->queue = device[lp].queue;
device[lp].gd->private_data = &device[lp];
sprintf(device[lp].gd->disk_name, “vhdd%c”. ‘a’+lp);
set_capacity(device[lp].gd, XXX_SECTOR_TOTAL);

add_disk(device[lp].gd);
}

add_diskgendisk 구조체 변수를 이용해 디바이스의 정보를 커널에 등록


gendisk 구조체 생성 및 등록
gendisk 구조체를 이용해 디바이스를 등록하고 제거할 때 사용하는 함수
alloc_disk : gendisk 구조체 생성
add_disk : 등록
del_gendisk : 제거

put_disk : 구조체 소멸

gendisk 구조체 생성 및 등록
add_disk 이용전 gendisk 구조체 할당과 필드 설정 필요
#include <linux/genhd.h>에 선언 되어 있음
alloc_disk() 함수에서 초기화 됨
드라이버가 추가적으로 초기화 해야 하는 필드
int major ::주번호
int first_minor ::부 번호
struct block_device_operations *fops:: 블록 파일 오퍼레이션 구조체 변수 주소
struct request_queue *queue :: 디바이스 요구 처리를 위한 변수 주소
char disk_name[16] :: 디바이스 이름
/proc/partition에 나타남
int flags :: 디바이스의 특성
cd-rom 이나 removable 디바이스

void *private_data :: 정보 처리를 위한 변수 주소 (request() 함수에서 구할 수 있음)

gendisk 구조체 할당과 해제
gendisk 구조체 변수를 할당하고 해제
할당
struct gendisk *alloc_disk(int minors)
해제

void put_disk(struct gendisk *disk)

gendisk 구조체 등록과 해제
gendisk 구조체를 커널에 등록하고 해제
등록
void add_disk(struct gendisk *disk)
해제

void del_gendisk(struct gendisk *gp)

블록 디바이스의 크기 설정
커널에 등록하기 전 디바이스의 크기를 설정 해야 함

void set_capacity(struct gendisk *disk, sector_t size)

블록 디바이스 제거
대부분의 블록 디바이스 드라이버는 커널이 부팅 될 때 등록 됨
만약 드라이버 모듈을 제거할 때는 다음 순서를 거쳐야 함
1.del_gendisk()를 이용하여 제거
2.alloc_disk()로 할당한 메모리를 put_disk()로 해제
3.등록된 요구 큐를 blk_cleanup_queue()로 커널에서 제거

4.등록된 디바이스를 unregister_blkdev()를 이용해 제거



참고 : [IT EXPERT 리눅스 디바이스 드라이버]

반응형

+ Recent posts