본문 바로가기

리눅스 커널/블록 멀티 큐

blk_mq_alloc_tag_set 흐름

이 함수는 nvme_reset_work() 에서 nvme_alloc_admin_tags() 에서도 호출된다. 그러나 이 때에는 관리자 큐를 위한 tagset 및 tags를 할당하기 위한 것이나 그 흐름은 거의 유사하다.

 

nvme_dev_add(struct nvme_dev * dev) from nvme_reset_work
	
    ->dev->tagset.ops = &nvme_mq_ops;
    ->dev->tagset.nr_hw_queues = dev->online_queues - 1;
    ->dev->tagset.queue_depth = min_t(int, dev->q_depth, BLK_MQ_MAX_DEPTH) - 1;
    ->dev->tagset.driver_data = dev;
    ->blk_mq_alloc_tag_set(&dev->tagset);
        ->...
    ->dev->ctrl.tagset = &dev->tagset;
    ->nvme_dbbuf_set(dev);
        ->nvme_submit_sync_cmd(...);
        
blk_mq_alloc_tag_set(struct blk_mq_tag_set * set) from nvme_dev_add
	
    ->set->tags = kzalloc_node(nr_cpu_ids * sizeof(struct blk_mq_tags *), ...);
    ->set->mq_map = kzalloc_node(sizeof(*set->mq_map) * nr_cpu_ids, ...);
    ->blk_mq_updated_queue_map(set);
        ->set->ops->map_queues(set); //nvme_pci_map_queues()
    ->blk_mq_alloc_rq_maps(set);
        ->__blk_mq_alloc_rq_maps(set);
            ->for (0 to set->nr_hw_queues)
                ->__blk_mq_alloc_rq_map(set, i);
                    ->set->tags[hctx_idx] = blk_mq_alloc_rq_map(...);
                        ->tags = blk_mq_init_tags(...);
                        ->tags->rqs = kzalloc_node(nr_tags * sizeof(struct request *), ...);
                        ->tags->static_rqs = kzalloc_node(nr_tags * sizeof(struct request *), ...);
                    ->blk_mq_alloc_rqs(...);
                        ->for (0 to depth)
                            ->p = page_address(page);
                            ->struct request * rq = p;
                            ->tags->static_rqs[i] = rq;
                            ->set->ops->init_request(...); //nvme_init_request
                        ->if fail, return -ENOMEM;
            ->return 0;

1. nvme_dev_add() 에서 blk_mq_alloc_tag_set()을 호출하기 전에 먼저 기본적인 작업을 준비한다.

2. tags를 위한 blk_mq_tags 포인터 배열을 준비한다. 그 길이는 cpu개수 만큼이다.

3. sw 큐와 hw 큐간 매핑정보를 저장할 배열을 위한 메모리를 준비한다.

4. nvme_pci_map_queues()를 이용하여 큐 들간 매핑된 정보를 저장한다.

5. tags배열의 각 tags를 위한 메모리를 할당하고, 초기화한다.

6. request pool을 준비한다.

7. tags를 위한 초기화가 하나라도 실패하면 blk_mq_alloc_rq_maps()에서 queue_depth를 절반으로 줄여 다시 진행하게 되는데, 그 queue_depth 가 0이 되어버리면, 더 이상 진행하지 못하고 nvme device driver 초기화는 실패하게 된다.



'리눅스 커널 > 블록 멀티 큐' 카테고리의 다른 글

urgent queue 를 위한 tag 예약  (0) 2021.10.26
blk_mq_init_queue  (0) 2021.10.26
nvme command 관련 추가 내용  (0) 2021.10.26
nvme command  (0) 2021.10.26
nvme_setup_io_queues 흐름  (0) 2021.10.26