# 요청 큐: 대기 중인 작업이 장치에서 진행 중인 작업이 될 때

v6.18.37 / block/blk-mq.c

파일시스템이 만든 bio는 장치가 처리할 request로 묶일 수 있습니다. request_queue는 그 장치의 요청 처리 규칙을 제공하며 blk-mq는 소프트웨어 쪽 요청을 하드웨어 큐로 연결합니다. 여기서는 드라이버가 요청을 시작할 때 부르는 blk_mq_start_request를 통해 태그, 시간 제한, 진행 상태가 왜 필요한지 살펴봅니다.

## blk_mq_start_request

```c

void blk_mq_start_request(struct request *rq)
{
	struct request_queue *q = rq->q;

	trace_block_rq_issue(rq);

	if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags) &&
	    !blk_rq_is_passthrough(rq)) {
		rq->io_start_time_ns = blk_time_get_ns();
		rq->stats_sectors = blk_rq_sectors(rq);
		rq->rq_flags |= RQF_STATS;
		rq_qos_issue(q, rq);
	}

	WARN_ON_ONCE(blk_mq_rq_state(rq) != MQ_RQ_IDLE);

	blk_add_timer(rq);
	WRITE_ONCE(rq->state, MQ_RQ_IN_FLIGHT);
	rq->mq_hctx->tags->rqs[rq->tag] = rq;

	if (blk_integrity_rq(rq) && req_op(rq) == REQ_OP_WRITE)
		blk_integrity_prepare(rq);

	if (rq->bio && rq->bio->bi_opf & REQ_POLLED)
	        WRITE_ONCE(rq->bio->bi_cookie, rq->mq_hctx->queue_num);
}

```

### 1351행

```c

void blk_mq_start_request(struct request *rq)

```

시작할 request를 받습니다. 드라이버가 장치 처리를 시작하는 경계에서 호출합니다.

### 1353행

```c

	struct request_queue *q = rq->q;

```

요청이 소속된 request_queue를 지역변수로 꺼내 통계와 서비스 품질 처리를 연결합니다.

### 1355행

```c

	trace_block_rq_issue(rq);

```

요청 발행 추적 이벤트를 남깁니다. 이 기록은 완료 이벤트와 구분됩니다.

### 1357행

```c

	if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags) &&

```

이 큐가 통계를 수집하도록 설정되어 있는지 검사합니다.

### 1358행

```c

	    !blk_rq_is_passthrough(rq)) {

```

일반 데이터 I/O 통계를 적용하기 어려운 통과 명령은 제외합니다. 두 조건을 모두 만족해야 본문을 실행합니다.

### 1359행

```c

		rq->io_start_time_ns = blk_time_get_ns();

```

I/O 시작 시각을 나노초 단위로 기록해 이후 지연 시간을 계산할 기준을 만듭니다.

### 1360행

```c

		rq->stats_sectors = blk_rq_sectors(rq);

```

통계에 사용할 요청 크기를 섹터 수로 저장합니다.

### 1361행

```c

		rq->rq_flags |= RQF_STATS;

```

이 요청에 통계 자료가 준비됐다는 RQF_STATS 비트를 켭니다.

### 1362행

```c

		rq_qos_issue(q, rq);

```

큐의 서비스 품질 제어 계층에 요청이 발행됐음을 알립니다.

### 1365행

```c

	WARN_ON_ONCE(blk_mq_rq_state(rq) != MQ_RQ_IDLE);

```

시작 전에 IDLE이어야 한다는 상태 규칙이 깨졌으면 한 번 경고합니다. 경고가 요청을 자동으로 취소하는 것은 아닙니다.

### 1367행

```c

	blk_add_timer(rq);

```

요청의 시간 제한을 감시할 타이머를 준비합니다.

### 1368행

```c

	WRITE_ONCE(rq->state, MQ_RQ_IN_FLIGHT);

```

상태를 MQ_RQ_IN_FLIGHT로 기록합니다. WRITE_ONCE는 이 필드 접근이 임의로 합쳐지거나 나뉘는 것을 제한합니다.

### 1369행

```c

	rq->mq_hctx->tags->rqs[rq->tag] = rq;

```

하드웨어 큐의 태그 표에서 rq->tag 항목이 이 request를 가리키게 합니다.

### 1371행

```c

	if (blk_integrity_rq(rq) && req_op(rq) == REQ_OP_WRITE)

```

무결성 보호 대상이면서 쓰기 요청인지 함께 검사합니다.

### 1372행

```c

		blk_integrity_prepare(rq);

```

쓰기에 필요한 무결성 처리를 준비합니다. 일반 읽기에는 이 분기가 적용되지 않습니다.

### 1374행

```c

	if (rq->bio && rq->bio->bi_opf & REQ_POLLED)

```

연결된 bio가 있으며 REQ_POLLED가 켜진 요청인지 확인합니다.

### 1375행

```c

	        WRITE_ONCE(rq->bio->bi_cookie, rq->mq_hctx->queue_num);

```

폴링할 하드웨어 큐 번호를 bio의 cookie에 기록합니다. cookie는 저장장치 주소가 아닙니다.

