← Documents Documentation/filesystems/dax.rst GitHub 원문 ↗

Linux 6.18.37 · Filesystems

Direct Access for files

DAX page-cache bypass, FS_XFLAG_DAX·S_DAX 정책, driver·filesystem 구현과 media error 복구 전문 번역입니다.

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

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

1. 요약·해설

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

요약·해설

dax.rst:1-305

DAX는 memory-like storage와 userspace 사이의 page cache copy를 제거합니다. persistent `FS_XFLAG_DAX`, inode의 active `S_DAX`, mount override를 구분해야 하며 directory flag는 새 child가 생성될 때만 상속됩니다.

block driver는 항상 byte-addressable한 storage의 `direct_access`를, filesystem은 iomap 기반 I/O·fault·zeroing과 locking을 구현해야 합니다. media poison은 driver를 통한 write·zeroing으로 clear하며 struct page가 없는 mapping은 GUP·RDMA·sendfile 계열과 호환되지 않습니다.

DAX policy와 data path
media와 filesystem DAX capability 확인`FS_XFLAG_DAX` 상속·mount option으로 policy 구성inode instantiation에서 `S_DAX` 결정iomap read·write·mmap fault로 storage 직접 접근statx로 active state 확인media error는 SIGBUS 후 driver write·zeroing 경로로 복구

