# 파티션 검색: 디스크 구간을 장치로 등록하기까지

v6.6 / block/partitions/core.c

파티션 표는 디스크의 어떤 범위를 독립된 구간으로 다룰지 기록한 메타데이터입니다. 표를 읽었다고 각 파티션 장치가 저절로 생기지는 않습니다. blk_add_partitions는 읽기 결과를 검사한 뒤 파티션을 등록하며, 장치 용량 때문에 다시 읽어야 할 때와 실제 오류도 구분합니다.

## blk_add_partitions

```c

static int blk_add_partitions(struct gendisk *disk)
{
	struct parsed_partitions *state;
	int ret = -EAGAIN, p;

	if (disk->flags & GENHD_FL_NO_PART)
		return 0;

	if (test_bit(GD_SUPPRESS_PART_SCAN, &disk->state))
		return 0;

	state = check_partition(disk);
	if (!state)
		return 0;
	if (IS_ERR(state)) {
		/*
		 * I/O error reading the partition table.  If we tried to read
		 * beyond EOD, retry after unlocking the native capacity.
		 */
		if (PTR_ERR(state) == -ENOSPC) {
			printk(KERN_WARNING "%s: partition table beyond EOD, ",
			       disk->disk_name);
			if (disk_unlock_native_capacity(disk))
				return -EAGAIN;
		}
		return -EIO;
	}

	/*
	 * Partitions are not supported on host managed zoned block devices.
	 */
	if (disk->queue->limits.zoned == BLK_ZONED_HM) {
		pr_warn("%s: ignoring partition table on host managed zoned block device\n",
			disk->disk_name);
		ret = 0;
		goto out_free_state;
	}

	/*
	 * If we read beyond EOD, try unlocking native capacity even if the
	 * partition table was successfully read as we could be missing some
	 * partitions.
	 */
	if (state->access_beyond_eod) {
		printk(KERN_WARNING
		       "%s: partition table partially beyond EOD, ",
		       disk->disk_name);
		if (disk_unlock_native_capacity(disk))
			goto out_free_state;
	}

	/* tell userspace that the media / partition table may have changed */
	kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);

	for (p = 1; p < state->limit; p++)
		if (!blk_add_partition(disk, state, p))
			goto out_free_state;

	ret = 0;
out_free_state:
	free_partitions(state);
	return ret;
}

```

### 585행

```c

static int blk_add_partitions(struct gendisk *disk)

```

파티션을 검색하고 등록할 디스크를 받으며, 결과를 정수 상태 코드로 반환합니다.

### 587행

```c

	struct parsed_partitions *state;

```

파티션 표를 해석한 임시 상태 객체를 가리킵니다.

### 588행

```c

	int ret = -EAGAIN, p;

```

초기 결과를 재시도 오류로 설정합니다. p는 등록할 파티션 번호입니다.

### 590행

```c

	if (disk->flags & GENHD_FL_NO_PART)

```

디스크에 파티션을 사용하지 않는 GENHD_FL_NO_PART 플래그가 있는지 확인합니다.

### 591행

```c

		return 0;

```

파티션을 사용하지 않는 디스크이므로 표 검색 없이 정상 반환합니다.

### 593행

```c

	if (test_bit(GD_SUPPRESS_PART_SCAN, &disk->state))

```

현재 디스크 상태에 파티션 검색을 억제하는 GD_SUPPRESS_PART_SCAN 비트가 설정됐는지 확인합니다.

### 594행

```c

		return 0;

```

검색을 억제한 상태이면 파티션을 추가하지 않고 정상 반환합니다.

### 596행

```c

	state = check_partition(disk);

```

지원하는 파티션 형식의 해석기로 디스크의 표를 읽습니다.

### 597행

```c

	if (!state)

```

해석할 파티션 정보가 없다는 NULL 결과인지 검사합니다.

### 598행

```c

		return 0;

```

표가 없다는 사실 자체를 I/O 오류로 만들지 않습니다.

### 599행

```c

	if (IS_ERR(state)) {

```

포인터처럼 보이는 반환값이 사실 오류 번호인지 확인합니다.

