본문 바로가기

리눅스 커널/블록 멀티 큐

NVMe device driver code tuning & comments - 1

구현한 NVMe device driver 구조.

nvme device driver 관련된 자료구조중 nvme_queue 구조체가 3개의 SQ를 갖게한다.

3개의 SQ는 아래와 같은데,

1. Read Only SQ

2. Write Only SQ

3. Urgent SQ

 

NVMe SSD가 WRR을 지원하면, 생성할 SQ의 Weight를 설정하여 IO의 차별적인 서비스 제공이 가능해진다.

여기서는 좀 극단적으로 Write에는 2, Read에는 8이라는 weight를 주어 응답성과 관련된 read연산의 성능을 향상 시키는 것을 목표로 하였고,

더 나아가 Urgent SQ를 두어 우선순위가 높은 프로세스의 IO는 이보다 더 빨리 처리되도록 구현하였다.

이는 아래와 같은 스케줄링을 NVMe SSD가 하기 때문이다.

qid == 0인 관리자 큐의 IO는 일반적인 IO와 다른 IO를 처리하기 때문에 제일 높은 우선순위를 갖는다.

해당 연산에는 장치와 직접적으로 관련된 IO로 CQ, SQ 생성 과 같은 device driver 초기화 시 nvme ssd에 명령어를 전달한다.

 

다음은 위 구조를 구현하는데 필요한 자료구조에 대한 설명이다.

struct nvme_dev {
	...

	//the number of each nvme_queue has maximum extra SQ
	u16 extra_nr;
};

추가한 extra_nr 은 nvme_dev 밑에 있는 nvme_queue구조체가 가질 수 있는 최대 SQ 개수를 의미한다.

NVMe SSD가 지원하는 SQ의 개수는 직접 명령어를 날려 알 수 있으며, 그 코드는 nvme device driver를 초기화 하는 과정에서 살펴볼 수 있다.

 

struct nvme_queue {
	...

	u16 size;
	//extra submission queue
	/*struct nvme_command * sq_cmds_extra;
	struct nvme_command __iomem * sq_cmds_io_extra;
	dma_addr_t sq_dma_addr_extra;
	u16 sq_tail_extra;
	u16 qid_extra;
	u32 * dbbuf_sq_db_extra;
	u32 * dbbuf_sq_ei_extra;
	u32 __iomem * q_db_extra;
	*/

	u16 extra_cnt;
	u16 extra_cursor;
	struct extra_queue ** extra_list;
};

extra_cnt는 해당 nvme_queue 가 실제로 갖고 있는 SQ의 전체 개수를 말하며, 

각 SQ는 포인터 배열로 접근 할 수 있다.

struct extra_queue
{
	struct nvme_command * sq_cmds_extra;
	struct nvme_command __iomem * sq_cmds_io_extra;
	dma_addr_t sq_dma_addr_extra;
	u32 __iomem * q_db_extra;
	u16 sq_tail_extra;
	u16 qid_extra;
	u16 size;
	u32 * dbbuf_sq_db_extra;
	u32 * dbbuf_sq_ei_extra;
};

여기서 SQ를 구현하는데 실질적으로 중요한 부분은

sq_cmds_extra

sq_dma_addr_extra

q_db_extra : 이 레지스터 값을 업데이트 하여 nvme ssd에 io가 있다는 사실을 알린다.

qid_extra 

sq_tail_extra

 

이다.

 

이외의 변수들은 실제로 사용하지는 않지만 기존 nvme_queue내 SQ와 최대한 유사한 구조를 갖도록 하였다.