persistent hint에서 실제 direct mapping과 error recovery까지의 흐름입니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 =======================
2 Direct Access for files
3 =======================
4
5 Motivation
6 ----------
7
8 The page cache is usually used to buffer reads and writes to files.
9 It is also used to provide the pages which are mapped into userspace
10 by a call to mmap.
11
12 For block devices that are memory-like, the page cache pages would be
13 unnecessary copies of the original storage. The `DAX` code removes the
14 extra copy by performing reads and writes directly to the storage device.
15 For file mappings, the storage device is mapped directly into userspace.
16
17
18 Usage
19 -----
20
21 If you have a block device which supports `DAX`, you can make a filesystem
22 on it as usual. The `DAX` code currently only supports files with a block
23 size equal to your kernel's `PAGE_SIZE`, so you may need to specify a block
24 size when creating the filesystem.
25
26 Currently 5 filesystems support `DAX`: ext2, ext4, xfs, virtiofs and erofs.
27 Enabling `DAX` on them is different.
28
29 Enabling DAX on ext2 and erofs
30 ------------------------------
31
32 When mounting the filesystem, use the ``-o dax`` option on the command line or
33 add 'dax' to the options in ``/etc/fstab``. This works to enable `DAX` on all files
34 within the filesystem. It is equivalent to the ``-o dax=always`` behavior below.
35
36
37 Enabling DAX on xfs and ext4
38 ----------------------------
39
40 Summary
41 -------
42
43 1. There exists an in-kernel file access mode flag `S_DAX` that corresponds to
44 the statx flag `STATX_ATTR_DAX`. See the manpage for statx(2) for details
45 about this access mode.
46
47 2. There exists a persistent flag `FS_XFLAG_DAX` that can be applied to regular
48 files and directories. This advisory flag can be set or cleared at any
49 time, but doing so does not immediately affect the `S_DAX` state.
50
51 3. If the persistent `FS_XFLAG_DAX` flag is set on a directory, this flag will
52 be inherited by all regular files and subdirectories that are subsequently
53 created in this directory. Files and subdirectories that exist at the time
54 this flag is set or cleared on the parent directory are not modified by
55 this modification of the parent directory.
56
57 4. There exist dax mount options which can override `FS_XFLAG_DAX` in the
58 setting of the `S_DAX` flag. Given underlying storage which supports `DAX` the
59 following hold:
60
61 ``-o dax=inode`` means "follow `FS_XFLAG_DAX`" and is the default.
62
63 ``-o dax=never`` means "never set `S_DAX`, ignore `FS_XFLAG_DAX`."
64
65 ``-o dax=always`` means "always set `S_DAX` ignore `FS_XFLAG_DAX`."
66
67 ``-o dax`` is a legacy option which is an alias for ``dax=always``.
68
69 .. warning::
70
71 The option ``-o dax`` may be removed in the future so ``-o dax=always`` is
72 the preferred method for specifying this behavior.
73
74 .. note::
75
76 Modifications to and the inheritance behavior of `FS_XFLAG_DAX` remain
77 the same even when the filesystem is mounted with a dax option. However,
78 in-core inode state (`S_DAX`) will be overridden until the filesystem is
79 remounted with dax=inode and the inode is evicted from kernel memory.
80
81 5. The `S_DAX` policy can be changed via:
82
83 a) Setting the parent directory `FS_XFLAG_DAX` as needed before files are
84 created
85
86 b) Setting the appropriate dax="foo" mount option
87
88 c) Changing the `FS_XFLAG_DAX` flag on existing regular files and
89 directories. This has runtime constraints and limitations that are
90 described in 6) below.
91
92 6. When changing the `S_DAX` policy via toggling the persistent `FS_XFLAG_DAX`
93 flag, the change to existing regular files won't take effect until the
94 files are closed by all processes.
95
96
97 Details
98 -------
99
100 There are 2 per-file dax flags. One is a persistent inode setting (`FS_XFLAG_DAX`)
101 and the other is a volatile flag indicating the active state of the feature
102 (`S_DAX`).
103
104 `FS_XFLAG_DAX` is preserved within the filesystem. This persistent config
105 setting can be set, cleared and/or queried using the `FS_IOC_FS`[`GS`]`ETXATTR` ioctl
106 (see ioctl_xfs_fsgetxattr(2)) or an utility such as 'xfs_io'.
107
108 New files and directories automatically inherit `FS_XFLAG_DAX` from
109 their parent directory **when created**. Therefore, setting `FS_XFLAG_DAX` at
110 directory creation time can be used to set a default behavior for an entire
111 sub-tree.
112
113 To clarify inheritance, here are 3 examples:
114
115 Example A:
116
117 .. code-block:: shell
118
119 mkdir -p a/b/c
120 xfs_io -c 'chattr +x' a
121 mkdir a/b/c/d
122 mkdir a/e
123
124 ------[outcome]------
125
126 dax: a,e
127 no dax: b,c,d
128
129 Example B:
130
131 .. code-block:: shell
132
133 mkdir a
134 xfs_io -c 'chattr +x' a
135 mkdir -p a/b/c/d
136
137 ------[outcome]------
138
139 dax: a,b,c,d
140 no dax:
141
142 Example C:
143
144 .. code-block:: shell
145
146 mkdir -p a/b/c
147 xfs_io -c 'chattr +x' c
148 mkdir a/b/c/d
149
150 ------[outcome]------
151
152 dax: c,d
153 no dax: a,b
154
155 The current enabled state (`S_DAX`) is set when a file inode is instantiated in
156 memory by the kernel. It is set based on the underlying media support, the
157 value of `FS_XFLAG_DAX` and the filesystem's dax mount option.
158
159 statx can be used to query `S_DAX`.
160
161 .. note::
162
163 That only regular files will ever have `S_DAX` set and therefore statx
164 will never indicate that `S_DAX` is set on directories.
165
166 Setting the `FS_XFLAG_DAX` flag (specifically or through inheritance) occurs even
167 if the underlying media does not support dax and/or the filesystem is
168 overridden with a mount option.
169
170
171 Enabling DAX on virtiofs
172 ----------------------------
173 The semantic of DAX on virtiofs is basically equal to that on ext4 and xfs,
174 except that when '-o dax=inode' is specified, virtiofs client derives the hint
175 whether DAX shall be enabled or not from virtiofs server through FUSE protocol,
176 rather than the persistent `FS_XFLAG_DAX` flag. That is, whether DAX shall be
177 enabled or not is completely determined by virtiofs server, while virtiofs
178 server itself may deploy various algorithm making this decision, e.g. depending
179 on the persistent `FS_XFLAG_DAX` flag on the host.
180
181 It is still supported to set or clear persistent `FS_XFLAG_DAX` flag inside
182 guest, but it is not guaranteed that DAX will be enabled or disabled for
183 corresponding file then. Users inside guest still need to call statx(2) and
184 check the statx flag `STATX_ATTR_DAX` to see if DAX is enabled for this file.
185
186
187 Implementation Tips for Block Driver Writers
188 --------------------------------------------
189
190 To support `DAX` in your block driver, implement the 'direct_access'
191 block device operation. It is used to translate the sector number
192 (expressed in units of 512-byte sectors) to a page frame number (pfn)
193 that identifies the physical page for the memory. It also returns a
194 kernel virtual address that can be used to access the memory.
195
196 The direct_access method takes a 'size' parameter that indicates the
197 number of bytes being requested. The function should return the number
198 of bytes that can be contiguously accessed at that offset. It may also
199 return a negative errno if an error occurs.
200
201 In order to support this method, the storage must be byte-accessible by
202 the CPU at all times. If your device uses paging techniques to expose
203 a large amount of memory through a smaller window, then you cannot
204 implement direct_access. Equally, if your device can occasionally
205 stall the CPU for an extended period, you should also not attempt to
206 implement direct_access.
207
208 These block devices may be used for inspiration:
209 - pmem: NVDIMM persistent memory driver
210
211
212 Implementation Tips for Filesystem Writers
213 ------------------------------------------
214
215 Filesystem support consists of:
216
217 * Adding support to mark inodes as being `DAX` by setting the `S_DAX` flag in
218 i_flags
219 * Implementing ->read_iter and ->write_iter operations which use
220 :c:func:`dax_iomap_rw()` when inode has `S_DAX` flag set
221 * Implementing an mmap file operation for `DAX` files which sets the
222 `VM_MIXEDMAP` and `VM_HUGEPAGE` flags on the `VMA`, and setting the vm_ops to
223 include handlers for fault, pmd_fault, page_mkwrite, pfn_mkwrite. These
224 handlers should probably call :c:func:`dax_iomap_fault()` passing the
225 appropriate fault size and iomap operations.
226 * Calling :c:func:`iomap_zero_range()` passing appropriate iomap operations
227 instead of :c:func:`block_truncate_page()` for `DAX` files
228 * Ensuring that there is sufficient locking between reads, writes,
229 truncates and page faults
230
231 The iomap handlers for allocating blocks must make sure that allocated blocks
232 are zeroed out and converted to written extents before being returned to avoid
233 exposure of uninitialized data through mmap.
234
235 These filesystems may be used for inspiration:
236
237 .. seealso::
238
239 ext2: see Documentation/filesystems/ext2.rst
240
241 .. seealso::
242
243 xfs: see Documentation/admin-guide/xfs.rst
244
245 .. seealso::
246
247 ext4: see Documentation/filesystems/ext4/
248
249
250 Handling Media Errors
251 ---------------------
252
253 The libnvdimm subsystem stores a record of known media error locations for
254 each pmem block device (in gendisk->badblocks). If we fault at such location,
255 or one with a latent error not yet discovered, the application can expect
256 to receive a `SIGBUS`. Libnvdimm also allows clearing of these errors by simply
257 writing the affected sectors (through the pmem driver, and if the underlying
258 NVDIMM supports the clear_poison DSM defined by ACPI).
259
260 Since `DAX` IO normally doesn't go through the ``driver/bio`` path, applications or
261 sysadmins have an option to restore the lost data from a prior ``backup/inbuilt``
262 redundancy in the following ways:
263
264 1. Delete the affected file, and restore from a backup (sysadmin route):
265 This will free the filesystem blocks that were being used by the file,
266 and the next time they're allocated, they will be zeroed first, which
267 happens through the driver, and will clear bad sectors.
268
269 2. Truncate or hole-punch the part of the file that has a bad-block (at least
270 an entire aligned sector has to be hole-punched, but not necessarily an
271 entire filesystem block).
272
273 These are the two basic paths that allow `DAX` filesystems to continue operating
274 in the presence of media errors. More robust error recovery mechanisms can be
275 built on top of this in the future, for example, involving redundancy/mirroring
276 provided at the block layer through DM, or additionally, at the filesystem
277 level. These would have to rely on the above two tenets, that error clearing
278 can happen either by sending an IO through the driver, or zeroing (also through
279 the driver).
280
281
282 Shortcomings
283 ------------
284
285 Even if the kernel or its modules are stored on a filesystem that supports
286 `DAX` on a block device that supports `DAX`, they will still be copied into RAM.
287
288 The DAX code does not work correctly on architectures which have virtually
289 mapped caches such as ARM, MIPS and SPARC.
290
291 Calling :c:func:`get_user_pages()` on a range of user memory that has been
292 mmapped from a `DAX` file will fail when there are no 'struct page' to describe
293 those pages. This problem has been addressed in some device drivers
294 by adding optional struct page support for pages under the control of
295 the driver (see `CONFIG_NVDIMM_PFN` in ``drivers/nvdimm`` for an example of
296 how to do this). In the non struct page cases `O_DIRECT` reads/writes to
297 those memory ranges from a non-`DAX` file will fail
298
299
300 .. note::
301
302 `O_DIRECT` reads/writes _of a `DAX` file do work, it is the memory that
303 is being accessed that is key here). Other things that will not work in
304 the non struct page case include RDMA, :c:func:`sendfile()` and
305 :c:func:`splice()`.
306

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

