← Documents Documentation/filesystems/iomap/design.rst GitHub 원문 ↗

Linux 6.18.37 · Filesystems

iomap Library Design

iomap iterator, struct iomap, callback 계약, operation flag와 locking hierarchy를 설명하는 전문 번역입니다.

Source pathDocumentation/filesystems/iomap/design.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

design.rst:1-459

iomap은 파일 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과 동시에 보유하지 않는 계층 관계를 유지해야 합니다.

iomap 구현 검토 순서
VFS parameter·state·freeze·access 준비upper lock으로 operation 사이 조정`->iomap_begin`에서 lower lock과 mapping 생성mapping type·flag·range·device 검증lower lock 해제 후 operation lock으로 I/O`->iomap_end`에서 결과와 reservation 정리

새 filesystem iomap 경로를 검토할 때의 핵심 항목입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2 .. _iomap_design:
3
4 ..
5 Dumb style notes to maintain the author's sanity:
6 Please try to start sentences on separate lines so that
7 sentence changes don't bleed colors in diff.
8 Heading decorations are documented in sphinx.rst.
9
10 ==============
11 Library Design
12 ==============
13
14 .. contents:: Table of Contents
15 :local:
16
17 Introduction
18 ============
19
20 iomap is a filesystem library for handling common file operations.
21 The library has two layers:
22
23 1. A lower layer that provides an iterator over ranges of file offsets.
24 This layer tries to obtain mappings of each file ranges to storage
25 from the filesystem, but the storage information is not necessarily
26 required.
27
28 2. An upper layer that acts upon the space mappings provided by the
29 lower layer iterator.
30
31 The iteration can involve mappings of file's logical offset ranges to
32 physical extents, but the storage layer information is not necessarily
33 required, e.g. for walking cached file information.
34 The library exports various APIs for implementing file operations such
35 as:
36
37 * Pagecache reads and writes
38 * Folio write faults to the pagecache
39 * Writeback of dirty folios
40 * Direct I/O reads and writes
41 * fsdax I/O reads, writes, loads, and stores
42 * FIEMAP
43 * lseek ``SEEK_DATA`` and ``SEEK_HOLE``
44 * swapfile activation
45
46 This origins of this library is the file I/O path that XFS once used; it
47 has now been extended to cover several other operations.
48
49 Who Should Read This?
50 =====================
51
52 The target audience for this document are filesystem, storage, and
53 pagecache programmers and code reviewers.
54
55 If you are working on PCI, machine architectures, or device drivers, you
56 are most likely in the wrong place.
57
58 How Is This Better?
59 ===================
60
61 Unlike the classic Linux I/O model which breaks file I/O into small
62 units (generally memory pages or blocks) and looks up space mappings on
63 the basis of that unit, the iomap model asks the filesystem for the
64 largest space mappings that it can create for a given file operation and
65 initiates operations on that basis.
66 This strategy improves the filesystem's visibility into the size of the
67 operation being performed, which enables it to combat fragmentation with
68 larger space allocations when possible.
69 Larger space mappings improve runtime performance by amortizing the cost
70 of mapping function calls into the filesystem across a larger amount of
71 data.
72
73 At a high level, an iomap operation `looks like this
74 <https://lore.kernel.org/all/[email protected]/>`_:
75
76 1. For each byte in the operation range...
77
78 1. Obtain a space mapping via ``->iomap_begin``
79
80 2. For each sub-unit of work...
81
82 1. Revalidate the mapping and go back to (1) above, if necessary.
83 So far only the pagecache operations need to do this.
84
85 2. Do the work
86
87 3. Increment operation cursor
88
89 4. Release the mapping via ``->iomap_end``, if necessary
90
91 Each iomap operation will be covered in more detail below.
92 This library was covered previously by an `LWN article
93 <https://lwn.net/Articles/935934/>`_ and a `KernelNewbies page
94 <https://kernelnewbies.org/KernelProjects/iomap>`_.
95
96 The goal of this document is to provide a brief discussion of the
97 design and capabilities of iomap, followed by a more detailed catalog
98 of the interfaces presented by iomap.
99 If you change iomap, please update this design document.
100
101 File Range Iterator
102 ===================
103
104 Definitions
105 -----------
106
107 * **buffer head**: Shattered remnants of the old buffer cache.
108
109 * ``fsblock``: The block size of a file, also known as ``i_blocksize``.
110
111 * ``i_rwsem``: The VFS ``struct inode`` rwsemaphore.
112 Processes hold this in shared mode to read file state and contents.
113 Some filesystems may allow shared mode for writes.
114 Processes often hold this in exclusive mode to change file state and
115 contents.
116
117 * ``invalidate_lock``: The pagecache ``struct address_space``
118 rwsemaphore that protects against folio insertion and removal for
119 filesystems that support punching out folios below EOF.
120 Processes wishing to insert folios must hold this lock in shared
121 mode to prevent removal, though concurrent insertion is allowed.
122 Processes wishing to remove folios must hold this lock in exclusive
123 mode to prevent insertions.
124 Concurrent removals are not allowed.
125
126 * ``dax_read_lock``: The RCU read lock that dax takes to prevent a
127 device pre-shutdown hook from returning before other threads have
128 released resources.
129
130 * **filesystem mapping lock**: This synchronization primitive is
131 internal to the filesystem and must protect the file mapping data
132 from updates while a mapping is being sampled.
133 The filesystem author must determine how this coordination should
134 happen; it does not need to be an actual lock.
135
136 * **iomap internal operation lock**: This is a general term for
137 synchronization primitives that iomap functions take while holding a
138 mapping.
139 A specific example would be taking the folio lock while reading or
140 writing the pagecache.
141
142 * **pure overwrite**: A write operation that does not require any
143 metadata or zeroing operations to perform during either submission
144 or completion.
145 This implies that the filesystem must have already allocated space
146 on disk as ``IOMAP_MAPPED`` and the filesystem must not place any
147 constraints on IO alignment or size.
148 The only constraints on I/O alignment are device level (minimum I/O
149 size and alignment, typically sector size).
150
151 ``struct iomap``
152 ----------------
153
154 The filesystem communicates to the iomap iterator the mapping of
155 byte ranges of a file to byte ranges of a storage device with the
156 structure below:
157
158 .. code-block:: c
159
160 struct iomap {
161 u64 addr;
162 loff_t offset;
163 u64 length;
164 u16 type;
165 u16 flags;
166 struct block_device *bdev;
167 struct dax_device *dax_dev;
168 void *inline_data;
169 void *private;
170 u64 validity_cookie;
171 };
172
173 The fields are as follows:
174
175 * ``offset`` and ``length`` describe the range of file offsets, in
176 bytes, covered by this mapping.
177 These fields must always be set by the filesystem.
178
179 * ``type`` describes the type of the space mapping:
180
181 * **IOMAP_HOLE**: No storage has been allocated.
182 This type must never be returned in response to an ``IOMAP_WRITE``
183 operation because writes must allocate and map space, and return
184 the mapping.
185 The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
186 iomap does not support writing (whether via pagecache or direct
187 I/O) to a hole.
188
189 * **IOMAP_DELALLOC**: A promise to allocate space at a later time
190 ("delayed allocation").
191 If the filesystem returns IOMAP_F_NEW here and the write fails, the
192 ``->iomap_end`` function must delete the reservation.
193 The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
194
195 * **IOMAP_MAPPED**: The file range maps to specific space on the
196 storage device.
197 The device is returned in ``bdev`` or ``dax_dev``.
198 The device address, in bytes, is returned via ``addr``.
199
200 * **IOMAP_UNWRITTEN**: The file range maps to specific space on the
201 storage device, but the space has not yet been initialized.
202 The device is returned in ``bdev`` or ``dax_dev``.
203 The device address, in bytes, is returned via ``addr``.
204 Reads from this type of mapping will return zeroes to the caller.
205 For a write or writeback operation, the ioend should update the
206 mapping to MAPPED.
207 Refer to the sections about ioends for more details.
208
209 * **IOMAP_INLINE**: The file range maps to the memory buffer
210 specified by ``inline_data``.
211 For write operation, the ``->iomap_end`` function presumably
212 handles persisting the data.
213 The ``addr`` field must be set to ``IOMAP_NULL_ADDR``.
214
215 * ``flags`` describe the status of the space mapping.
216 These flags should be set by the filesystem in ``->iomap_begin``:
217
218 * **IOMAP_F_NEW**: The space under the mapping is newly allocated.
219 Areas that will not be written to must be zeroed.
220 If a write fails and the mapping is a space reservation, the
221 reservation must be deleted.
222
223 * **IOMAP_F_DIRTY**: The inode will have uncommitted metadata needed
224 to access any data written.
225 fdatasync is required to commit these changes to persistent
226 storage.
227 This needs to take into account metadata changes that *may* be made
228 at I/O completion, such as file size updates from direct I/O.
229
230 * **IOMAP_F_SHARED**: The space under the mapping is shared.
231 Copy on write is necessary to avoid corrupting other file data.
232
233 * **IOMAP_F_BUFFER_HEAD**: This mapping requires the use of buffer
234 heads for pagecache operations.
235 Do not add more uses of this.
236
237 * **IOMAP_F_MERGED**: Multiple contiguous block mappings were
238 coalesced into this single mapping.
239 This is only useful for FIEMAP.
240
241 * **IOMAP_F_XATTR**: The mapping is for extended attribute data, not
242 regular file data.
243 This is only useful for FIEMAP.
244
245 * **IOMAP_F_BOUNDARY**: This indicates I/O and its completion must not be
246 merged with any other I/O or completion. Filesystems must use this when
247 submitting I/O to devices that cannot handle I/O crossing certain LBAs
248 (e.g. ZNS devices). This flag applies only to buffered I/O writeback; all
249 other functions ignore it.
250
251 * **IOMAP_F_PRIVATE**: This flag is reserved for filesystem private use.
252
253 * **IOMAP_F_ANON_WRITE**: Indicates that (write) I/O does not have a target
254 block assigned to it yet and the file system will do that in the bio
255 submission handler, splitting the I/O as needed.
256
257 * **IOMAP_F_ATOMIC_BIO**: This indicates write I/O must be submitted with the
258 ``REQ_ATOMIC`` flag set in the bio. Filesystems need to set this flag to
259 inform iomap that the write I/O operation requires torn-write protection
260 based on HW-offload mechanism. They must also ensure that mapping updates
261 upon the completion of the I/O must be performed in a single metadata
262 update.
263
264 These flags can be set by iomap itself during file operations.
265 The filesystem should supply an ``->iomap_end`` function if it needs
266 to observe these flags:
267
268 * **IOMAP_F_SIZE_CHANGED**: The file size has changed as a result of
269 using this mapping.
270
271 * **IOMAP_F_STALE**: The mapping was found to be stale.
272 iomap will call ``->iomap_end`` on this mapping and then
273 ``->iomap_begin`` to obtain a new mapping.
274
275 Currently, these flags are only set by pagecache operations.
276
277 * ``addr`` describes the device address, in bytes.
278
279 * ``bdev`` describes the block device for this mapping.
280 This only needs to be set for mapped or unwritten operations.
281
282 * ``dax_dev`` describes the DAX device for this mapping.
283 This only needs to be set for mapped or unwritten operations, and
284 only for a fsdax operation.
285
286 * ``inline_data`` points to a memory buffer for I/O involving
287 ``IOMAP_INLINE`` mappings.
288 This value is ignored for all other mapping types.
289
290 * ``private`` is a pointer to `filesystem-private information
291 <https://lore.kernel.org/all/[email protected]/>`_.
292 This value will be passed unchanged to ``->iomap_end``.
293
294 * ``validity_cookie`` is a magic freshness value set by the filesystem
295 that should be used to detect stale mappings.
296 For pagecache operations this is critical for correct operation
297 because page faults can occur, which implies that filesystem locks
298 should not be held between ``->iomap_begin`` and ``->iomap_end``.
299 Filesystems with completely static mappings need not set this value.
300 Only pagecache operations revalidate mappings; see the section about
301 ``iomap_valid`` for details.
302
303 ``struct iomap_ops``
304 --------------------
305
306 Every iomap function requires the filesystem to pass an operations
307 structure to obtain a mapping and (optionally) to release the mapping:
308
309 .. code-block:: c
310
311 struct iomap_ops {
312 int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length,
313 unsigned flags, struct iomap *iomap,
314 struct iomap *srcmap);
315
316 int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length,
317 ssize_t written, unsigned flags,
318 struct iomap *iomap);
319 };
320
321 ``->iomap_begin``
322 ~~~~~~~~~~~~~~~~~
323
324 iomap operations call ``->iomap_begin`` to obtain one file mapping for
325 the range of bytes specified by ``pos`` and ``length`` for the file
326 ``inode``.
327 This mapping should be returned through the ``iomap`` pointer.
328 The mapping must cover at least the first byte of the supplied file
329 range, but it does not need to cover the entire requested range.
330
331 Each iomap operation describes the requested operation through the
332 ``flags`` argument.
333 The exact value of ``flags`` will be documented in the
334 operation-specific sections below.
335 These flags can, at least in principle, apply generally to iomap
336 operations:
337
338 * ``IOMAP_DIRECT`` is set when the caller wishes to issue file I/O to
339 block storage.
340
341 * ``IOMAP_DAX`` is set when the caller wishes to issue file I/O to
342 memory-like storage.
343
344 * ``IOMAP_NOWAIT`` is set when the caller wishes to perform a best
345 effort attempt to avoid any operation that would result in blocking
346 the submitting task.
347 This is similar in intent to ``O_NONBLOCK`` for network APIs - it is
348 intended for asynchronous applications to keep doing other work
349 instead of waiting for the specific unavailable filesystem resource
350 to become available.
351 Filesystems implementing ``IOMAP_NOWAIT`` semantics need to use
352 trylock algorithms.
353 They need to be able to satisfy the entire I/O request range with a
354 single iomap mapping.
355 They need to avoid reading or writing metadata synchronously.
356 They need to avoid blocking memory allocations.
357 They need to avoid waiting on transaction reservations to allow
358 modifications to take place.
359 They probably should not be allocating new space.
360 And so on.
361 If there is any doubt in the filesystem developer's mind as to
362 whether any specific ``IOMAP_NOWAIT`` operation may end up blocking,
363 then they should return ``-EAGAIN`` as early as possible rather than
364 start the operation and force the submitting task to block.
365 ``IOMAP_NOWAIT`` is often set on behalf of ``IOCB_NOWAIT`` or
366 ``RWF_NOWAIT``.
367
368 * ``IOMAP_DONTCACHE`` is set when the caller wishes to perform a
369 buffered file I/O and would like the kernel to drop the pagecache
370 after the I/O completes, if it isn't already being used by another
371 thread.
372
373 If it is necessary to read existing file contents from a `different
374 <https://lore.kernel.org/all/[email protected]/>`_
375 device or address range on a device, the filesystem should return that
376 information via ``srcmap``.
377 Only pagecache and fsdax operations support reading from one mapping and
378 writing to another.
379
380 ``->iomap_end``
381 ~~~~~~~~~~~~~~~
382
383 After the operation completes, the ``->iomap_end`` function, if present,
384 is called to signal that iomap is finished with a mapping.
385 Typically, implementations will use this function to tear down any
386 context that were set up in ``->iomap_begin``.
387 For example, a write might wish to commit the reservations for the bytes
388 that were operated upon and unreserve any space that was not operated
389 upon.
390 ``written`` might be zero if no bytes were touched.
391 ``flags`` will contain the same value passed to ``->iomap_begin``.
392 iomap ops for reads are not likely to need to supply this function.
393
394 Both functions should return a negative errno code on error, or zero on
395 success.
396
397 Preparing for File Operations
398 =============================
399
400 iomap only handles mapping and I/O.
401 Filesystems must still call out to the VFS to check input parameters
402 and file state before initiating an I/O operation.
403 It does not handle obtaining filesystem freeze protection, updating of
404 timestamps, stripping privileges, or access control.
405
406 Locking Hierarchy
407 =================
408
409 iomap requires that filesystems supply their own locking model.
410 There are three categories of synchronization primitives, as far as
411 iomap is concerned:
412
413 * The **upper** level primitive is provided by the filesystem to
414 coordinate access to different iomap operations.
415 The exact primitive is specific to the filesystem and operation,
416 but is often a VFS inode, pagecache invalidation, or folio lock.
417 For example, a filesystem might take ``i_rwsem`` before calling
418 ``iomap_file_buffered_write`` and ``iomap_file_unshare`` to prevent
419 these two file operations from clobbering each other.
420 Pagecache writeback may lock a folio to prevent other threads from
421 accessing the folio until writeback is underway.
422
423 * The **lower** level primitive is taken by the filesystem in the
424 ``->iomap_begin`` and ``->iomap_end`` functions to coordinate
425 access to the file space mapping information.
426 The fields of the iomap object should be filled out while holding
427 this primitive.
428 The upper level synchronization primitive, if any, remains held
429 while acquiring the lower level synchronization primitive.
430 For example, XFS takes ``ILOCK_EXCL`` and ext4 takes ``i_data_sem``
431 while sampling mappings.
432 Filesystems with immutable mapping information may not require
433 synchronization here.
434
435 * The **operation** primitive is taken by an iomap operation to
436 coordinate access to its own internal data structures.
437 The upper level synchronization primitive, if any, remains held
438 while acquiring this primitive.
439 The lower level primitive is not held while acquiring this
440 primitive.
441 For example, pagecache write operations will obtain a file mapping,
442 then grab and lock a folio to copy new contents.
443 It may also lock an internal folio state object to update metadata.
444
445 The exact locking requirements are specific to the filesystem; for
446 certain operations, some of these locks can be elided.
447 All further mentions of locking are *recommendations*, not mandates.
448 Each filesystem author must figure out the locking for themself.
449
450 Bugs and Limitations
451 ====================
452
453 * No support for fscrypt.
454 * No support for compression.
455 * No support for fsverity yet.
456 * Strong assumptions that IO should work the way it does on XFS.
457 * Does iomap *actually* work for non-regular file data?
458
459 Patches welcome!
460

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-48