### 604행

```c

		if (PTR_ERR(state) == -ENOSPC) {

```

읽으려던 표가 알려진 장치 용량을 넘어갔다는 -ENOSPC인지 구분합니다.

### 605행

```c

			printk(KERN_WARNING "%s: partition table beyond EOD, ",

```

장치 끝을 넘는 파티션 표가 발견됐다는 경고 출력을 시작합니다.

### 606행

```c

			       disk->disk_name);

```

경고에 실제 디스크 이름을 넣습니다.

### 607행

```c

			if (disk_unlock_native_capacity(disk))

```

숨겨진 원래 장치 용량을 활성화할 수 있었는지 확인합니다.

### 608행

```c

				return -EAGAIN;

```

용량 조건이 바뀌었으므로 호출자에게 다시 검색하도록 -EAGAIN을 반환합니다.

### 610행

```c

		return -EIO;

```

이 경로에서 해결할 수 없는 파티션 표 읽기 실패는 -EIO로 알립니다.

### 616행

```c

	if (disk->queue->limits.zoned == BLK_ZONED_HM) {

```

큐의 zoned 종류가 host-managed인지 확인합니다. v6.6의 이 분기는 모든 zoned 종류를 무조건 배제하는 조건이 아닙니다.

### 617행

```c

		pr_warn("%s: ignoring partition table on host managed zoned block device\n",

```

이 장치의 파티션 표를 무시한다는 경고를 출력합니다.

### 618행

```c

			disk->disk_name);

```

경고 메시지의 대상 장치 이름을 전달합니다.

### 619행

```c

		ret = 0;

```

표를 무시하는 정책으로 처리했으므로 정상 결과를 선택합니다.

### 620행

```c

		goto out_free_state;

```

이미 할당한 파티션 해석 상태를 해제하는 위치로 갑니다.

### 628행

```c

	if (state->access_beyond_eod) {

```

표 해석이 끝났어도 장치 끝을 넘은 접근이 있었는지 확인합니다.

### 629행

```c

		printk(KERN_WARNING

```

부분적으로 장치 끝을 넘는 경우의 경고를 시작합니다.

### 630행

```c

		       "%s: partition table partially beyond EOD, ",

```

파티션 표 일부가 현재 용량 밖이었다는 문구입니다.

### 631행

```c

		       disk->disk_name);

```

어떤 디스크에서 발생했는지 이름을 출력합니다.

### 632행

```c

		if (disk_unlock_native_capacity(disk))

```

이 경우에도 원래 용량을 다시 사용할 수 있는지 시도합니다.

### 633행

```c

			goto out_free_state;

```

용량을 활성화했으면 초기값 -EAGAIN을 유지하며 임시 상태를 해제합니다.

### 637행

```c

	kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE);

```

매체나 파티션 표가 바뀌었을 수 있음을 사용자 공간에 KOBJ_CHANGE 이벤트로 알립니다.

### 639행

```c

	for (p = 1; p < state->limit; p++)

```

전체 디스크를 나타내는 0번을 제외하고 해석 가능한 파티션 항목을 순회합니다.

### 640행

```c

		if (!blk_add_partition(disk, state, p))

```

해당 파티션의 범위를 확인하고 등록을 시도합니다. 하위 함수가 원래 용량을 활성화해 재검색이 필요해지면 거짓을 반환합니다.

### 641행

```c

			goto out_free_state;

```

용량을 다시 확인해야 하므로 초기 결과 -EAGAIN을 유지한 채 임시 상태를 해제합니다.

### 643행

```c

	ret = 0;

```

모든 항목 처리를 마쳐 성공값 0을 설정합니다.

### 644행

```c

out_free_state:

```

유효한 해석 상태를 얻은 경로들이 모이는 정리 위치입니다.

### 645행

```c

	free_partitions(state);

```

임시 파티션 해석 결과를 해제합니다. 이미 등록한 장치 객체와는 구분됩니다.

### 646행

```c

	return ret;

```

성공 또는 재시도 상태를 호출자에게 전달합니다.