DAX 동기와 ext2·erofs 사용

1-36

일반 file read/write와 `mmap` userspace mapping에는 page cache가 buffer page를 제공합니다. 그러나 memory-like block device에서는 page cache page가 원본 storage의 불필요한 copy가 됩니다.

DAX(Direct Access)는 storage device를 직접 read/write해 추가 copy를 없애고 file mapping에서는 device를 userspace에 직접 map합니다.

DAX block device에 filesystem을 평소처럼 만들 수 있지만 현재 DAX file의 block size는 kernel `PAGE_SIZE`와 같아야 하므로 filesystem 생성 시 block size를 지정해야 할 수 있습니다.

지원 filesystem은 ext2, ext4, xfs, virtiofs, erofs 다섯 가지입니다. ext2와 erofs는 mount에 `-o dax` 또는 `/etc/fstab`의 `dax` option을 주면 전체 file에 DAX가 활성화되며 아래의 `-o dax=always`와 같습니다.

Page cache와 DAX 경로
일반 경로: storage → page cache page → userspace mappingDAX 경로: storage byte range → userspace direct mappingread/write도 page cache 대신 device memory에 직접 접근filesystem block size는 kernel `PAGE_SIZE`와 일치

memory-like storage에서 중간 page copy를 제거하는 차이를 보여줍니다.

