Linux v6.6 · 개념과 코드 읽기

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

이 코드는 어떤 문제를 푸나요?

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

읽을 범위: v6.6 · block/blk-mq.c · blk_mq_start_request 1245–1269행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.

먼저 알아둘 개념

request

장치에 전달하고 완료를 추적하는 블록 계층의 작업 단위입니다. 하나의 request가 여러 bio를 포함할 수 있으므로 bio와 일대일이라고 단정할 수 없습니다.

태그

진행 중인 요청을 찾는 데 사용하는 정수 식별자입니다. 완료 통지가 태그로 돌아오면 이를 request 포인터로 연결합니다. 태그는 디스크의 섹터 번호가 아닙니다.

시간 제한

장치가 영원히 응답하지 않는 상황에 대비해 요청 시작 시 타이머를 준비합니다. 제한을 넘겼다는 사실과 최종 복구 정책은 별개입니다.

처음 읽을 때

대기열에 들어간 시점과 실제 요청을 시작한 시점을 구분하십시오. 이 함수는 두 번째 시점의 상태와 계측을 준비하며, 데이터가 이미 저장됐다는 뜻은 아닙니다.

더 깊이 살펴볼 때

WRITE_ONCE만으로 모든 필드의 메모리 순서를 보장한다고 해석하지 마십시오. 이 v6.6 본문은 통계 플래그만으로 시작 시각을 기록하며 태그 표 등록을 직접 수행하지 않습니다. 요청 할당과 완료 경로의 태그 수명, 큐 잠금과 함께 읽어야 합니다.

그림으로 보는 변화

요청 큐: 대기 중인 작업이 장치에서 진행 중인 작업이 될 때의 단계별 개념 그림
각 단계에 화살표 의미와 생략 범위를 표시했습니다. 주소·숫자 예제는 실제 장치 값을 뜻하지 않습니다.
1단계 설명

1단계 고정

GIF 원본 열기

1. 요청이 준비됩니다

request는 bio와 장치 큐를 참조하며 아직 완료되지 않은 작업을 나타냅니다.

화살표는 bio가 request로 묶여 전달되는 관계입니다.

2. 시작을 기록합니다

시작 시각과 시간 제한을 준비하고 상태를 IN_FLIGHT로 바꿉니다. 이 함수 밖에서 마련된 태그 관계로 이후 완료를 추적합니다.

화살표는 대기 상태에서 진행 상태로 바뀌는 순서입니다. 이 v6.6 함수가 태그 표에 새 항목을 넣는다는 뜻은 아닙니다.

3. 완료할 요청을 찾습니다

장치 완료 경로는 태그 등의 정보로 원래 request를 찾아 완료를 이어갑니다.

화살표는 식별자로 객체를 찾는 방향입니다. 이 마지막 단계는 별도의 완료 경로에서 실행됩니다.

blk_mq_start_request를 한 줄씩 읽기

줄 번호는 v6.6 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.

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)) {
		rq->io_start_time_ns = ktime_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);

#ifdef CONFIG_BLK_DEV_INTEGRITY
	if (blk_integrity_rq(rq) && req_op(rq) == REQ_OP_WRITE)
		q->integrity.profile->prepare_fn(rq);
#endif
	if (rq->bio && rq->bio->bi_opf & REQ_POLLED)
	        WRITE_ONCE(rq->bio->bi_cookie, rq->mq_hctx->queue_num);
}
void blk_mq_start_request(struct request *rq)

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

	struct request_queue *q = rq->q;

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

	trace_block_rq_issue(rq);

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

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

큐의 통계 수집 플래그가 켜졌는지 검사합니다. 이 v6.6 본문에는 통과 명령을 제외하는 추가 조건이 없습니다.

		rq->io_start_time_ns = ktime_get_ns();

ktime_get_ns로 단조 증가 시간의 나노초 값을 얻어 요청 시작 시각으로 저장합니다.

		rq->stats_sectors = blk_rq_sectors(rq);

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

		rq->rq_flags |= RQF_STATS;

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

		rq_qos_issue(q, rq);

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

	WARN_ON_ONCE(blk_mq_rq_state(rq) != MQ_RQ_IDLE);

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

	blk_add_timer(rq);

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

	WRITE_ONCE(rq->state, MQ_RQ_IN_FLIGHT);

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

#ifdef CONFIG_BLK_DEV_INTEGRITY

데이터와 함께 보호 정보도 전달하는 장치를 위해 블록 계층의 무결성 처리를 포함하는 설정입니다. v6.6의 이 구간은 쓰기 요청에 필요한 보호 정보 준비를 수행하며, 이 설정만으로 모든 저장장치가 무결성 정보를 사용하지는 않습니다. 이 선택은 전처리 단계에서 이루어지며, CPU가 실행 중 이 줄의 조건을 검사하지 않습니다.

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

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

		q->integrity.profile->prepare_fn(rq);

큐의 무결성 프로파일이 제공한 prepare_fn에 쓰기 요청을 넘겨 무결성 정보를 준비합니다.

#endif

무결성 기능에 따른 조건부 코드는 여기서 끝납니다.

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

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

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

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

함께 생각해 볼 질문

태그 7은 디스크의 7번 섹터인가요?

아닙니다. 예시 태그 7은 진행 중인 요청을 식별하는 번호이고 저장 위치는 요청의 섹터 정보로 나타냅니다.

IN_FLIGHT면 I/O가 성공했나요?

아직 진행 중이라는 상태입니다. 성공 또는 실패는 완료 시 결정됩니다.

폴링 요청의 cookie에 왜 큐 번호를 쓰나요?

어느 하드웨어 큐를 살펴보아야 해당 요청의 완료를 찾을 수 있는지 알려주기 위해서입니다.

출처와 읽은 범위

Linux stable v6.6 · block/blk-mq.c

해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고

맨 위로 ↑