iomap은 공통 파일 연산을 처리하는 파일시스템 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이며, 현재는 여러 다른 연산까지 포괄하도록 확장되었습니다.

iomap의 두 계층
파일 operation의 offset 범위아래 계층 iterator가 filesystem mapping 요청logical range와 storage extent 또는 cached 정보 획득위 계층이 mapping의 sub-unit에 실제 작업 수행pagecache·direct I/O·fsdax·FIEMAP 등에 결과 반영

파일 범위 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을 변경하면 이 설계 문서도 갱신해야 합니다.

고전적 I/O와 iomap 비교
관점고전적 Linux I/Oiomap
조회 단위page 또는 block 같은 작은 단위filesystem이 제공 가능한 가장 큰 범위
연산 크기 가시성제한적전체 범위를 더 잘 파악
fragmentation 대응작은 allocation 중심더 큰 allocation 가능
mapping 호출 비용작은 data마다 반복큰 data 범위에 분산

mapping을 조회하는 단위가 allocation과 호출 비용에 영향을 줍니다.

상위 수준 iomap 연산
`->iomap_begin`으로 mapping 획득작업 sub-unit 선택필요 시 mapping 재검증 후 begin부터 반복실제 작업 수행operation cursor 증가필요 시 `->iomap_end` 호출

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/[email protected]/>`_:

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-150

buffer 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뿐입니다.

iomap 설계의 잠금 용어
Primitive보호 대상핵심 규칙
`i_rwsem`inode 상태와 내용read는 shared, 변경은 흔히 exclusive
`invalidate_lock`pagecache folio 삽입·제거삽입 shared, 제거 exclusive
`dax_read_lock`DAX shutdown과 resource 수명RCU read-side 보호
filesystem mapping lock파일 공간 mapping metadatafilesystem 내부 구현이 결정
iomap operation lockiomap 내부 작업 상태예: pagecache folio lock

각 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`여야 합니다.