=======================
Direct Access for files
=======================

Motivation
----------

The page cache is usually used to buffer reads and writes to files.
It is also used to provide the pages which are mapped into userspace
by a call to mmap.

For block devices that are memory-like, the page cache pages would be
unnecessary copies of the original storage.  The `DAX` code removes the
extra copy by performing reads and writes directly to the storage device.
For file mappings, the storage device is mapped directly into userspace.


Usage
-----

If you have a block device which supports `DAX`, you can make a filesystem
on it as usual.  The `DAX` code currently only supports files with a block
size equal to your kernel's `PAGE_SIZE`, so you may need to specify a block
size when creating the filesystem.

Currently 5 filesystems support `DAX`: ext2, ext4, xfs, virtiofs and erofs.
Enabling `DAX` on them is different.

Enabling DAX on ext2 and erofs
------------------------------

When mounting the filesystem, use the ``-o dax`` option on the command line or
add 'dax' to the options in ``/etc/fstab``.  This works to enable `DAX` on all files
within the filesystem.  It is equivalent to the ``-o dax=always`` behavior below.

xfs·ext4의 persistent·active DAX 정책

37-96

kernel의 active file access mode flag `S_DAX`는 `statx`의 `STATX_ATTR_DAX`에 대응합니다. persistent advisory flag `FS_XFLAG_DAX`는 regular file과 directory에 설정·해제할 수 있지만 변경이 즉시 `S_DAX`에 반영되지는 않습니다.

directory의 `FS_XFLAG_DAX`는 이후 생성되는 regular file과 subdirectory가 상속합니다. flag 변경 당시 이미 존재하는 child에는 소급 적용되지 않습니다.

storage가 DAX를 지원할 때 `-o dax=inode`는 `FS_XFLAG_DAX`를 따르며 기본값입니다. `dax=never`는 persistent flag를 무시하고 `S_DAX`를 절대 설정하지 않으며, `dax=always`는 persistent flag를 무시하고 항상 설정합니다. legacy `-o dax`는 `dax=always` alias이고 향후 제거될 수 있어 명시적 form이 권장됩니다.

mount override 중에도 `FS_XFLAG_DAX` 수정과 상속은 그대로 일어나지만 in-core `S_DAX`는 override됩니다. 다시 `dax=inode`로 remount하고 inode가 kernel memory에서 evict되어야 persistent policy가 active state에 반영됩니다.

정책은 file 생성 전 parent flag 설정, 적절한 mount option, existing file·directory의 persistent flag 변경으로 제어합니다. 기존 regular file의 `FS_XFLAG_DAX` toggle은 모든 process가 file을 close한 뒤에야 `S_DAX` 변경으로 반영됩니다.

DAX mount policy
Mount option`FS_XFLAG_DAX``S_DAX`
`dax=inode`따름inode instantiation 때 hint·media support로 결정
`dax=never`저장은 계속됨항상 unset
`dax=always`저장은 계속됨항상 set
legacy `dax`무시`dax=always` alias, 제거 가능

persistent inode hint와 volatile active state의 결합을 비교합니다.

Enabling DAX on xfs and ext4
----------------------------

