Linux kernel v4.4에서 간단한 블록 장치 드라이버 만들어보기

SOFTIRQ에서 request 처리

소스: https://github.com/gurugio/mybrd/blob/ch04-request-mode-softirq/mybrd.c

irqmode라는걸 추가할 수 있는데 한번 만들어보겠습니다. 이전에는 커널이 호출한 즉시 request들을 처리했습니다. 예를들어서 진짜 하드디스크의 드라이버라면 디스크에서 이전 데이터의 처리가 끝났다는 인터럽트가 발생할때마다 새로운 request를 처리할 것입니다. 그런데 이렇게 인터럽트가 발생했을 때마다 request를 처리하는게 좋지만은 않습니다. request 처리를 인터럽트 핸들러에서 구현하려면 프로세스가 잠들어서도 안되고, 그러다보니 메모리 할당도 까다로워지는 등 여러가지 불편한점들이 많습니다.

따라서 이런 request 처리를 잠시 미뤘다가 하는 방법도 있습니다. 커널이 제공하는 softirq라는 지연 처리 메커니즘이 있고 이걸 활용해서 request 처리를 하는 방법입니다.

softirq 자체에 대해서는 다음 문서를 참고하시기 바랍니다.

https://lwn.net/Articles/520076/

우리는 실제 코드를 보면서 이해해보겠습니다.

blk_complete_request()

blk_cpu_done이라는 per-cpu 리스트가 있습니다. 드라이버에서 blk_complete_request()를 호출하면 해당 request를 blk_cpu_done 리스트에 추가해놓고 request_fn 함수를 종료합니다. 

blk_cpu_done이라는게 뭔지 blk_cpu_done으로 코드를 검색해보면 blk_softirq_init() 함수에 리스트를 초기화하는게 보입니다. blk_softirq_init()함수는 blk_cpu_done 리스트를 만들고, BLOCK_SOFTIRQ를 등록합니다.

그러면 나중에 softirq가 실행될 때 BLOCK_SOFTIRQ로 등록된 blk_done_softirq() 함수가 호출되고, blk_cpu_done 리스트에서 request를 꺼내서 큐에 있는 softirq_done_fn 함수를 호출합니다. 결국 이런 과정을 거쳐서 mybrd_softirq_done_fn() 함수가 호출되는 것입니다.

mybrd_softirq_done_fn()

어짜피 하나의 request를 처리해야하는건 mybrd_request_fn과 동일합니다. mybrd_request_fn()에서 했듯이 _mybrd_request_fn()을 호출해서 IO를 처리합니다.

차이가 있다면 request의 queuelist를 초기화해서 큐로부터 request를 분리하는 것 뿐입니다. request 처리가 완료되었을 때 blk_end_request_all()을 호출하는 것도 mybrd_request_fn()과 동일합니다.

 

댓글

댓글 본문
작성자
비밀번호
버전 관리
gurugio
현재 버전
선택 버전
graphittie 자세히 보기