`struct iomap` mapping type
Type공간 상태`addr`/deviceread·write 동작
`IOMAP_HOLE`미할당`IOMAP_NULL_ADDR`write mapping으로 반환 금지
`IOMAP_DELALLOC`지연 할당 reservation`IOMAP_NULL_ADDR`실패 시 새 reservation 삭제
`IOMAP_MAPPED`할당·초기화됨`addr`와 `bdev`/`dax_dev`device 공간에 직접 대응
`IOMAP_UNWRITTEN`할당됐지만 미초기화`addr`와 deviceread는 zero, write 후 MAPPED
`IOMAP_INLINE`memory buffer 내부 data`inline_data`, null addressend callback이 영속화

공간 할당 상태와 필수 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` 절을 참조합니다.

파일시스템이 설정하는 iomap flag
Flag의미필수 후속 처리
`IOMAP_F_NEW`새 공간미기록 영역 zeroing, 실패 reservation 삭제
`IOMAP_F_DIRTY`미commit 접근 metadata`fdatasync`로 영속화
`IOMAP_F_SHARED`공유 공간copy-on-write
`IOMAP_F_BUFFER_HEAD`buffer head 필요새 사용처 추가 금지
`IOMAP_F_MERGED`연속 mapping 병합FIEMAP 전용
`IOMAP_F_XATTR`extended attribute mappingFIEMAP 전용
`IOMAP_F_BOUNDARY`I/O 병합 금지 경계buffered writeback에서 경계 준수
`IOMAP_F_PRIVATE`filesystem privatefilesystem 정의
`IOMAP_F_ANON_WRITE`target block 미배정 writebio submission 때 배정·분할
`IOMAP_F_ATOMIC_BIO`atomic write 필요`REQ_ATOMIC`, 단일 metadata update

begin callback이 mapping의 상태와 제약을 전달합니다.

iomap이 설정하는 flag
Flag상태iomap 동작
`IOMAP_F_SIZE_CHANGED`file size 변경filesystem이 end에서 관찰 가능
`IOMAP_F_STALE`mapping이 오래됨end 호출 후 begin으로 재획득

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/[email protected]/>`_.
   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·해제 같은 정리를 선택적으로 수행할 수 있습니다.