Summary
-------

 1. There exists an in-kernel file access mode flag `S_DAX` that corresponds to
    the statx flag `STATX_ATTR_DAX`.  See the manpage for statx(2) for details
    about this access mode.

 2. There exists a persistent flag `FS_XFLAG_DAX` that can be applied to regular
    files and directories. This advisory flag can be set or cleared at any
    time, but doing so does not immediately affect the `S_DAX` state.

 3. If the persistent `FS_XFLAG_DAX` flag is set on a directory, this flag will
    be inherited by all regular files and subdirectories that are subsequently
    created in this directory. Files and subdirectories that exist at the time
    this flag is set or cleared on the parent directory are not modified by
    this modification of the parent directory.

 4. There exist dax mount options which can override `FS_XFLAG_DAX` in the
    setting of the `S_DAX` flag.  Given underlying storage which supports `DAX` the
    following hold:

    ``-o dax=inode``  means "follow `FS_XFLAG_DAX`" and is the default.

    ``-o dax=never``  means "never set `S_DAX`, ignore `FS_XFLAG_DAX`."

    ``-o dax=always`` means "always set `S_DAX` ignore `FS_XFLAG_DAX`."

    ``-o dax``      is a legacy option which is an alias for ``dax=always``.

    .. warning::

      The option ``-o dax`` may be removed in the future so ``-o dax=always`` is
      the preferred method for specifying this behavior.

    .. note::

      Modifications to and the inheritance behavior of `FS_XFLAG_DAX` remain
      the same even when the filesystem is mounted with a dax option.  However,
      in-core inode state (`S_DAX`) will be overridden until the filesystem is
      remounted with dax=inode and the inode is evicted from kernel memory.

 5. The `S_DAX` policy can be changed via:

    a) Setting the parent directory `FS_XFLAG_DAX` as needed before files are
       created

    b) Setting the appropriate dax="foo" mount option

    c) Changing the `FS_XFLAG_DAX` flag on existing regular files and
       directories.  This has runtime constraints and limitations that are
       described in 6) below.

 6. When changing the `S_DAX` policy via toggling the persistent `FS_XFLAG_DAX`
    flag, the change to existing regular files won't take effect until the
    files are closed by all processes.

FS_XFLAG_DAX 상속 예제와 S_DAX 결정

97-170

file마다 persistent configuration인 `FS_XFLAG_DAX`와 현재 feature 활성 상태를 나타내는 volatile `S_DAX` 두 flag가 있습니다. persistent flag는 filesystem에 보존되고 `FS_IOC_FSGETXATTR`·`FS_IOC_FSSETXATTR` ioctl 또는 `xfs_io`로 조회·변경합니다.

새 file과 directory는 생성 순간 parent directory의 `FS_XFLAG_DAX`를 상속하므로 subtree의 default behavior를 정하려면 child 생성 전에 parent flag를 설정합니다.

Example A는 `a/b/c`를 먼저 만든 뒤 `a`에 `chattr +x`를 하고 `a/b/c/d`, `a/e`를 만듭니다. 기존 `b`, `c`는 바뀌지 않아 그 아래 새 `d`도 no-DAX이고, flag 설정 뒤 `a` 바로 아래 만든 `e`만 상속합니다. 결과는 DAX `a,e`, no-DAX `b,c,d`입니다.

Example B는 `a`를 만들고 먼저 flag를 설정한 뒤 `a/b/c/d`를 생성하므로 모든 child가 연쇄 상속합니다. 결과는 DAX `a,b,c,d`이고 no-DAX는 없습니다.

Example C는 `a/b/c`를 만든 뒤 `c`에만 flag를 설정하고 `c/d`를 만듭니다. 결과는 DAX `c,d`, no-DAX `a,b`입니다.

`S_DAX`는 kernel이 file inode를 memory에 instantiate할 때 underlying media support, `FS_XFLAG_DAX`, filesystem mount option을 조합해 설정합니다. `statx`로 조회할 수 있으며 regular file에만 설정되므로 directory의 `statx`는 `S_DAX`를 보고하지 않습니다.

underlying media가 DAX를 지원하지 않거나 mount option이 override해도 persistent `FS_XFLAG_DAX` 자체의 설정·상속은 일어납니다.

상속 예제 결과
예제Flag 설정 시점DAXNo DAX
A`a/b/c` 생성 후 `a +x``a`, `e``b`, `c`, `d`
B`a +x` 후 subtree 생성`a`, `b`, `c`, `d`없음
C`a/b/c` 생성 후 `c +x``c`, `d``a`, `b`

flag 변경은 기존 child에 소급되지 않고 생성 시 parent 상태만 복사됩니다.

Details
-------

There are 2 per-file dax flags.  One is a persistent inode setting (`FS_XFLAG_DAX`)
and the other is a volatile flag indicating the active state of the feature
(`S_DAX`).

`FS_XFLAG_DAX` is preserved within the filesystem.  This persistent config
setting can be set, cleared and/or queried using the `FS_IOC_FS`[`GS`]`ETXATTR` ioctl
(see ioctl_xfs_fsgetxattr(2)) or an utility such as 'xfs_io'.

New files and directories automatically inherit `FS_XFLAG_DAX` from
their parent directory **when created**.  Therefore, setting `FS_XFLAG_DAX` at
directory creation time can be used to set a default behavior for an entire
sub-tree.

To clarify inheritance, here are 3 examples:

