본문 바로가기

리눅스 커널/블록 멀티 큐

NVMe device driver code tuning & comments - 5

작성한 커널 코드를 정리하던 중에 디버깅용으로 작성한 코드 중 SQ의 쌓인 entry 개수를 측정하는 함수가 있었다.

여기서는 이와 관련된 것을 정리하겠다.

 

SQ의 entry가 증가하는 경우는

__nvme_submit_cmd()와 __nvme_submit_cmd_extra()를 참조하면 된다.

해당 함수에서 size를 1 증가시키는 코드의 주석을 해제하면 된다.

static void __nvme_submit_cmd(struct nvme_queue *nvmeq,
                                                struct nvme_command *cmd)
{
        u16 tail = nvmeq->sq_tail;

        if (nvmeq->sq_cmds_io)
                memcpy_toio(&nvmeq->sq_cmds_io[tail], cmd, sizeof(*cmd));
        else
                memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd));

        if (++tail == nvmeq->q_depth)
                tail = 0;
        if (nvme_dbbuf_update_and_check_event(tail, nvmeq->dbbuf_sq_db,
                                              nvmeq->dbbuf_sq_ei))
                writel(tail, nvmeq->q_db);

        //if (nvmeq->qid)
                //nvmeq->size += 1;

        nvmeq->sq_tail = tail;

관리자 큐를 제외한 IO를 위한 SQ일 때에 만 동작한다.

더 중요한 건 entry를 감소시킬 때이다.

static void nvme_process_cq(struct nvme_queue *nvmeq)
{
        struct nvme_completion cqe;
        int consumed = 0;

        while (nvme_read_cqe(nvmeq, &cqe)) {
                nvme_handle_cqe(nvmeq, &cqe);
                consumed++;
                //if (nvmeq->cqe_seen && cqe.sq_id)
                        //nvme_queue_size_update(nvmeq, cqe.sq_id);
        }

        if (consumed)
                nvme_ring_cq_doorbell(nvmeq);
}

위 함수는 io가 끝났을 때 인터럽트 문맥에서 호출되는 함수이다.

여기서 주석처리된 부분에 대한 설명을 하자면,

io가 처리되었고 관리자 큐가 아닌 경우면 sq의 entry개수를 줄이는 함수를 호출한다.

static inline void nvme_queue_size_update(struct nvme_queue * nvmeq, u16 sq_id)
{
        int max = nvmeq->dev->online_queues - 1;
        sq_id -= 1;

        if (sq_id < max)
                nvmeq->size -= 1;
        else
                nvmeq->extra_list[(sq_id / max) - 1]->size -= 1;

        /*if (size)
        {
                --(*size);
                printk("extra, %s, qid(%d), size: %d\n", current->comm, sq_id, *size);
        }*/
}

max는 원래 커널이 생성하는 IO를 위한 SQ개수를 의미한다.

코어가 6개인 경우 그 개수는 6이나 online_queues는 관리자 큐 개수로 인해 7이 된다.

그래서 1을 빼는 것이다.

 

그리고 qid를 적절히 보정 한 후 해당 SQ에 접근해서 size를 1감소시키는데,

 

[01] [02] [03] [04] [05] [06]

[07] [08] [09] [10] [11] [12]

[13] [14] [15] [16] [17] [18]

 

첫번째 행에 있는 것들은 원래 커널이 만들어내는 큐들의 id이다.

그리고 각 열은 1번 코어가 갖고 있는 SQ의 id들을 나타낸다.

그리고 __nvme_submit_cmd_extra()에 의해 증가된 size를 줄이기 위해서는 

extra_list에 각 sq_id에 적합한 인덱스를 통해 접근해야 된다.

 

그런데 (12 / 6) - 1을 해주면 그 인덱스가 1이 나온다. 잘못된 sq에 접근하고 있는 것 이다.

그래서 이러한 점을 막기 위해 값을 보정하여 계산한다.

아래와 같은 형식으로 만드는 것이다.

 

[00] [01] [02] [03] [04] [05]

[06] [07] [08] [09] [10] [11]

[12] [13] [14] [15] [16] [17]