# F2FS: 읽기 방식 선택에도 쓰기 상태를 확인하는 이유

v6.18.37 / fs/f2fs/file.c

F2FS는 플래시 저장장치를 고려해 세그먼트와 노드 구조로 파일 위치를 관리합니다. 읽기를 시작할 때도 압축 지원과 진행 중인 직접 쓰기를 확인해야 안전한 데이터를 얻을 수 있습니다. f2fs_file_read_iter 전체를 통해 파일시스템의 저장 정책이 읽기 분기와 대기 조건에 어떻게 나타나는지 살펴봅니다.

## f2fs_file_read_iter

```c

static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
	struct inode *inode = file_inode(iocb->ki_filp);
	const loff_t pos = iocb->ki_pos;
	ssize_t ret;
	bool dio;

	if (!f2fs_is_compress_backend_ready(inode))
		return -EOPNOTSUPP;

	if (trace_f2fs_dataread_start_enabled())
		f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
					iov_iter_count(to), READ);

	dio = f2fs_should_use_dio(inode, iocb, to);

	/* In LFS mode, if there is inflight dio, wait for its completion */
	if (f2fs_lfs_mode(F2FS_I_SB(inode)) &&
	    get_pages(F2FS_I_SB(inode), F2FS_DIO_WRITE) &&
		(!f2fs_is_pinned_file(inode) || !dio))
		inode_dio_wait(inode);

	if (dio) {
		ret = f2fs_dio_read_iter(iocb, to);
	} else {
		ret = filemap_read(iocb, to, 0);
		if (ret > 0)
			f2fs_update_iostat(F2FS_I_SB(inode), inode,
						APP_BUFFERED_READ_IO, ret);
	}
	trace_f2fs_dataread_end(inode, pos, ret);
	return ret;
}

```

### 4851행

```c

static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)

```

F2FS 파일 읽기 요청과 목적지 반복자를 받습니다. 결과는 바이트 수 또는 음수 오류입니다.

### 4853행

```c

	struct inode *inode = file_inode(iocb->ki_filp);

```

파일에서 inode를 얻어 F2FS 속성과 동시 I/O 상태를 확인합니다.

### 4854행

```c

	const loff_t pos = iocb->ki_pos;

```

읽기 전 시작 위치를 보관합니다. 이후 위치가 이동해도 추적 기록에 원래 값을 쓸 수 있습니다.

### 4855행

```c

	ssize_t ret;

```

읽기 결과를 저장할 부호 있는 변수입니다. 음수 오류도 담아야 합니다.

### 4856행

```c

	bool dio;

```

이번 읽기가 직접 I/O를 사용할지 기록할 논리값입니다.

### 4858행

```c

	if (!f2fs_is_compress_backend_ready(inode))

```

해당 파일을 읽는 데 필요한 압축 구현이 준비되어 있는지 확인합니다.

### 4859행

```c

		return -EOPNOTSUPP;

```

준비되지 않았다면 지원하지 않는 작업이라는 오류를 반환합니다.

### 4861행

```c

	if (trace_f2fs_dataread_start_enabled())

```

읽기 시작 추적 이벤트가 활성화됐을 때만 경로 추적 정보를 계산합니다.

### 4862행

```c

		f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,

```

파일과 현재 위치를 추적 함수에 전달합니다.

### 4863행

```c

					iov_iter_count(to), READ);

```

요청 바이트 수와 읽기 방향 READ도 함께 전달합니다.

### 4865행

```c

	dio = f2fs_should_use_dio(inode, iocb, to);

```

파일과 요청 조건을 함께 검사해 F2FS가 사용할 직접 I/O 여부를 결정합니다.

### 4868행

```c

	if (f2fs_lfs_mode(F2FS_I_SB(inode)) &&

```

파일시스템이 LFS 모드인지를 대기 조건의 첫 항목으로 검사합니다.

### 4869행

```c

	    get_pages(F2FS_I_SB(inode), F2FS_DIO_WRITE) &&

```

동시에 진행 중인 직접 쓰기가 있는지를 두 번째 조건으로 검사합니다.

### 4870행

```c

		(!f2fs_is_pinned_file(inode) || !dio))

```

pinned 파일의 직접 읽기 예외를 고려합니다. pinned가 아니거나 이번 읽기가 직접 I/O가 아니면 앞 조건들과 함께 대기합니다.

### 4871행

```c

		inode_dio_wait(inode);

```

이 inode의 진행 중인 직접 I/O가 끝날 때까지 기다립니다.

### 4873행

```c

	if (dio) {

```

앞서 결정한 직접 I/O 사용 여부에 따라 읽기 경로를 나눕니다.

### 4874행

```c

		ret = f2fs_dio_read_iter(iocb, to);

```

F2FS 직접 읽기를 수행해 결과를 ret에 저장합니다.

### 4875행

```c

	} else {

```

직접 I/O를 선택하지 않은 요청은 아래 캐시 읽기 경로로 갑니다.

### 4876행

```c

		ret = filemap_read(iocb, to, 0);

```

페이지 캐시를 이용하는 filemap 읽기에 요청을 넘깁니다.

### 4877행

```c

		if (ret > 0)

```

실제로 양수 바이트를 읽었을 때만 읽은 양을 통계에 더합니다.

### 4878행

```c

			f2fs_update_iostat(F2FS_I_SB(inode), inode,

```

F2FS 파일시스템과 inode를 통계 갱신 함수에 전달합니다.

### 4879행

```c

						APP_BUFFERED_READ_IO, ret);

```

애플리케이션 버퍼드 읽기 종류와 실제 읽은 바이트 수를 전달합니다.

### 4881행

```c

	trace_f2fs_dataread_end(inode, pos, ret);

```

원래 시작 위치와 최종 결과로 읽기 종료 추적 이벤트를 남깁니다.

### 4882행

```c

	return ret;

```

실제 읽은 길이, 0 또는 오류를 호출자에게 반환합니다.