Example A:

.. code-block:: shell

  mkdir -p a/b/c
  xfs_io -c 'chattr +x' a
  mkdir a/b/c/d
  mkdir a/e

  ------[outcome]------

  dax: a,e
  no dax: b,c,d

Example B:

.. code-block:: shell

  mkdir a
  xfs_io -c 'chattr +x' a
  mkdir -p a/b/c/d

  ------[outcome]------

  dax: a,b,c,d
  no dax:

Example C:

.. code-block:: shell

  mkdir -p a/b/c
  xfs_io -c 'chattr +x' c
  mkdir a/b/c/d

  ------[outcome]------

  dax: c,d
  no dax: a,b

The current enabled state (`S_DAX`) is set when a file inode is instantiated in
memory by the kernel.  It is set based on the underlying media support, the
value of `FS_XFLAG_DAX` and the filesystem's dax mount option.

statx can be used to query `S_DAX`.

.. note::

  That only regular files will ever have `S_DAX` set and therefore statx
  will never indicate that `S_DAX` is set on directories.

Setting the `FS_XFLAG_DAX` flag (specifically or through inheritance) occurs even
if the underlying media does not support dax and/or the filesystem is
overridden with a mount option.

virtiofs의 server 결정 DAX hint

171-186

virtiofs의 DAX 의미는 ext4·xfs와 대체로 같지만 `-o dax=inode`일 때 client가 persistent `FS_XFLAG_DAX`를 직접 따르지 않고 FUSE protocol을 통해 server에서 DAX enable hint를 받습니다.

최종 결정은 virtiofs server가 전적으로 내리며 server는 host의 persistent flag 등 다양한 algorithm을 사용할 수 있습니다.

guest 안에서 `FS_XFLAG_DAX`를 set·clear하는 것은 지원하지만 해당 file의 실제 DAX 상태가 그대로 바뀐다고 보장되지 않습니다. guest userspace는 `statx(2)`의 `STATX_ATTR_DAX`를 확인해야 합니다.

virtiofs DAX 결정
guest가 persistent `FS_XFLAG_DAX`를 설정할 수 있음client가 `dax=inode` mount policy 사용virtiofs server가 FUSE protocol로 DAX hint 반환server policy가 최종 enable 여부 결정guest는 `statx`의 `STATX_ATTR_DAX`로 실제 상태 확인

guest hint와 server policy, 실제 active state를 구분합니다.

Enabling DAX on virtiofs
----------------------------
The semantic of DAX on virtiofs is basically equal to that on ext4 and xfs,
except that when '-o dax=inode' is specified, virtiofs client derives the hint
whether DAX shall be enabled or not from virtiofs server through FUSE protocol,
rather than the persistent `FS_XFLAG_DAX` flag. That is, whether DAX shall be
enabled or not is completely determined by virtiofs server, while virtiofs
server itself may deploy various algorithm making this decision, e.g. depending
on the persistent `FS_XFLAG_DAX` flag on the host.

It is still supported to set or clear persistent `FS_XFLAG_DAX` flag inside
guest, but it is not guaranteed that DAX will be enabled or disabled for
corresponding file then. Users inside guest still need to call statx(2) and
check the statx flag `STATX_ATTR_DAX` to see if DAX is enabled for this file.

Block driver 구현 조건

187-211

block driver가 DAX를 지원하려면 `direct_access` block device operation을 구현합니다. 512-byte sector 단위 sector number를 physical memory page의 page frame number(pfn)로 변환하고 접근용 kernel virtual address도 반환합니다.

`size` parameter는 요청 byte 수입니다. method는 해당 offset에서 연속 접근 가능한 byte 수를 반환하고 오류 시 negative errno를 반환할 수 있습니다.

storage는 CPU가 항상 byte-addressable해야 합니다. 작은 window로 큰 memory를 paging해 노출하는 device나 CPU를 장시간 stall할 수 있는 device는 `direct_access`를 구현해서는 안 됩니다.

참고 구현은 NVDIMM persistent memory driver인 `pmem`입니다.

`direct_access` 계약
항목계약
Input512-byte sector number와 요청 `size`
Outputpfn, kernel virtual address, contiguous byte count
Errornegative errno
필수 storage 특성항상 CPU byte-addressable
금지 특성window paging 또는 장시간 CPU stall
참고 driver`pmem`

DAX block mapping이 성립하기 위한 입력·출력·hardware 조건입니다.

Implementation Tips for Block Driver Writers
--------------------------------------------

To support `DAX` in your block driver, implement the 'direct_access'
block device operation.  It is used to translate the sector number
(expressed in units of 512-byte sectors) to a page frame number (pfn)
that identifies the physical page for the memory.  It also returns a
kernel virtual address that can be used to access the memory.

