요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
.. _iomap_design:
..
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.
==============
Library Design
==============
.. contents:: Table of Contents
:local:
Introduction
============
iomap is a filesystem library for handling common file operations.
The library has two layers:
1. A lower layer that provides an iterator over ranges of file offsets.
This layer tries to obtain mappings of each file ranges to storage
from the filesystem, but the storage information is not necessarily
required.
2. An upper layer that acts upon the space mappings provided by the
lower layer iterator.
The iteration can involve mappings of file's logical offset ranges to
physical extents, but the storage layer information is not necessarily
required, e.g. for walking cached file information.
The library exports various APIs for implementing file operations such
as:
* Pagecache reads and writes
* Folio write faults to the pagecache
* Writeback of dirty folios
* Direct I/O reads and writes
* fsdax I/O reads, writes, loads, and stores
* FIEMAP
* lseek ``SEEK_DATA`` and ``SEEK_HOLE``
* swapfile activation
This origins of this library is the file I/O path that XFS once used; it
has now been extended to cover several other operations.
Who Should Read This?
=====================
The target audience for this document are filesystem, storage, and
pagecache programmers and code reviewers.
If you are working on PCI, machine architectures, or device drivers, you
are most likely in the wrong place.
How Is This Better?
===================
Unlike the classic Linux I/O model which breaks file I/O into small
units (generally memory pages or blocks) and looks up space mappings on
the basis of that unit, the iomap model asks the filesystem for the
largest space mappings that it can create for a given file operation and
initiates operations on that basis.
This strategy improves the filesystem's visibility into the size of the
operation being performed, which enables it to combat fragmentation with
larger space allocations when possible.
Larger space mappings improve runtime performance by amortizing the cost
of mapping function calls into the filesystem across a larger amount of
data.
At a high level, an iomap operation `looks like this
<https://lore.kernel.org/all/ZGbVaewzcCysclPt@dread.disaster.area/>`_:
1. For each byte in the operation range...
1. Obtain a space mapping via ``->iomap_begin``
2. For each sub-unit of work...
1. Revalidate the mapping and go back to (1) above, if necessary.
So far only the pagecache operations need to do this.
2. Do the work
3. Increment operation cursor
4. Release the mapping via ``->iomap_end``, if necessary
Each iomap operation will be covered in more detail below.
This library was covered previously by an `LWN article
<https://lwn.net/Articles/935934/>`_ and a `KernelNewbies page
<https://kernelnewbies.org/KernelProjects/iomap>`_.
The goal of this document is to provide a brief discussion of the
design and capabilities of iomap, followed by a more detailed catalog
of the interfaces presented by iomap.
If you change iomap, please update this design document.
File Range Iterator
===================
Definitions
-----------
* **buffer head**: Shattered remnants of the old buffer cache.
* ``fsblock``: The block size of a file, also known as ``i_blocksize``.
* ``i_rwsem``: The VFS ``struct inode`` rwsemaphore.
Processes hold this in shared mode to read file state and contents.
Some filesystems may allow shared mode for writes.
Processes often hold this in exclusive mode to change file state and
contents.
* ``invalidate_lock``: The pagecache ``struct address_space``
rwsemaphore that protects against folio insertion and removal for
filesystems that support punching out folios below EOF.
Processes wishing to insert folios must hold this lock in shared
mode to prevent removal, though concurrent insertion is allowed.
Processes wishing to remove folios must hold this lock in exclusive
mode to prevent insertions.
Concurrent removals are not allowed.
* ``dax_read_lock``: The RCU read lock that dax takes to prevent a
device pre-shutdown hook from returning before other threads have
released resources.
* **filesystem mapping lock**: This synchronization primitive is
internal to the filesystem and must protect the file mapping data
from updates while a mapping is being sampled.
The filesystem author must determine how this coordination should
happen; it does not need to be an actual lock.
* **iomap internal operation lock**: This is a general term for
synchronization primitives that iomap functions take while holding a
mapping.
A specific example would be taking the folio lock while reading or
writing the pagecache.
* **pure overwrite**: A write operation that does not require any
metadata or zeroing operations to perform during either submission
or completion.
This implies that the filesystem must have already allocated space
on disk as ``IOMAP_MAPPED`` and the filesystem must not place any
constraints on IO alignment or size.
The only constraints on I/O alignment are device level (minimum I/O
size and alignment, typically sector size).
``struct iomap``
----------------
The filesystem communicates to the iomap iterator the mapping of
byte ranges of a file to byte ranges of a storage device with the
structure below:
.. code-block:: c
struct iomap {
u64 addr;
loff_t offset;
u64 length;
u16 type;
u16 flags;
struct block_device *bdev;
struct dax_device *dax_dev;
void *inline_data;
void *private;
u64 validity_cookie;
};
The fields are as follows:
* ``offset`` and ``length`` describe the range of file offsets, in
bytes, covered by this mapping.
These fields must always be set by the filesystem.
* ``type`` describes the type of the space mapping:
* **IOMAP_HOLE**: No storage has been allocated.
This type must never be returned in response to an ``IOMAP_WRITE``
operation because writes must allocate and map space, and return
the mapping.
The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
iomap does not support writing (whether via pagecache or direct
I/O) to a hole.
* **IOMAP_DELALLOC**: A promise to allocate space at a later time
("delayed allocation").
If the filesystem returns IOMAP_F_NEW here and the write fails, the
``->iomap_end`` function must delete the reservation.
The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
* **IOMAP_MAPPED**: The file range maps to specific space on the
storage device.
The device is returned in ``bdev`` or ``dax_dev``.
The device address, in bytes, is returned via ``addr``.
* **IOMAP_UNWRITTEN**: The file range maps to specific space on the
storage device, but the space has not yet been initialized.
The device is returned in ``bdev`` or ``dax_dev``.
The device address, in bytes, is returned via ``addr``.
Reads from this type of mapping will return zeroes to the caller.
For a write or writeback operation, the ioend should update the
mapping to MAPPED.
Refer to the sections about ioends for more details.
* **IOMAP_INLINE**: The file range maps to the memory buffer
specified by ``inline_data``.
For write operation, the ``->iomap_end`` function presumably
handles persisting the data.
The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
* ``flags`` describe the status of the space mapping.
These flags should be set by the filesystem in ``->iomap_begin``:
* **IOMAP_F_NEW**: The space under the mapping is newly allocated.
Areas that will not be written to must be zeroed.
If a write fails and the mapping is a space reservation, the
reservation must be deleted.
* **IOMAP_F_DIRTY**: The inode will have uncommitted metadata needed
to access any data written.
fdatasync is required to commit these changes to persistent
storage.
This needs to take into account metadata changes that *may* be made
at I/O completion, such as file size updates from direct I/O.
* **IOMAP_F_SHARED**: The space under the mapping is shared.
Copy on write is necessary to avoid corrupting other file data.
* **IOMAP_F_BUFFER_HEAD**: This mapping requires the use of buffer
heads for pagecache operations.
Do not add more uses of this.
* **IOMAP_F_MERGED**: Multiple contiguous block mappings were
coalesced into this single mapping.
This is only useful for FIEMAP.
* **IOMAP_F_XATTR**: The mapping is for extended attribute data, not
regular file data.
This is only useful for FIEMAP.
* **IOMAP_F_BOUNDARY**: This indicates I/O and its completion must not be
merged with any other I/O or completion. Filesystems must use this when
submitting I/O to devices that cannot handle I/O crossing certain LBAs
(e.g. ZNS devices). This flag applies only to buffered I/O writeback; all
other functions ignore it.
* **IOMAP_F_PRIVATE**: This flag is reserved for filesystem private use.
* **IOMAP_F_ANON_WRITE**: Indicates that (write) I/O does not have a target
block assigned to it yet and the file system will do that in the bio
submission handler, splitting the I/O as needed.
* **IOMAP_F_ATOMIC_BIO**: This indicates write I/O must be submitted with the
``REQ_ATOMIC`` flag set in the bio. Filesystems need to set this flag to
inform iomap that the write I/O operation requires torn-write protection
based on HW-offload mechanism. They must also ensure that mapping updates
upon the completion of the I/O must be performed in a single metadata
update.
These flags can be set by iomap itself during file operations.
The filesystem should supply an ``->iomap_end`` function if it needs
to observe these flags:
* **IOMAP_F_SIZE_CHANGED**: The file size has changed as a result of
using this mapping.
* **IOMAP_F_STALE**: The mapping was found to be stale.
iomap will call ``->iomap_end`` on this mapping and then
``->iomap_begin`` to obtain a new mapping.
Currently, these flags are only set by pagecache operations.
* ``addr`` describes the device address, in bytes.
* ``bdev`` describes the block device for this mapping.
This only needs to be set for mapped or unwritten operations.
* ``dax_dev`` describes the DAX device for this mapping.
This only needs to be set for mapped or unwritten operations, and
only for a fsdax operation.
* ``inline_data`` points to a memory buffer for I/O involving
``IOMAP_INLINE`` mappings.
This value is ignored for all other mapping types.
* ``private`` is a pointer to `filesystem-private information
<https://lore.kernel.org/all/20180619164137.13720-7-hch@lst.de/>`_.
This value will be passed unchanged to ``->iomap_end``.
* ``validity_cookie`` is a magic freshness value set by the filesystem
that should be used to detect stale mappings.
For pagecache operations this is critical for correct operation
because page faults can occur, which implies that filesystem locks
should not be held between ``->iomap_begin`` and ``->iomap_end``.
Filesystems with completely static mappings need not set this value.
Only pagecache operations revalidate mappings; see the section about
``iomap_valid`` for details.
``struct iomap_ops``
--------------------
Every iomap function requires the filesystem to pass an operations
structure to obtain a mapping and (optionally) to release the mapping:
.. code-block:: c
struct iomap_ops {
int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length,
unsigned flags, struct iomap *iomap,
struct iomap *srcmap);
int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length,
ssize_t written, unsigned flags,
struct iomap *iomap);
};
``->iomap_begin``
~~~~~~~~~~~~~~~~~
iomap operations call ``->iomap_begin`` to obtain one file mapping for
the range of bytes specified by ``pos`` and ``length`` for the file
``inode``.
This mapping should be returned through the ``iomap`` pointer.
The mapping must cover at least the first byte of the supplied file
range, but it does not need to cover the entire requested range.
Each iomap operation describes the requested operation through the
``flags`` argument.
The exact value of ``flags`` will be documented in the
operation-specific sections below.
These flags can, at least in principle, apply generally to iomap
operations:
* ``IOMAP_DIRECT`` is set when the caller wishes to issue file I/O to
block storage.
* ``IOMAP_DAX`` is set when the caller wishes to issue file I/O to
memory-like storage.
* ``IOMAP_NOWAIT`` is set when the caller wishes to perform a best
effort attempt to avoid any operation that would result in blocking
the submitting task.
This is similar in intent to ``O_NONBLOCK`` for network APIs - it is
intended for asynchronous applications to keep doing other work
instead of waiting for the specific unavailable filesystem resource
to become available.
Filesystems implementing ``IOMAP_NOWAIT`` semantics need to use
trylock algorithms.
They need to be able to satisfy the entire I/O request range with a
single iomap mapping.
They need to avoid reading or writing metadata synchronously.
They need to avoid blocking memory allocations.
They need to avoid waiting on transaction reservations to allow
modifications to take place.
They probably should not be allocating new space.
And so on.
If there is any doubt in the filesystem developer's mind as to
whether any specific ``IOMAP_NOWAIT`` operation may end up blocking,
then they should return ``-EAGAIN`` as early as possible rather than
start the operation and force the submitting task to block.
``IOMAP_NOWAIT`` is often set on behalf of ``IOCB_NOWAIT`` or
``RWF_NOWAIT``.
* ``IOMAP_DONTCACHE`` is set when the caller wishes to perform a
buffered file I/O and would like the kernel to drop the pagecache
after the I/O completes, if it isn't already being used by another
thread.
If it is necessary to read existing file contents from a `different
<https://lore.kernel.org/all/20191008071527.29304-9-hch@lst.de/>`_
device or address range on a device, the filesystem should return that
information via ``srcmap``.
Only pagecache and fsdax operations support reading from one mapping and
writing to another.
``->iomap_end``
~~~~~~~~~~~~~~~
After the operation completes, the ``->iomap_end`` function, if present,
is called to signal that iomap is finished with a mapping.
Typically, implementations will use this function to tear down any
context that were set up in ``->iomap_begin``.
For example, a write might wish to commit the reservations for the bytes
that were operated upon and unreserve any space that was not operated
upon.
``written`` might be zero if no bytes were touched.
``flags`` will contain the same value passed to ``->iomap_begin``.
iomap ops for reads are not likely to need to supply this function.
Both functions should return a negative errno code on error, or zero on
success.
Preparing for File Operations
=============================
iomap only handles mapping and I/O.
Filesystems must still call out to the VFS to check input parameters
and file state before initiating an I/O operation.
It does not handle obtaining filesystem freeze protection, updating of
timestamps, stripping privileges, or access control.
Locking Hierarchy
=================
iomap requires that filesystems supply their own locking model.
There are three categories of synchronization primitives, as far as
iomap is concerned:
* The **upper** level primitive is provided by the filesystem to
coordinate access to different iomap operations.
The exact primitive is specific to the filesystem and operation,
but is often a VFS inode, pagecache invalidation, or folio lock.
For example, a filesystem might take ``i_rwsem`` before calling
``iomap_file_buffered_write`` and ``iomap_file_unshare`` to prevent
these two file operations from clobbering each other.
Pagecache writeback may lock a folio to prevent other threads from
accessing the folio until writeback is underway.
* The **lower** level primitive is taken by the filesystem in the
``->iomap_begin`` and ``->iomap_end`` functions to coordinate
access to the file space mapping information.
The fields of the iomap object should be filled out while holding
this primitive.
The upper level synchronization primitive, if any, remains held
while acquiring the lower level synchronization primitive.
For example, XFS takes ``ILOCK_EXCL`` and ext4 takes ``i_data_sem``
while sampling mappings.
Filesystems with immutable mapping information may not require
synchronization here.
* The **operation** primitive is taken by an iomap operation to
coordinate access to its own internal data structures.
The upper level synchronization primitive, if any, remains held
while acquiring this primitive.
The lower level primitive is not held while acquiring this
primitive.
For example, pagecache write operations will obtain a file mapping,
then grab and lock a folio to copy new contents.
It may also lock an internal folio state object to update metadata.
The exact locking requirements are specific to the filesystem; for
certain operations, some of these locks can be elided.
All further mentions of locking are *recommendations*, not mandates.
Each filesystem author must figure out the locking for themself.
Bugs and Limitations
====================
* No support for fscrypt.
* No support for compression.
* No support for fsverity yet.
* Strong assumptions that IO should work the way it does on XFS.
* Does iomap *actually* work for non-regular file data?
Patches welcome!
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
문서 표기와 목차
1-16이 문서는 GPL-2.0으로 배포되며 Sphinx 참조 anchor는 `iomap_design`입니다. 제목은 iomap library 설계입니다.
원문의 숨김 style note는 문장 변경이 diff에서 주변 줄의 색까지 번지지 않도록 각 문장을 별도 줄에서 시작하고, heading 장식은 `sphinx.rst`를 따르라고 요청합니다. 본문에는 local table of contents가 포함됩니다.
.. SPDX-License-Identifier: GPL-2.0
.. _iomap_design:
..
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.
==============
Library Design
==============
.. contents:: Table of Contents
:local:
iomap의 두 계층과 지원 연산
17-48iomap은 공통 파일 연산을 처리하는 파일시스템 library입니다. 두 계층 가운데 아래 계층은 파일 offset 범위를 순회하는 iterator를 제공합니다. 파일시스템에서 각 파일 범위를 storage에 연결하는 mapping을 얻으려 하지만, cached file 정보만 순회하는 경우처럼 storage 정보가 반드시 필요한 것은 아닙니다.
위 계층은 아래 계층 iterator가 제공한 공간 mapping에 실제 연산을 수행합니다. 순회 과정은 파일의 logical offset 범위를 physical extent에 연결할 수 있지만, storage 계층 정보 없이도 동작할 수 있습니다.
library는 pagecache read/write, pagecache에 대한 folio write fault, dirty folio writeback, direct I/O read/write, fsdax I/O read·write·load·store, FIEMAP, `lseek`의 `SEEK_DATA`와 `SEEK_HOLE`, swapfile 활성화를 구현하는 API를 제공합니다.
iomap의 기원은 과거 XFS가 사용하던 file I/O path이며, 현재는 여러 다른 연산까지 포괄하도록 확장되었습니다.
파일 범위 mapping 획득과 실제 연산 실행을 분리합니다.
Introduction
============
iomap is a filesystem library for handling common file operations.
The library has two layers:
1. A lower layer that provides an iterator over ranges of file offsets.
This layer tries to obtain mappings of each file ranges to storage
from the filesystem, but the storage information is not necessarily
required.
2. An upper layer that acts upon the space mappings provided by the
lower layer iterator.
The iteration can involve mappings of file's logical offset ranges to
physical extents, but the storage layer information is not necessarily
required, e.g. for walking cached file information.
The library exports various APIs for implementing file operations such
as:
* Pagecache reads and writes
* Folio write faults to the pagecache
* Writeback of dirty folios
* Direct I/O reads and writes
* fsdax I/O reads, writes, loads, and stores
* FIEMAP
* lseek ``SEEK_DATA`` and ``SEEK_HOLE``
* swapfile activation
This origins of this library is the file I/O path that XFS once used; it
has now been extended to cover several other operations.
대상 독자와 큰 mapping의 이점
49-100이 문서의 대상 독자는 파일시스템, storage, pagecache programmer와 code reviewer입니다. PCI, machine architecture, device driver를 다루는 사람은 대체로 이 문서의 대상이 아닙니다.
고전적인 Linux I/O model은 file I/O를 보통 memory page나 block 같은 작은 단위로 나누고 그 단위마다 공간 mapping을 조회합니다. 반면 iomap model은 주어진 파일 연산에 대해 파일시스템이 만들 수 있는 가장 큰 공간 mapping을 요청하고 그 크기를 기준으로 연산을 시작합니다.
이 전략은 파일시스템이 수행 중인 연산의 전체 크기를 더 잘 파악하게 하므로 가능할 때 더 큰 공간을 할당해 fragmentation을 줄일 수 있습니다. mapping 함수 호출 비용도 더 많은 data에 나누어 부담하므로 runtime 성능이 좋아집니다.
높은 수준에서 iomap 연산은 다음 순서입니다. 연산 범위의 각 byte를 처리하기 위해 `->iomap_begin`으로 공간 mapping을 얻습니다. 각 작업 sub-unit마다 필요하면 mapping을 재검증하고 처음으로 돌아가며, 현재는 pagecache 연산만 이 재검증이 필요합니다. 작업을 수행하고 operation cursor를 증가시킨 뒤, 필요하면 `->iomap_end`로 mapping을 해제합니다.
원문은 이 흐름을 설명한 lore.kernel.org 글, 이전 LWN 기사, KernelNewbies iomap page를 연결합니다. 문서의 목적은 iomap 설계와 기능을 간단히 논의한 다음 interface를 자세히 목록화하는 것입니다. iomap을 변경하면 이 설계 문서도 갱신해야 합니다.
mapping을 조회하는 단위가 allocation과 호출 비용에 영향을 줍니다.
mapping 획득부터 cursor 전진과 해제까지의 반복입니다.
Who Should Read This?
=====================
The target audience for this document are filesystem, storage, and
pagecache programmers and code reviewers.
If you are working on PCI, machine architectures, or device drivers, you
are most likely in the wrong place.
How Is This Better?
===================
Unlike the classic Linux I/O model which breaks file I/O into small
units (generally memory pages or blocks) and looks up space mappings on
the basis of that unit, the iomap model asks the filesystem for the
largest space mappings that it can create for a given file operation and
initiates operations on that basis.
This strategy improves the filesystem's visibility into the size of the
operation being performed, which enables it to combat fragmentation with
larger space allocations when possible.
Larger space mappings improve runtime performance by amortizing the cost
of mapping function calls into the filesystem across a larger amount of
data.
At a high level, an iomap operation `looks like this
<https://lore.kernel.org/all/ZGbVaewzcCysclPt@dread.disaster.area/>`_:
1. For each byte in the operation range...
1. Obtain a space mapping via ``->iomap_begin``
2. For each sub-unit of work...
1. Revalidate the mapping and go back to (1) above, if necessary.
So far only the pagecache operations need to do this.
2. Do the work
3. Increment operation cursor
4. Release the mapping via ``->iomap_end``, if necessary
Each iomap operation will be covered in more detail below.
This library was covered previously by an `LWN article
<https://lwn.net/Articles/935934/>`_ and a `KernelNewbies page
<https://kernelnewbies.org/KernelProjects/iomap>`_.
The goal of this document is to provide a brief discussion of the
design and capabilities of iomap, followed by a more detailed catalog
of the interfaces presented by iomap.
If you change iomap, please update this design document.
파일 범위 iterator의 용어와 잠금
101-150buffer head는 원문의 표현대로 옛 buffer cache가 산산이 남긴 잔재입니다. `fsblock`은 파일의 block 크기이며 `i_blocksize`라고도 합니다.
`i_rwsem`은 VFS `struct inode`의 rwsemaphore입니다. process는 파일 상태와 내용을 읽을 때 shared mode로 잡고, 일부 파일시스템은 write에도 shared mode를 허용합니다. 파일 상태나 내용을 바꿀 때는 흔히 exclusive mode로 잡습니다.
`invalidate_lock`은 pagecache `struct address_space`의 rwsemaphore입니다. EOF 아래 folio를 punch out할 수 있는 파일시스템에서 folio 삽입과 제거의 충돌을 막습니다. 삽입자는 제거를 막기 위해 shared mode로 잡으며 동시 삽입은 허용됩니다. 제거자는 삽입을 막기 위해 exclusive mode로 잡고 동시 제거는 허용되지 않습니다.
`dax_read_lock`은 device pre-shutdown hook이 다른 thread의 resource 해제 전에 반환하지 못하도록 DAX가 잡는 RCU read lock입니다.
filesystem mapping lock은 mapping을 sampling하는 동안 파일 mapping data의 갱신을 막아야 하는 파일시스템 내부 동기화 primitive입니다. 실제 lock일 필요는 없으며 파일시스템 작성자가 조정 방식을 결정합니다.
iomap internal operation lock은 iomap 함수가 mapping을 보유한 상태에서 잡는 동기화 primitive의 일반 명칭입니다. pagecache를 읽거나 쓸 때 folio lock을 잡는 것이 구체적 예입니다.
pure overwrite는 submit 또는 completion 중 metadata 작업이나 zeroing 작업이 필요 없는 write입니다. 파일시스템은 공간을 이미 `IOMAP_MAPPED`로 할당했고 I/O alignment나 size에 별도 제약을 두지 않아야 합니다. 남는 alignment 제약은 보통 sector size인 device의 minimum I/O size와 alignment뿐입니다.
각 primitive가 보호하는 상태와 mode를 구분합니다.
File Range Iterator
===================
Definitions
-----------
* **buffer head**: Shattered remnants of the old buffer cache.
* ``fsblock``: The block size of a file, also known as ``i_blocksize``.
* ``i_rwsem``: The VFS ``struct inode`` rwsemaphore.
Processes hold this in shared mode to read file state and contents.
Some filesystems may allow shared mode for writes.
Processes often hold this in exclusive mode to change file state and
contents.
* ``invalidate_lock``: The pagecache ``struct address_space``
rwsemaphore that protects against folio insertion and removal for
filesystems that support punching out folios below EOF.
Processes wishing to insert folios must hold this lock in shared
mode to prevent removal, though concurrent insertion is allowed.
Processes wishing to remove folios must hold this lock in exclusive
mode to prevent insertions.
Concurrent removals are not allowed.
* ``dax_read_lock``: The RCU read lock that dax takes to prevent a
device pre-shutdown hook from returning before other threads have
released resources.
* **filesystem mapping lock**: This synchronization primitive is
internal to the filesystem and must protect the file mapping data
from updates while a mapping is being sampled.
The filesystem author must determine how this coordination should
happen; it does not need to be an actual lock.
* **iomap internal operation lock**: This is a general term for
synchronization primitives that iomap functions take while holding a
mapping.
A specific example would be taking the folio lock while reading or
writing the pagecache.
* **pure overwrite**: A write operation that does not require any
metadata or zeroing operations to perform during either submission
or completion.
This implies that the filesystem must have already allocated space
on disk as ``IOMAP_MAPPED`` and the filesystem must not place any
constraints on IO alignment or size.
The only constraints on I/O alignment are device level (minimum I/O
size and alignment, typically sector size).
`struct iomap`과 mapping type
151-214파일시스템은 `struct iomap`으로 파일의 byte 범위를 storage device의 byte 범위에 연결해 iomap iterator에 전달합니다. 구조체에는 `addr`, `offset`, `length`, `type`, `flags`, `bdev`, `dax_dev`, `inline_data`, `private`, `validity_cookie`가 있습니다.
`offset`과 `length`는 이 mapping이 덮는 file offset 범위를 byte 단위로 나타내며 파일시스템이 항상 설정해야 합니다. `type`은 공간 mapping의 종류를 나타냅니다.
`IOMAP_HOLE`은 storage가 할당되지 않은 상태입니다. write는 공간을 할당하고 mapping을 반환해야 하므로 `IOMAP_WRITE`에 대한 응답으로 절대 반환하면 안 됩니다. `addr`는 `IOMAP_NULL_ADDR`여야 하며 iomap은 pagecache든 direct I/O든 hole에 쓰는 것을 지원하지 않습니다.
`IOMAP_DELALLOC`은 나중에 공간을 할당하겠다는 delayed allocation 약속입니다. 파일시스템이 이 상태와 `IOMAP_F_NEW`를 반환했는데 write가 실패하면 `->iomap_end`가 reservation을 삭제해야 합니다. `addr`는 `IOMAP_NULL_ADDR`여야 합니다.
`IOMAP_MAPPED`는 파일 범위가 storage device의 특정 공간에 연결된 상태입니다. device는 `bdev` 또는 `dax_dev`, byte 단위 device address는 `addr`로 반환합니다.
`IOMAP_UNWRITTEN`은 storage의 특정 공간에 연결됐지만 아직 초기화되지 않은 상태입니다. device와 address 전달 방식은 MAPPED와 같습니다. read는 호출자에게 zero를 반환하고, write 또는 writeback의 ioend는 mapping을 MAPPED로 바꿔야 합니다. 자세한 내용은 ioend 절을 참조합니다.
`IOMAP_INLINE`은 파일 범위가 `inline_data`가 가리키는 memory buffer에 연결된 상태입니다. write에서는 `->iomap_end`가 data 영속화를 처리할 것으로 예상됩니다. `addr`는 `IOMAP_NULL_ADDR`여야 합니다.
공간 할당 상태와 필수 field를 정리했습니다.
``struct iomap``
----------------
The filesystem communicates to the iomap iterator the mapping of
byte ranges of a file to byte ranges of a storage device with the
structure below:
.. code-block:: c
struct iomap {
u64 addr;
loff_t offset;
u64 length;
u16 type;
u16 flags;
struct block_device *bdev;
struct dax_device *dax_dev;
void *inline_data;
void *private;
u64 validity_cookie;
};
The fields are as follows:
* ``offset`` and ``length`` describe the range of file offsets, in
bytes, covered by this mapping.
These fields must always be set by the filesystem.
* ``type`` describes the type of the space mapping:
* **IOMAP_HOLE**: No storage has been allocated.
This type must never be returned in response to an ``IOMAP_WRITE``
operation because writes must allocate and map space, and return
the mapping.
The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
iomap does not support writing (whether via pagecache or direct
I/O) to a hole.
* **IOMAP_DELALLOC**: A promise to allocate space at a later time
("delayed allocation").
If the filesystem returns IOMAP_F_NEW here and the write fails, the
``->iomap_end`` function must delete the reservation.
The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
* **IOMAP_MAPPED**: The file range maps to specific space on the
storage device.
The device is returned in ``bdev`` or ``dax_dev``.
The device address, in bytes, is returned via ``addr``.
* **IOMAP_UNWRITTEN**: The file range maps to specific space on the
storage device, but the space has not yet been initialized.
The device is returned in ``bdev`` or ``dax_dev``.
The device address, in bytes, is returned via ``addr``.
Reads from this type of mapping will return zeroes to the caller.
For a write or writeback operation, the ioend should update the
mapping to MAPPED.
Refer to the sections about ioends for more details.
* **IOMAP_INLINE**: The file range maps to the memory buffer
specified by ``inline_data``.
For write operation, the ``->iomap_end`` function presumably
handles persisting the data.
The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
`struct iomap` flag와 나머지 field
215-302`flags`는 공간 mapping의 상태를 나타냅니다. 다음 flag들은 파일시스템이 `->iomap_begin`에서 설정해야 합니다.
`IOMAP_F_NEW`는 mapping 아래 공간이 새로 할당됐다는 뜻입니다. 쓰지 않을 영역은 zeroing해야 하고, write가 실패했으며 mapping이 공간 reservation이면 그 reservation을 삭제해야 합니다.
`IOMAP_F_DIRTY`는 기록된 data에 접근하는 데 필요한 미commit metadata가 inode에 있음을 뜻합니다. 이를 persistent storage에 commit하려면 `fdatasync`가 필요하며, direct I/O 완료 시 file size 갱신처럼 I/O completion에서 생길 수 있는 metadata 변경까지 고려해야 합니다.
`IOMAP_F_SHARED`는 mapping 아래 공간이 공유되어 다른 파일 data를 손상하지 않으려면 copy-on-write가 필요하다는 뜻입니다. `IOMAP_F_BUFFER_HEAD`는 pagecache 연산에 buffer head가 필요하다는 뜻이며 새 사용처를 추가하면 안 됩니다.
`IOMAP_F_MERGED`는 연속 block mapping 여러 개를 하나로 합쳤다는 뜻이고 FIEMAP에서만 유용합니다. `IOMAP_F_XATTR`는 일반 file data가 아니라 extended attribute data의 mapping이며 역시 FIEMAP 전용입니다.
`IOMAP_F_BOUNDARY`는 I/O와 completion을 다른 I/O 또는 completion과 합치면 안 된다는 뜻입니다. ZNS device처럼 특정 LBA 경계를 넘는 I/O를 처리할 수 없는 device에 제출할 때 파일시스템이 사용해야 합니다. buffered I/O writeback에만 적용되고 다른 함수는 무시합니다.
`IOMAP_F_PRIVATE`는 파일시스템 private 용도로 예약되어 있습니다. `IOMAP_F_ANON_WRITE`는 write I/O에 아직 target block이 없고 파일시스템이 bio submission handler에서 이를 배정하면서 필요하면 I/O를 나눌 것임을 나타냅니다.
`IOMAP_F_ATOMIC_BIO`는 write I/O의 bio에 `REQ_ATOMIC`을 설정해야 한다는 뜻입니다. HW-offload 기반 torn-write 보호가 필요한 연산임을 iomap에 알리며, 파일시스템은 I/O 완료 후 mapping 갱신도 단일 metadata update로 수행해야 합니다.
다음 flag는 파일 연산 중 iomap 자체가 설정할 수 있습니다. 파일시스템이 관찰해야 한다면 `->iomap_end`를 제공해야 합니다. `IOMAP_F_SIZE_CHANGED`는 이 mapping 사용으로 file size가 바뀌었음을 뜻합니다. `IOMAP_F_STALE`은 mapping이 stale임을 뜻하며 iomap은 해당 mapping에 `->iomap_end`를 호출한 뒤 새 mapping을 얻으려고 `->iomap_begin`을 호출합니다. 현재 이 두 flag는 pagecache 연산만 설정합니다.
`addr`는 byte 단위 device address입니다. `bdev`는 block device이며 mapped 또는 unwritten 연산에서만 설정해야 합니다. `dax_dev`는 DAX device이며 fsdax의 mapped 또는 unwritten 연산에서만 설정합니다. `inline_data`는 `IOMAP_INLINE` I/O의 memory buffer이고 다른 type에서는 무시됩니다.
`private`는 filesystem-private information pointer이며 변경 없이 `->iomap_end`에 전달됩니다. `validity_cookie`는 파일시스템이 설정하는 mapping freshness 값으로 stale mapping 검출에 사용합니다. page fault가 일어날 수 있어 `->iomap_begin`과 `->iomap_end` 사이에 파일시스템 lock을 유지하면 안 되는 pagecache 연산에서는 정확성에 필수입니다. mapping이 완전히 static인 파일시스템은 설정할 필요가 없습니다. mapping 재검증은 pagecache 연산만 수행하며 자세한 내용은 `iomap_valid` 절을 참조합니다.
begin callback이 mapping의 상태와 제약을 전달합니다.
pagecache 연산이 end callback에 알려 주는 상태입니다.
* ``flags`` describe the status of the space mapping.
These flags should be set by the filesystem in ``->iomap_begin``:
* **IOMAP_F_NEW**: The space under the mapping is newly allocated.
Areas that will not be written to must be zeroed.
If a write fails and the mapping is a space reservation, the
reservation must be deleted.
* **IOMAP_F_DIRTY**: The inode will have uncommitted metadata needed
to access any data written.
fdatasync is required to commit these changes to persistent
storage.
This needs to take into account metadata changes that *may* be made
at I/O completion, such as file size updates from direct I/O.
* **IOMAP_F_SHARED**: The space under the mapping is shared.
Copy on write is necessary to avoid corrupting other file data.
* **IOMAP_F_BUFFER_HEAD**: This mapping requires the use of buffer
heads for pagecache operations.
Do not add more uses of this.
* **IOMAP_F_MERGED**: Multiple contiguous block mappings were
coalesced into this single mapping.
This is only useful for FIEMAP.
* **IOMAP_F_XATTR**: The mapping is for extended attribute data, not
regular file data.
This is only useful for FIEMAP.
* **IOMAP_F_BOUNDARY**: This indicates I/O and its completion must not be
merged with any other I/O or completion. Filesystems must use this when
submitting I/O to devices that cannot handle I/O crossing certain LBAs
(e.g. ZNS devices). This flag applies only to buffered I/O writeback; all
other functions ignore it.
* **IOMAP_F_PRIVATE**: This flag is reserved for filesystem private use.
* **IOMAP_F_ANON_WRITE**: Indicates that (write) I/O does not have a target
block assigned to it yet and the file system will do that in the bio
submission handler, splitting the I/O as needed.
* **IOMAP_F_ATOMIC_BIO**: This indicates write I/O must be submitted with the
``REQ_ATOMIC`` flag set in the bio. Filesystems need to set this flag to
inform iomap that the write I/O operation requires torn-write protection
based on HW-offload mechanism. They must also ensure that mapping updates
upon the completion of the I/O must be performed in a single metadata
update.
These flags can be set by iomap itself during file operations.
The filesystem should supply an ``->iomap_end`` function if it needs
to observe these flags:
* **IOMAP_F_SIZE_CHANGED**: The file size has changed as a result of
using this mapping.
* **IOMAP_F_STALE**: The mapping was found to be stale.
iomap will call ``->iomap_end`` on this mapping and then
``->iomap_begin`` to obtain a new mapping.
Currently, these flags are only set by pagecache operations.
* ``addr`` describes the device address, in bytes.
* ``bdev`` describes the block device for this mapping.
This only needs to be set for mapped or unwritten operations.
* ``dax_dev`` describes the DAX device for this mapping.
This only needs to be set for mapped or unwritten operations, and
only for a fsdax operation.
* ``inline_data`` points to a memory buffer for I/O involving
``IOMAP_INLINE`` mappings.
This value is ignored for all other mapping types.
* ``private`` is a pointer to `filesystem-private information
<https://lore.kernel.org/all/20180619164137.13720-7-hch@lst.de/>`_.
This value will be passed unchanged to ``->iomap_end``.
* ``validity_cookie`` is a magic freshness value set by the filesystem
that should be used to detect stale mappings.
For pagecache operations this is critical for correct operation
because page faults can occur, which implies that filesystem locks
should not be held between ``->iomap_begin`` and ``->iomap_end``.
Filesystems with completely static mappings need not set this value.
Only pagecache operations revalidate mappings; see the section about
``iomap_valid`` for details.
`struct iomap_ops` callback
303-320모든 iomap 함수는 mapping을 얻고 선택적으로 해제하기 위한 operation 구조체를 파일시스템에서 받아야 합니다.
`struct iomap_ops`의 `iomap_begin` callback은 `inode`, `pos`, `length`, `flags`, 결과 `iomap`, 선택적 source `srcmap`을 받습니다. `iomap_end` callback은 `inode`, `pos`, `length`, 실제 처리량 `written`, 같은 `flags`, 사용한 `iomap`을 받습니다.
두 callback을 분리함으로써 iterator가 mapping을 사용하는 동안의 context를 파일시스템이 준비하고, 작업 결과에 따라 reservation commit·해제 같은 정리를 선택적으로 수행할 수 있습니다.
mapping 획득과 사용 후 정리를 callback으로 연결합니다.
``struct iomap_ops``
--------------------
Every iomap function requires the filesystem to pass an operations
structure to obtain a mapping and (optionally) to release the mapping:
.. code-block:: c
struct iomap_ops {
int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length,
unsigned flags, struct iomap *iomap,
struct iomap *srcmap);
int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length,
ssize_t written, unsigned flags,
struct iomap *iomap);
};
`->iomap_begin`의 mapping 계약
321-379iomap 연산은 `inode` 파일의 `pos`와 `length`가 지정한 byte 범위에 대해 하나의 file mapping을 얻으려고 `->iomap_begin`을 호출합니다. 결과는 `iomap` pointer로 반환합니다. mapping은 요청 범위의 첫 byte를 반드시 포함해야 하지만 전체 요청 범위를 덮을 필요는 없습니다.
각 iomap 연산은 `flags` 인수로 요청 종류를 설명하며 정확한 값은 각 연산 절에서 문서화합니다. 원칙적으로 여러 연산에 공통 적용될 수 있는 flag가 있습니다.
`IOMAP_DIRECT`는 호출자가 block storage에 file I/O를 발행하려는 경우, `IOMAP_DAX`는 memory-like storage에 file I/O를 발행하려는 경우 설정됩니다.
`IOMAP_NOWAIT`는 submitting task를 block할 수 있는 연산을 피하려고 best-effort로 시도한다는 뜻입니다. 목적은 network API의 `O_NONBLOCK`과 비슷하며, asynchronous application이 특정 파일시스템 resource를 기다리지 않고 다른 작업을 계속하도록 합니다.
`IOMAP_NOWAIT`를 구현하는 파일시스템은 trylock 알고리즘을 사용하고 전체 I/O 요청 범위를 하나의 iomap mapping으로 충족할 수 있어야 합니다. metadata를 동기적으로 읽거나 쓰지 말고, blocking memory allocation을 피하며, 변경을 위한 transaction reservation을 기다리지 말아야 합니다. 새 공간도 할당하지 않는 편이 좋습니다.
특정 NOWAIT 연산이 block할 가능성이 있는지 조금이라도 의심되면 작업을 시작해 task를 막기보다 가능한 한 일찍 `-EAGAIN`을 반환해야 합니다. 이 flag는 흔히 `IOCB_NOWAIT` 또는 `RWF_NOWAIT`를 대신해 설정됩니다.
`IOMAP_DONTCACHE`는 buffered file I/O를 수행한 뒤 pagecache가 다른 thread에서 사용 중이지 않으면 kernel이 이를 버리기를 호출자가 원한다는 뜻입니다.
기존 file content를 다른 device 또는 같은 device의 다른 address range에서 읽어야 한다면 파일시스템은 그 정보를 `srcmap`으로 반환해야 합니다. 한 mapping에서 읽고 다른 mapping에 쓰는 기능은 pagecache와 fsdax 연산만 지원합니다.
호출자가 요구하는 I/O 경로와 blocking 정책입니다.
``->iomap_begin``
~~~~~~~~~~~~~~~~~
iomap operations call ``->iomap_begin`` to obtain one file mapping for
the range of bytes specified by ``pos`` and ``length`` for the file
``inode``.
This mapping should be returned through the ``iomap`` pointer.
The mapping must cover at least the first byte of the supplied file
range, but it does not need to cover the entire requested range.
Each iomap operation describes the requested operation through the
``flags`` argument.
The exact value of ``flags`` will be documented in the
operation-specific sections below.
These flags can, at least in principle, apply generally to iomap
operations:
* ``IOMAP_DIRECT`` is set when the caller wishes to issue file I/O to
block storage.
* ``IOMAP_DAX`` is set when the caller wishes to issue file I/O to
memory-like storage.
* ``IOMAP_NOWAIT`` is set when the caller wishes to perform a best
effort attempt to avoid any operation that would result in blocking
the submitting task.
This is similar in intent to ``O_NONBLOCK`` for network APIs - it is
intended for asynchronous applications to keep doing other work
instead of waiting for the specific unavailable filesystem resource
to become available.
Filesystems implementing ``IOMAP_NOWAIT`` semantics need to use
trylock algorithms.
They need to be able to satisfy the entire I/O request range with a
single iomap mapping.
They need to avoid reading or writing metadata synchronously.
They need to avoid blocking memory allocations.
They need to avoid waiting on transaction reservations to allow
modifications to take place.
They probably should not be allocating new space.
And so on.
If there is any doubt in the filesystem developer's mind as to
whether any specific ``IOMAP_NOWAIT`` operation may end up blocking,
then they should return ``-EAGAIN`` as early as possible rather than
start the operation and force the submitting task to block.
``IOMAP_NOWAIT`` is often set on behalf of ``IOCB_NOWAIT`` or
``RWF_NOWAIT``.
* ``IOMAP_DONTCACHE`` is set when the caller wishes to perform a
buffered file I/O and would like the kernel to drop the pagecache
after the I/O completes, if it isn't already being used by another
thread.
If it is necessary to read existing file contents from a `different
<https://lore.kernel.org/all/20191008071527.29304-9-hch@lst.de/>`_
device or address range on a device, the filesystem should return that
information via ``srcmap``.
Only pagecache and fsdax operations support reading from one mapping and
writing to another.
`->iomap_end`의 정리 계약
380-396연산이 끝나면 `->iomap_end`가 존재하는 경우 iomap이 mapping 사용을 마쳤음을 알리기 위해 호출됩니다. 구현은 보통 `->iomap_begin`에서 마련한 context를 해체하는 데 사용합니다.
예를 들어 write는 실제로 처리한 byte에 대한 reservation을 commit하고 처리하지 않은 공간은 unreserve할 수 있습니다. 아무 byte도 건드리지 않았다면 `written`은 0일 수 있습니다. `flags`에는 `->iomap_begin`에 전달한 것과 같은 값이 들어갑니다.
read용 iomap ops는 이 callback을 제공할 필요가 거의 없습니다. `->iomap_begin`과 `->iomap_end` 모두 오류 시 음수 errno, 성공 시 0을 반환해야 합니다.
``->iomap_end``
~~~~~~~~~~~~~~~
After the operation completes, the ``->iomap_end`` function, if present,
is called to signal that iomap is finished with a mapping.
Typically, implementations will use this function to tear down any
context that were set up in ``->iomap_begin``.
For example, a write might wish to commit the reservations for the bytes
that were operated upon and unreserve any space that was not operated
upon.
``written`` might be zero if no bytes were touched.
``flags`` will contain the same value passed to ``->iomap_begin``.
iomap ops for reads are not likely to need to supply this function.
Both functions should return a negative errno code on error, or zero on
success.
파일 연산 전 VFS 준비
397-405iomap은 mapping과 I/O만 처리합니다. 파일시스템은 I/O 연산을 시작하기 전에 입력 parameter와 file state를 검사하도록 여전히 VFS를 호출해야 합니다.
iomap은 filesystem freeze protection 획득, timestamp 갱신, privilege 제거, access control을 처리하지 않습니다. 이 준비 작업은 iomap 바깥의 파일시스템·VFS 경로가 책임집니다.
Preparing for File Operations
=============================
iomap only handles mapping and I/O.
Filesystems must still call out to the VFS to check input parameters
and file state before initiating an I/O operation.
It does not handle obtaining filesystem freeze protection, updating of
timestamps, stripping privileges, or access control.
iomap locking 계층
406-449iomap은 파일시스템이 자체 locking model을 제공하도록 요구합니다. iomap 관점의 동기화 primitive는 upper, lower, operation 세 범주입니다.
upper-level primitive는 서로 다른 iomap 연산의 접근을 조정하려고 파일시스템이 제공합니다. 정확한 primitive는 파일시스템과 연산에 따라 다르지만 흔히 VFS inode lock, pagecache invalidation lock, folio lock입니다. 예를 들어 `iomap_file_buffered_write`와 `iomap_file_unshare`가 서로 상태를 덮어쓰지 않도록 호출 전에 `i_rwsem`을 잡을 수 있습니다. pagecache writeback은 writeback이 시작될 때까지 다른 thread의 folio 접근을 막으려고 folio를 lock할 수 있습니다.
lower-level primitive는 file space mapping 정보 접근을 조정하려고 파일시스템이 `->iomap_begin`과 `->iomap_end`에서 잡습니다. 이 primitive를 보유한 동안 iomap object field를 채워야 합니다. upper primitive가 있다면 유지한 채 lower primitive를 획득합니다. XFS는 mapping sampling 중 `ILOCK_EXCL`, ext4는 `i_data_sem`을 잡습니다. mapping 정보가 immutable이면 이 단계의 동기화가 필요 없을 수 있습니다.
operation primitive는 iomap 연산이 자체 내부 data structure 접근을 조정하려고 잡습니다. upper primitive가 있다면 유지한 채 획득하지만 lower primitive는 보유하지 않은 상태여야 합니다. 예를 들어 pagecache write는 file mapping을 얻은 뒤 새 content를 복사하려고 folio를 획득해 lock하고, metadata를 갱신하려고 내부 folio state object도 lock할 수 있습니다.
정확한 locking 요구사항은 파일시스템별로 다르며 어떤 연산에서는 일부 lock을 생략할 수 있습니다. 이후 문서의 locking 언급은 의무가 아니라 권고입니다. 각 파일시스템 작성자가 자신의 locking을 결정해야 합니다.
upper는 유지할 수 있지만 lower와 operation은 동시에 보유하지 않습니다.
획득 위치와 대표 구현을 비교합니다.
Locking Hierarchy
=================
iomap requires that filesystems supply their own locking model.
There are three categories of synchronization primitives, as far as
iomap is concerned:
* The **upper** level primitive is provided by the filesystem to
coordinate access to different iomap operations.
The exact primitive is specific to the filesystem and operation,
but is often a VFS inode, pagecache invalidation, or folio lock.
For example, a filesystem might take ``i_rwsem`` before calling
``iomap_file_buffered_write`` and ``iomap_file_unshare`` to prevent
these two file operations from clobbering each other.
Pagecache writeback may lock a folio to prevent other threads from
accessing the folio until writeback is underway.
* The **lower** level primitive is taken by the filesystem in the
``->iomap_begin`` and ``->iomap_end`` functions to coordinate
access to the file space mapping information.
The fields of the iomap object should be filled out while holding
this primitive.
The upper level synchronization primitive, if any, remains held
while acquiring the lower level synchronization primitive.
For example, XFS takes ``ILOCK_EXCL`` and ext4 takes ``i_data_sem``
while sampling mappings.
Filesystems with immutable mapping information may not require
synchronization here.
* The **operation** primitive is taken by an iomap operation to
coordinate access to its own internal data structures.
The upper level synchronization primitive, if any, remains held
while acquiring this primitive.
The lower level primitive is not held while acquiring this
primitive.
For example, pagecache write operations will obtain a file mapping,
then grab and lock a folio to copy new contents.
It may also lock an internal folio state object to update metadata.
The exact locking requirements are specific to the filesystem; for
certain operations, some of these locks can be elided.
All further mentions of locking are *recommendations*, not mandates.
Each filesystem author must figure out the locking for themself.
알려진 버그와 한계
450-459현재 iomap은 fscrypt와 compression을 지원하지 않으며 fsverity도 아직 지원하지 않습니다.
I/O가 XFS 방식으로 동작해야 한다는 강한 가정이 남아 있고, regular file data가 아닌 data에도 iomap이 실제로 올바르게 동작하는지는 질문으로 남아 있습니다.
원문은 이러한 한계를 개선할 patch를 환영한다고 마무리합니다.
원문이 명시한 미지원 기능과 공개 질문입니다.
Bugs and Limitations
====================
* No support for fscrypt.
* No support for compression.
* No support for fsverity yet.
* Strong assumptions that IO should work the way it does on XFS.
* Does iomap *actually* work for non-regular file data?
Patches welcome!
요약·해설
design.rst:1-459iomap은 파일 offset 범위의 mapping을 얻는 iterator 계층과 그 mapping에 실제 I/O를 수행하는 상위 계층을 분리합니다. 가능한 한 큰 mapping을 사용해 allocation 판단과 mapping 호출 비용을 개선하며 pagecache, direct I/O, fsdax, FIEMAP 등 여러 연산의 공통 기반을 제공합니다.
파일시스템 구현에서 가장 중요한 계약은 `->iomap_begin`이 요청 첫 byte를 포함하는 유효한 `struct iomap`을 반환하고, 필요하면 `->iomap_end`가 실제 처리량에 따라 reservation과 context를 정리하는 것입니다. mapping type, `IOMAP_F_*` flag, `validity_cookie`, `srcmap`의 의미를 정확히 지켜야 합니다.
locking은 iomap이 대신 정하지 않습니다. 파일시스템은 upper mapping-operation 조정, lower mapping metadata sampling, iomap 내부 operation lock의 순서를 설계해야 하며, lower lock을 operation lock과 동시에 보유하지 않는 계층 관계를 유지해야 합니다.
새 filesystem iomap 경로를 검토할 때의 핵심 항목입니다.