`struct iomap_ops` 수명 주기
iomap operation이 범위와 flag 준비`->iomap_begin`이 mapping 또는 srcmap 반환iomap 상위 계층이 mapping으로 작업처리 byte 수를 `written`에 기록필요하면 `->iomap_end`가 context와 reservation 정리

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-379

iomap 연산은 `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 연산만 지원합니다.

`->iomap_begin` 공통 operation flag
Flag요청파일시스템 의무
`IOMAP_DIRECT`block storage I/Odirect mapping 제공
`IOMAP_DAX`memory-like storage I/ODAX mapping 제공
`IOMAP_NOWAIT`blocking 회피trylock, 단일 mapping, 조기 `-EAGAIN`
`IOMAP_DONTCACHE`buffered I/O 후 cache drop다른 thread가 미사용 시 pagecache 제거 허용

호출자가 요구하는 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/[email protected]/>`_
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-405

iomap은 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-449

iomap은 파일시스템이 자체 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을 결정해야 합니다.

iomap locking hierarchy
upper: 파일시스템 연산 사이 조정upper를 유지한 채 lower 획득lower: begin/end에서 mapping metadata samplinglower 해제upper를 유지한 채 operation lock 획득operation: folio 등 iomap 내부 작업 상태 보호

upper는 유지할 수 있지만 lower와 operation은 동시에 보유하지 않습니다.

세 locking 범주
범주획득 주체/위치대표 예
upperiomap 호출 전 filesystem`i_rwsem`, invalidate lock, folio lock
lower`->iomap_begin`/`->iomap_end`XFS `ILOCK_EXCL`, ext4 `i_data_sem`
operationmapping 획득 후 iomap 연산pagecache folio와 내부 folio state lock

획득 위치와 대표 구현을 비교합니다.

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를 환영한다고 마무리합니다.

iomap 설계의 현재 한계
영역상태
fscrypt미지원
compression미지원
fsverity아직 미지원
I/O modelXFS 방식에 강하게 의존
non-regular file data실제 동작 여부가 공개 질문

원문이 명시한 미지원 기능과 공개 질문입니다.

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!