The direct_access method takes a 'size' parameter that indicates the
number of bytes being requested.  The function should return the number
of bytes that can be contiguously accessed at that offset.  It may also
return a negative errno if an error occurs.

In order to support this method, the storage must be byte-accessible by
the CPU at all times.  If your device uses paging techniques to expose
a large amount of memory through a smaller window, then you cannot
implement direct_access.  Equally, if your device can occasionally
stall the CPU for an extended period, you should also not attempt to
implement direct_access.

These block devices may be used for inspiration:
- pmem: NVDIMM persistent memory driver

Filesystem 구현 요구사항

212-249

filesystem은 DAX inode의 `i_flags`에 `S_DAX`를 설정할 수 있어야 합니다. `->read_iter`와 `->write_iter`는 flag가 설정된 inode에서 `dax_iomap_rw()`를 사용합니다.

DAX file의 mmap operation은 VMA에 `VM_MIXEDMAP`과 `VM_HUGEPAGE`를 설정하고 `fault`, `pmd_fault`, `page_mkwrite`, `pfn_mkwrite` handler를 포함하는 `vm_ops`를 설치해야 합니다. handler는 알맞은 fault size와 iomap operations를 `dax_iomap_fault()`에 전달하는 방식이 권장됩니다.

DAX file truncation에는 `block_truncate_page()` 대신 적절한 iomap operation과 `iomap_zero_range()`를 사용하고 read, write, truncate, page fault 사이에 충분한 locking을 보장해야 합니다.

block allocation iomap handler는 mmap을 통해 uninitialized data가 노출되지 않도록 allocated block을 zero하고 written extent로 변환한 뒤 반환해야 합니다.

참고 filesystem은 `Documentation/filesystems/ext2.rst`, `Documentation/admin-guide/xfs.rst`, `Documentation/filesystems/ext4/`입니다.

Filesystem DAX I/O
inode instantiation에서 `S_DAX` policy 결정read/write iterator가 `dax_iomap_rw()` 호출mmap VMA에 mixedmap·hugepage flag와 DAX vm_ops 설치page fault handler가 `dax_iomap_fault()` 호출truncate·zero는 `iomap_zero_range()` 사용allocation block을 zero 후 written extent로 반환

inode active flag에서 iomap 기반 read·write·fault·truncate로 이어지는 경로입니다.

Implementation Tips for Filesystem Writers
------------------------------------------

Filesystem support consists of:

* Adding support to mark inodes as being `DAX` by setting the `S_DAX` flag in
  i_flags
* Implementing ->read_iter and ->write_iter operations which use
  :c:func:`dax_iomap_rw()` when inode has `S_DAX` flag set
* Implementing an mmap file operation for `DAX` files which sets the
  `VM_MIXEDMAP` and `VM_HUGEPAGE` flags on the `VMA`, and setting the vm_ops to
  include handlers for fault, pmd_fault, page_mkwrite, pfn_mkwrite. These
  handlers should probably call :c:func:`dax_iomap_fault()` passing the
  appropriate fault size and iomap operations.
* Calling :c:func:`iomap_zero_range()` passing appropriate iomap operations
  instead of :c:func:`block_truncate_page()` for `DAX` files
* Ensuring that there is sufficient locking between reads, writes,
  truncates and page faults

The iomap handlers for allocating blocks must make sure that allocated blocks
are zeroed out and converted to written extents before being returned to avoid
exposure of uninitialized data through mmap.

These filesystems may be used for inspiration:

.. seealso::

  ext2: see Documentation/filesystems/ext2.rst

.. seealso::

  xfs:  see Documentation/admin-guide/xfs.rst

.. seealso::

  ext4: see Documentation/filesystems/ext4/

Media error 처리

250-280

libnvdimm은 pmem block device별 known media error location을 `gendisk->badblocks`에 기록합니다. 알려진 위치나 아직 발견되지 않은 latent error에서 fault가 나면 application은 `SIGBUS`를 받습니다.

underlying NVDIMM이 ACPI의 `clear_poison` DSM을 지원하면 pmem driver를 통해 영향을 받은 sector에 write하여 error를 clear할 수 있습니다.

DAX I/O는 보통 `driver/bio` path를 거치지 않으므로 backup이나 내장 redundancy에서 data를 복원하는 기본 경로가 두 가지입니다. 첫째 affected file을 삭제하고 backup에서 복원하면 filesystem block이 free되고 다음 allocation에서 driver를 통해 zero되어 bad sector가 clear됩니다.

