요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
.. _iomap_porting:
..
Dumb style notes to maintain the author's sanity:
Please try to start sentences on separate lines so that
sentence changes don't bleed colors in diff.
Heading decorations are documented in sphinx.rst.
=======================
Porting Your Filesystem
=======================
.. contents:: Table of Contents
:local:
Why Convert?
============
There are several reasons to convert a filesystem to iomap:
1. The classic Linux I/O path is not terribly efficient.
Pagecache operations lock a single base page at a time and then call
into the filesystem to return a mapping for only that page.
Direct I/O operations build I/O requests a single file block at a
time.
This worked well enough for direct/indirect-mapped filesystems such
as ext2, but is very inefficient for extent-based filesystems such
as XFS.
2. Large folios are only supported via iomap; there are no plans to
convert the old buffer_head path to use them.
3. Direct access to storage on memory-like devices (fsdax) is only
supported via iomap.
4. Lower maintenance overhead for individual filesystem maintainers.
iomap handles common pagecache related operations itself, such as
allocating, instantiating, locking, and unlocking of folios.
No ->write_begin(), ->write_end() or direct_IO
address_space_operations are required to be implemented by
filesystem using iomap.
How Do I Convert a Filesystem?
==============================
First, add ``#include <linux/iomap.h>`` from your source code and add
``select FS_IOMAP`` to your filesystem's Kconfig option.
Build the kernel, run fstests with the ``-g all`` option across a wide
variety of your filesystem's supported configurations to build a
baseline of which tests pass and which ones fail.
The recommended approach is first to implement ``->iomap_begin`` (and
``->iomap_end`` if necessary) to allow iomap to obtain a read-only
mapping of a file range.
In most cases, this is a relatively trivial conversion of the existing
``get_block()`` function for read-only mappings.
``FS_IOC_FIEMAP`` is a good first target because it is trivial to
implement support for it and then to determine that the extent map
iteration is correct from userspace.
If FIEMAP is returning the correct information, it's a good sign that
other read-only mapping operations will do the right thing.
Next, modify the filesystem's ``get_block(create = false)``
implementation to use the new ``->iomap_begin`` implementation to map
file space for selected read operations.
Hide behind a debugging knob the ability to switch on the iomap mapping
functions for selected call paths.
It is necessary to write some code to fill out the bufferhead-based
mapping information from the ``iomap`` structure, but the new functions
can be tested without needing to implement any iomap APIs.
Once the read-only functions are working like this, convert each high
level file operation one by one to use iomap native APIs instead of
going through ``get_block()``.
Done one at a time, regressions should be self evident.
You *do* have a regression test baseline for fstests, right?
It is suggested to convert swap file activation, ``SEEK_DATA``, and
``SEEK_HOLE`` before tackling the I/O paths.
A likely complexity at this point will be converting the buffered read
I/O path because of bufferheads.
The buffered read I/O paths doesn't need to be converted yet, though the
direct I/O read path should be converted in this phase.
At this point, you should look over your ``->iomap_begin`` function.
If it switches between large blocks of code based on dispatching of the
``flags`` argument, you should consider breaking it up into
per-operation iomap ops with smaller, more cohesive functions.
XFS is a good example of this.
The next thing to do is implement ``get_blocks(create == true)``
functionality in the ``->iomap_begin``/``->iomap_end`` methods.
It is strongly recommended to create separate mapping functions and
iomap ops for write operations.
Then convert the direct I/O write path to iomap, and start running fsx
w/ DIO enabled in earnest on filesystem.
This will flush out lots of data integrity corner case bugs that the new
write mapping implementation introduces.
Now, convert any remaining file operations to call the iomap functions.
This will get the entire filesystem using the new mapping functions, and
they should largely be debugged and working correctly after this step.
Most likely at this point, the buffered read and write paths will still
need to be converted.
The mapping functions should all work correctly, so all that needs to be
done is rewriting all the code that interfaces with bufferheads to
interface with iomap and folios.
It is much easier first to get regular file I/O (without any fancy
features like fscrypt, fsverity, compression, or data=journaling)
converted to use iomap.
Some of those fancy features (fscrypt and compression) aren't
implemented yet in iomap.
For unjournalled filesystems that use the pagecache for symbolic links
and directories, you might also try converting their handling to iomap.
The rest is left as an exercise for the reader, as it will be different
for every filesystem.
If you encounter problems, email the people and lists in
``get_maintainers.pl`` for help.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
iomap으로 전환해야 하는 이유
1-43이 문서는 GPL-2.0으로 배포되며 Sphinx anchor는 `iomap_porting`입니다. 문장별 diff를 읽기 쉽게 유지하기 위한 작성 메모와 로컬 목차 다음에 파일시스템을 iomap으로 옮겨야 하는 이유를 설명합니다.
첫째, 고전적인 Linux I/O 경로는 효율이 높지 않습니다. Page cache 연산은 한 번에 기본 페이지 하나만 잠근 뒤 그 페이지 하나의 mapping을 받으려고 파일시스템을 호출하고, direct I/O도 파일 블록 하나씩 I/O 요청을 만듭니다. ext2처럼 direct/indirect mapping을 쓰는 파일시스템에는 충분했지만 XFS 같은 extent 기반 파일시스템에는 매우 비효율적입니다.
둘째, large folio는 iomap 경로에서만 지원됩니다. 기존 `buffer_head` 경로를 large folio용으로 바꿀 계획은 없습니다. 셋째, 메모리처럼 접근할 수 있는 장치의 저장 공간을 직접 사용하는 fsdax 역시 iomap에서만 지원됩니다.
넷째, 개별 파일시스템 관리자의 유지보수 부담이 줄어듭니다. iomap이 folio 할당·인스턴스화·잠금·잠금 해제 같은 공통 page cache 연산을 직접 처리하므로 iomap을 쓰는 파일시스템은 `->write_begin()`, `->write_end()`, `direct_IO` address space operation을 구현할 필요가 없습니다.
성능, folio, fsdax, 유지보수 관점의 전환 이점을 정리합니다.
.. SPDX-License-Identifier: GPL-2.0
.. _iomap_porting:
..
Dumb style notes to maintain the author's sanity:
Please try to start sentences on separate lines so that
sentence changes don't bleed colors in diff.
Heading decorations are documented in sphinx.rst.
=======================
Porting Your Filesystem
=======================
.. contents:: Table of Contents
:local:
Why Convert?
============
There are several reasons to convert a filesystem to iomap:
1. The classic Linux I/O path is not terribly efficient.
Pagecache operations lock a single base page at a time and then call
into the filesystem to return a mapping for only that page.
Direct I/O operations build I/O requests a single file block at a
time.
This worked well enough for direct/indirect-mapped filesystems such
as ext2, but is very inefficient for extent-based filesystems such
as XFS.
2. Large folios are only supported via iomap; there are no plans to
convert the old buffer_head path to use them.
3. Direct access to storage on memory-like devices (fsdax) is only
supported via iomap.
4. Lower maintenance overhead for individual filesystem maintainers.
iomap handles common pagecache related operations itself, such as
allocating, instantiating, locking, and unlocking of folios.
No ->write_begin(), ->write_end() or direct_IO
address_space_operations are required to be implemented by
filesystem using iomap.
빌드 설정과 읽기 전용 mapping부터 시작하기
44-71소스에 `#include <linux/iomap.h>`를 추가하고 파일시스템 Kconfig 옵션에 `select FS_IOMAP`을 넣는 것이 첫 단계입니다. 커널을 빌드한 뒤 지원하는 여러 구성에서 `fstests -g all`을 실행하여 통과·실패 시험의 기준선을 만들어야 합니다.
권장 순서는 먼저 `->iomap_begin`과 필요하다면 `->iomap_end`를 구현하여 iomap이 파일 범위의 읽기 전용 mapping을 얻도록 하는 것입니다. 대개 기존 `get_block()` 함수의 읽기 전용 mapping 부분을 비교적 단순하게 변환할 수 있습니다.
첫 목표로는 `FS_IOC_FIEMAP`이 좋습니다. 구현이 간단하고 userspace에서 extent map 반복이 올바른지 확인하기 쉽기 때문입니다. FIEMAP이 정확한 정보를 반환하면 다른 읽기 전용 mapping 연산도 제대로 동작할 가능성이 높습니다.
다음으로 `get_block(create = false)`가 새 `->iomap_begin`을 사용하여 선택한 읽기 경로의 파일 공간을 mapping하도록 수정합니다. 디버그 옵션 뒤에서 호출 경로별 iomap mapping을 켜고 끌 수 있게 하십시오. `struct iomap`에서 bufferhead 기반 mapping 정보를 채우는 변환 코드는 필요하지만, 아직 iomap 상위 API를 구현하지 않고도 새 mapping 함수를 시험할 수 있습니다.
쓰기 경로를 건드리기 전에 mapping 정확도를 검증하는 단계입니다.
How Do I Convert a Filesystem?
==============================
First, add ``#include <linux/iomap.h>`` from your source code and add
``select FS_IOMAP`` to your filesystem's Kconfig option.
Build the kernel, run fstests with the ``-g all`` option across a wide
variety of your filesystem's supported configurations to build a
baseline of which tests pass and which ones fail.
The recommended approach is first to implement ``->iomap_begin`` (and
``->iomap_end`` if necessary) to allow iomap to obtain a read-only
mapping of a file range.
In most cases, this is a relatively trivial conversion of the existing
``get_block()`` function for read-only mappings.
``FS_IOC_FIEMAP`` is a good first target because it is trivial to
implement support for it and then to determine that the extent map
iteration is correct from userspace.
If FIEMAP is returning the correct information, it's a good sign that
other read-only mapping operations will do the right thing.
Next, modify the filesystem's ``get_block(create = false)``
implementation to use the new ``->iomap_begin`` implementation to map
file space for selected read operations.
Hide behind a debugging knob the ability to switch on the iomap mapping
functions for selected call paths.
It is necessary to write some code to fill out the bufferhead-based
mapping information from the ``iomap`` structure, but the new functions
can be tested without needing to implement any iomap APIs.
파일 연산과 direct I/O의 단계적 전환
72-98읽기 전용 함수가 작동하면 고수준 파일 연산을 하나씩 `get_block()` 경유 방식에서 iomap native API로 바꿉니다. 한 번에 하나씩 전환하면 회귀가 분명하게 드러나므로 앞서 만든 fstests 기준선이 중요합니다.
I/O 경로보다 먼저 swap file activation, `SEEK_DATA`, `SEEK_HOLE`을 전환하는 것이 좋습니다. Buffered read는 bufferhead 때문에 복잡할 수 있어 아직 미뤄도 되지만, direct I/O read 경로는 이 단계에서 전환해야 합니다.
이 시점에 `->iomap_begin`을 다시 검토하십시오. `flags` 값에 따라 큰 코드 블록을 분기한다면 연산별 iomap ops와 작고 응집력 있는 함수로 나누는 편이 낫습니다. XFS가 좋은 예입니다.
그다음 `->iomap_begin`/`->iomap_end`에 `get_blocks(create == true)` 기능을 구현합니다. 쓰기 연산에는 별도 mapping 함수와 iomap ops를 만드는 것이 강력히 권장됩니다. Direct I/O write를 iomap으로 전환한 뒤 DIO를 활성화한 `fsx`를 본격적으로 실행하면 새 write mapping이 만든 데이터 무결성 경계 조건 버그를 많이 찾아낼 수 있습니다.
회귀의 원인을 좁힐 수 있도록 한 경로씩 진행합니다.
Once the read-only functions are working like this, convert each high
level file operation one by one to use iomap native APIs instead of
going through ``get_block()``.
Done one at a time, regressions should be self evident.
You *do* have a regression test baseline for fstests, right?
It is suggested to convert swap file activation, ``SEEK_DATA``, and
``SEEK_HOLE`` before tackling the I/O paths.
A likely complexity at this point will be converting the buffered read
I/O path because of bufferheads.
The buffered read I/O paths doesn't need to be converted yet, though the
direct I/O read path should be converted in this phase.
At this point, you should look over your ``->iomap_begin`` function.
If it switches between large blocks of code based on dispatching of the
``flags`` argument, you should consider breaking it up into
per-operation iomap ops with smaller, more cohesive functions.
XFS is a good example of this.
The next thing to do is implement ``get_blocks(create == true)``
functionality in the ``->iomap_begin``/``->iomap_end`` methods.
It is strongly recommended to create separate mapping functions and
iomap ops for write operations.
Then convert the direct I/O write path to iomap, and start running fsx
w/ DIO enabled in earnest on filesystem.
This will flush out lots of data integrity corner case bugs that the new
write mapping implementation introduces.
남은 buffered I/O와 특수 기능
99-120이제 남은 파일 연산을 모두 iomap 함수로 바꿉니다. 그러면 파일시스템 전체가 새 mapping 함수를 사용하게 되며, 이 단계 뒤에는 mapping 함수 대부분이 충분히 디버깅되어 올바르게 작동해야 합니다.
마지막까지 남기 쉬운 부분은 buffered read와 write입니다. Mapping 함수는 이미 검증했으므로 bufferhead와 접속하던 코드를 iomap 및 folio와 접속하도록 다시 쓰는 일이 핵심입니다.
먼저 fscrypt, fsverity, compression, `data=journaling` 같은 고급 기능이 없는 regular file I/O를 전환하는 편이 쉽습니다. 이 문서 시점에는 fscrypt와 compression 같은 일부 기능이 아직 iomap에 구현되지 않았습니다. Page cache를 symbolic link와 directory에 쓰는 비저널링 파일시스템이라면 그 처리도 iomap으로 옮겨볼 수 있습니다.
나머지 세부 작업은 파일시스템마다 다릅니다. 문제가 생기면 `get_maintainers.pl`이 알려주는 담당자와 메일링 리스트에 도움을 요청하십시오.
Now, convert any remaining file operations to call the iomap functions.
This will get the entire filesystem using the new mapping functions, and
they should largely be debugged and working correctly after this step.
Most likely at this point, the buffered read and write paths will still
need to be converted.
The mapping functions should all work correctly, so all that needs to be
done is rewriting all the code that interfaces with bufferheads to
interface with iomap and folios.
It is much easier first to get regular file I/O (without any fancy
features like fscrypt, fsverity, compression, or data=journaling)
converted to use iomap.
Some of those fancy features (fscrypt and compression) aren't
implemented yet in iomap.
For unjournalled filesystems that use the pagecache for symbolic links
and directories, you might also try converting their handling to iomap.
The rest is left as an exercise for the reader, as it will be different
for every filesystem.
If you encounter problems, email the people and lists in
``get_maintainers.pl`` for help.
요약·해설
porting.rst:1-120iomap 이식은 읽기 전용 mapping을 먼저 검증하고 파일 연산을 하나씩 native API로 옮긴 뒤 direct write와 buffered I/O를 전환하는 점진적 작업입니다. 각 단계에서 fstests와 fsx 기준선을 유지해야 회귀와 데이터 무결성 문제를 분리해 찾을 수 있습니다.
낮은 위험의 관찰 API에서 전체 I/O 경로로 확장합니다.