둘째 bad block을 포함한 file 부분을 truncate하거나 hole-punch합니다. 최소한 정렬된 sector 전체를 punch해야 하지만 filesystem block 전체일 필요는 없습니다.

향후 DM block layer 또는 filesystem 수준 redundancy·mirroring으로 더 강한 recovery를 만들 수 있지만, driver를 통과하는 I/O 또는 driver를 통한 zeroing으로 error를 clear한다는 두 원칙에 의존해야 합니다.

DAX media error 복구
badblocks 또는 latent poison에서 DAX access faultapplication이 `SIGBUS` 수신경로 1: file 삭제 → block 재할당 zero → backup 복원경로 2: aligned sector truncate·hole-punch → zeroingpmem driver와 `clear_poison` DSM이 media error 제거

SIGBUS 이후 driver를 통과하는 write·zero 경로를 다시 만드는 두 방법입니다.

Handling Media Errors
---------------------

The libnvdimm subsystem stores a record of known media error locations for
each pmem block device (in gendisk->badblocks). If we fault at such location,
or one with a latent error not yet discovered, the application can expect
to receive a `SIGBUS`. Libnvdimm also allows clearing of these errors by simply
writing the affected sectors (through the pmem driver, and if the underlying
NVDIMM supports the clear_poison DSM defined by ACPI).

Since `DAX` IO normally doesn't go through the ``driver/bio`` path, applications or
sysadmins have an option to restore the lost data from a prior ``backup/inbuilt``
redundancy in the following ways:

1. Delete the affected file, and restore from a backup (sysadmin route):
   This will free the filesystem blocks that were being used by the file,
   and the next time they're allocated, they will be zeroed first, which
   happens through the driver, and will clear bad sectors.

2. Truncate or hole-punch the part of the file that has a bad-block (at least
   an entire aligned sector has to be hole-punched, but not necessarily an
   entire filesystem block).

These are the two basic paths that allow `DAX` filesystems to continue operating
in the presence of media errors. More robust error recovery mechanisms can be
built on top of this in the future, for example, involving redundancy/mirroring
provided at the block layer through DM, or additionally, at the filesystem
level. These would have to rely on the above two tenets, that error clearing
can happen either by sending an IO through the driver, or zeroing (also through
the driver).

DAX 제약과 struct page 부재

281-305

kernel이나 module이 DAX-capable filesystem·device에 저장되어도 여전히 RAM으로 copy됩니다.

DAX code는 ARM, MIPS, SPARC처럼 virtually mapped cache를 사용하는 architecture에서 올바르게 동작하지 않습니다.

DAX mmap range에 대응하는 `struct page`가 없으면 그 userspace memory에 `get_user_pages()`가 실패합니다. 일부 device driver는 optional struct page support를 추가해 해결하며 `drivers/nvdimm`의 `CONFIG_NVDIMM_PFN`이 예입니다.

struct page가 없는 DAX-mapped memory를 non-DAX file의 `O_DIRECT` read/write target으로 쓰면 실패합니다. 반대로 DAX file 자체의 `O_DIRECT` I/O는 동작하며 핵심은 접근 대상 memory의 page representation입니다.

non-struct-page 경우에는 RDMA, `sendfile()`, `splice()`도 동작하지 않습니다.

DAX 현재 제약
영역제약
Kernel/module imageDAX storage에 있어도 RAM으로 copy
Architecturevirtually mapped cache에서 비정상
GUP`struct page` 없는 DAX mmap range 실패
Non-DAX `O_DIRECT`DAX-mapped no-page memory를 buffer로 사용 시 실패
DAX file `O_DIRECT`동작함
기타 APIno-page memory에서 RDMA·sendfile·splice 실패

storage direct mapping이 일반 memory API와 만나는 한계를 정리합니다.


Shortcomings
------------

Even if the kernel or its modules are stored on a filesystem that supports
`DAX` on a block device that supports `DAX`, they will still be copied into RAM.

The DAX code does not work correctly on architectures which have virtually
mapped caches such as ARM, MIPS and SPARC.

Calling :c:func:`get_user_pages()` on a range of user memory that has been
mmapped from a `DAX` file will fail when there are no 'struct page' to describe
those pages.  This problem has been addressed in some device drivers
by adding optional struct page support for pages under the control of
the driver (see `CONFIG_NVDIMM_PFN` in ``drivers/nvdimm`` for an example of
how to do this). In the non struct page cases `O_DIRECT` reads/writes to
those memory ranges from a non-`DAX` file will fail 


.. note::

  `O_DIRECT` reads/writes _of a `DAX` file do work, it is the memory that
  is being accessed that is key here).  Other things that will not work in
  the non struct page case include RDMA, :c:func:`sendfile()` and
  :c:func:`splice()`.