← Documents Documentation/mm/process_addrs.rst GitHub 원문 ↗

Linux 6.18.37 · Memory management

Process Addresses

VMA·mm·maple-tree model, mmap/VMA/rmap lock 규칙과 page-table lifetime을 설명합니다.

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

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

1. 요약·해설

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

요약·해설

process_addrs.rst:1-909

Process address space는 `mm_struct`의 maple tree에 든 VMA 집합으로 표현됩니다. VMA metadata는 mmap·VMA·rmap lock으로 안정화하며, page-table traversal·installation·zapping·freeing은 mapping identity와 lifetime 위험에 따라 서로 다른 lock 조합을 요구합니다.

MM과 VMA 구성
Task / thread`struct mm_struct`Maple tree`struct vm_area_struct`동일 attribute의 virtual-contiguous range

같은 address space를 공유하는 task가 하나의 mm과 그 maple-tree VMA set을 참조합니다.

VMA metadata lock 범위
Lock범위대표 APIWrite 선행 조건
mmapMM 전체 address space`mmap_read_lock`, `mmap_write_lock`없음
VMAVMA 하나`lock_vma_under_rcu`, `vma_start_write`VMA write 전에 mmap write
rmap`anon_vma` 또는 `address_space` interval tree`anon_vma_*lock_*`, `i_mmap_*lock_*`Mapping 유형별 lock

세 lock family가 VMA를 stable하게 만드는 서로 다른 접근 경로를 보호합니다.

유효 lock-state와 권한
mmapVMArmapStableReadWrite mostWrite all
---NNNN
-R-YYNN
--R/WYYNN
R/W-/R-/R/WYYNN
WW-/RYYYN
WWWYYYY

원문의 Stable·Read·Write 표를 같은 상태 조합으로 구조화했습니다.

VMA field group별 write lock
Group대표 fieldWrite lock
Virtual layout`vm_start`, `vm_end`, `vm_pgoff`mmap W + VMA W + rmap W
Core mutable`vm_page_prot`, `__vm_flags`mmap W + VMA W
Write-once core`vm_mm`, `vm_file`, `vm_ops`Initial map에서 한 번
Config-specific`anon_name`, `vm_policy`, `vm_userfaultfd_ctx`Field별 mmap/VMA 또는 subsystem lock
Reverse mapping`shared.rb`, `anon_vma_chain`, `anon_vma`mmap/VMA + i_mmap 또는 anon_vma lock

Field 목적에 따라 reverse mapping에서 숨겨야 하는 정도가 다릅니다.

Page-table operation과 안정화 규칙
OperationVMA 요구핵심 주의
TraverseStable VMA, lockless variant 가능PTE deletion은 RCU로 방지
Installmmap 또는 VMA lockrmap lock만으로는 부족
Zapmmap·VMA·rmap 중 하나Leaf mapping만 clear
Free tablesVMA가 rmap에서 unreachableZap 이후 새 entry 금지
Move tablesmmap + VMA + 관련 rmap 모두Higher-level table identity 이동

Mapping identity 변경 여부와 lifetime 위험이 필요한 lock을 결정합니다.

주요 lock-order chain
Context획득 순서
Core rmap`inode->i_rwsem → mm->mmap_lock → invalidate_lock → folio_lock → vma_start_write → i_mmap_rwsem → anon_vma->rwsem → page_table_lock/pte_lock`
Truncate`i_rwsem → invalidate_lock → i_mmap_rwsem`
File mapping`mmap_lock → i_mmap_rwsem → page_table_lock/pte_lock → i_pages`
File fault`mmap_lock → invalidate_lock → lock_page`
Write fault`i_rwsem → mmap_lock`
VMA merge`i_mmap_rwsem → anon_vma.lock`
Anon prepare`anon_vma.lock → page_table_lock/pte_lock`
PTE writeback`page_table_lock/pte_lock → swap/private/i_pages/lruvec/inode/bdi locks`

원문의 mm/rmap.c와 mm/filemap.c ordering을 대표 chain별로 보존했습니다.

Page-table level별 lock
Level기본 lock추가 요구
PGD / P4D / PUD`mm->page_table_lock`Atomic `pXXp_get`, `set_pXX`, `pXX_clear`
PMD`pmd_lock` / split lockEntry revalidation
PTE`pte_offset_map_lock` / PTE spinlockRCU, highmem mapping, PMD 재검증

Higher-level global lock과 PMD·PTE fine-grained lock을 구분합니다.

PTE installation 재검증
PMD를 lockless readExpected PMD인지 확인PTE-specific lock 획득PMD 다시 확인PTE set/clear`pte_unmap_unlock`

THP collapse와 race하지 않도록 PMD를 lock 전후 두 번 확인합니다.

VMA read·write lock 내부 상태
RCU lookup`vma.vm_refcnt` 증가`vm_lock_seq != mm_lock_seq` 확인Read lock 성공`vma_end_read`
mmap write lock`vm_refcnt` writer bit setReader drain 대기`vm_lock_seq = mm_lock_seq`VMA write lockmmap unlock/downgrade로 일괄 해제

Reference counter는 reader 수와 writer bit를, sequence equality는 write-lock 상태를 나타냅니다.

mmap lock exclusivity
Row / ColumnRDW
RNNY
DNYY
WYYY

원문의 R·D·W matrix입니다. Y는 mutual exclusion, N은 동시 보유 가능을 뜻합니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 =================
4 Process Addresses
5 =================
6
7 .. toctree::
8 :maxdepth: 3
9
10
11 Userland memory ranges are tracked by the kernel via Virtual Memory Areas or
12 'VMA's of type :c:struct:`!struct vm_area_struct`.
13
14 Each VMA describes a virtually contiguous memory range with identical
15 attributes, each described by a :c:struct:`!struct vm_area_struct`
16 object. Userland access outside of VMAs is invalid except in the case where an
17 adjacent stack VMA could be extended to contain the accessed address.
18
19 All VMAs are contained within one and only one virtual address space, described
20 by a :c:struct:`!struct mm_struct` object which is referenced by all tasks (that is,
21 threads) which share the virtual address space. We refer to this as the
22 :c:struct:`!mm`.
23
24 Each mm object contains a maple tree data structure which describes all VMAs
25 within the virtual address space.
26
27 .. note:: An exception to this is the 'gate' VMA which is provided by
28 architectures which use :c:struct:`!vsyscall` and is a global static
29 object which does not belong to any specific mm.
30
31 -------
32 Locking
33 -------
34
35 The kernel is designed to be highly scalable against concurrent read operations
36 on VMA **metadata** so a complicated set of locks are required to ensure memory
37 corruption does not occur.
38
39 .. note:: Locking VMAs for their metadata does not have any impact on the memory
40 they describe nor the page tables that map them.
41
42 Terminology
43 -----------
44
45 * **mmap locks** - Each MM has a read/write semaphore :c:member:`!mmap_lock`
46 which locks at a process address space granularity which can be acquired via
47 :c:func:`!mmap_read_lock`, :c:func:`!mmap_write_lock` and variants.
48 * **VMA locks** - The VMA lock is at VMA granularity (of course) which behaves
49 as a read/write semaphore in practice. A VMA read lock is obtained via
50 :c:func:`!lock_vma_under_rcu` (and unlocked via :c:func:`!vma_end_read`) and a
51 write lock via :c:func:`!vma_start_write` (all VMA write locks are unlocked
52 automatically when the mmap write lock is released). To take a VMA write lock
53 you **must** have already acquired an :c:func:`!mmap_write_lock`.
54 * **rmap locks** - When trying to access VMAs through the reverse mapping via a
55 :c:struct:`!struct address_space` or :c:struct:`!struct anon_vma` object
56 (reachable from a folio via :c:member:`!folio->mapping`). VMAs must be stabilised via
57 :c:func:`!anon_vma_[try]lock_read` or :c:func:`!anon_vma_[try]lock_write` for
58 anonymous memory and :c:func:`!i_mmap_[try]lock_read` or
59 :c:func:`!i_mmap_[try]lock_write` for file-backed memory. We refer to these
60 locks as the reverse mapping locks, or 'rmap locks' for brevity.
61
62 We discuss page table locks separately in the dedicated section below.
63
64 The first thing **any** of these locks achieve is to **stabilise** the VMA
65 within the MM tree. That is, guaranteeing that the VMA object will not be
66 deleted from under you nor modified (except for some specific fields
67 described below).
68
69 Stabilising a VMA also keeps the address space described by it around.
70
71 Lock usage
72 ----------
73
74 If you want to **read** VMA metadata fields or just keep the VMA stable, you
75 must do one of the following:
76
77 * Obtain an mmap read lock at the MM granularity via :c:func:`!mmap_read_lock` (or a
78 suitable variant), unlocking it with a matching :c:func:`!mmap_read_unlock` when
79 you're done with the VMA, *or*
80 * Try to obtain a VMA read lock via :c:func:`!lock_vma_under_rcu`. This tries to
81 acquire the lock atomically so might fail, in which case fall-back logic is
82 required to instead obtain an mmap read lock if this returns :c:macro:`!NULL`,
83 *or*
84 * Acquire an rmap lock before traversing the locked interval tree (whether
85 anonymous or file-backed) to obtain the required VMA.
86
87 If you want to **write** VMA metadata fields, then things vary depending on the
88 field (we explore each VMA field in detail below). For the majority you must:
89
90 * Obtain an mmap write lock at the MM granularity via :c:func:`!mmap_write_lock` (or a
91 suitable variant), unlocking it with a matching :c:func:`!mmap_write_unlock` when
92 you're done with the VMA, *and*
93 * Obtain a VMA write lock via :c:func:`!vma_start_write` for each VMA you wish to
94 modify, which will be released automatically when :c:func:`!mmap_write_unlock` is
95 called.
96 * If you want to be able to write to **any** field, you must also hide the VMA
97 from the reverse mapping by obtaining an **rmap write lock**.
98
99 VMA locks are special in that you must obtain an mmap **write** lock **first**
100 in order to obtain a VMA **write** lock. A VMA **read** lock however can be
101 obtained without any other lock (:c:func:`!lock_vma_under_rcu` will acquire then
102 release an RCU lock to lookup the VMA for you).
103
104 This constrains the impact of writers on readers, as a writer can interact with
105 one VMA while a reader interacts with another simultaneously.
106
107 .. note:: The primary users of VMA read locks are page fault handlers, which
108 means that without a VMA write lock, page faults will run concurrent with
109 whatever you are doing.
110
111 Examining all valid lock states:
112
113 .. table::
114
115 ========= ======== ========= ======= ===== =========== ==========
116 mmap lock VMA lock rmap lock Stable? Read? Write most? Write all?
117 ========= ======== ========= ======= ===== =========== ==========
118 \- \- \- N N N N
119 \- R \- Y Y N N
120 \- \- R/W Y Y N N
121 R/W \-/R \-/R/W Y Y N N
122 W W \-/R Y Y Y N
123 W W W Y Y Y Y
124 ========= ======== ========= ======= ===== =========== ==========
125
126 .. warning:: While it's possible to obtain a VMA lock while holding an mmap read lock,
127 attempting to do the reverse is invalid as it can result in deadlock - if
128 another task already holds an mmap write lock and attempts to acquire a VMA
129 write lock that will deadlock on the VMA read lock.
130
131 All of these locks behave as read/write semaphores in practice, so you can
132 obtain either a read or a write lock for each of these.
133
134 .. note:: Generally speaking, a read/write semaphore is a class of lock which
135 permits concurrent readers. However a write lock can only be obtained
136 once all readers have left the critical region (and pending readers
137 made to wait).
138
139 This renders read locks on a read/write semaphore concurrent with other
140 readers and write locks exclusive against all others holding the semaphore.
141
142 VMA fields
143 ^^^^^^^^^^
144
145 We can subdivide :c:struct:`!struct vm_area_struct` fields by their purpose, which makes it
146 easier to explore their locking characteristics:
147
148 .. note:: We exclude VMA lock-specific fields here to avoid confusion, as these
149 are in effect an internal implementation detail.
150
151 .. table:: Virtual layout fields
152
153 ===================== ======================================== ===========
154 Field Description Write lock
155 ===================== ======================================== ===========
156 :c:member:`!vm_start` Inclusive start virtual address of range mmap write,
157 VMA describes. VMA write,
158 rmap write.
159 :c:member:`!vm_end` Exclusive end virtual address of range mmap write,
160 VMA describes. VMA write,
161 rmap write.
162 :c:member:`!vm_pgoff` Describes the page offset into the file, mmap write,
163 the original page offset within the VMA write,
164 virtual address space (prior to any rmap write.
165 :c:func:`!mremap`), or PFN if a PFN map
166 and the architecture does not support
167 :c:macro:`!CONFIG_ARCH_HAS_PTE_SPECIAL`.
168 ===================== ======================================== ===========
169
170 These fields describes the size, start and end of the VMA, and as such cannot be
171 modified without first being hidden from the reverse mapping since these fields
172 are used to locate VMAs within the reverse mapping interval trees.
173
174 .. table:: Core fields
175
176 ============================ ======================================== =========================
177 Field Description Write lock
178 ============================ ======================================== =========================
179 :c:member:`!vm_mm` Containing mm_struct. None - written once on
180 initial map.
181 :c:member:`!vm_page_prot` Architecture-specific page table mmap write, VMA write.
182 protection bits determined from VMA
183 flags.
184 :c:member:`!vm_flags` Read-only access to VMA flags describing N/A
185 attributes of the VMA, in union with
186 private writable
187 :c:member:`!__vm_flags`.
188 :c:member:`!__vm_flags` Private, writable access to VMA flags mmap write, VMA write.
189 field, updated by
190 :c:func:`!vm_flags_*` functions.
191 :c:member:`!vm_file` If the VMA is file-backed, points to a None - written once on
192 struct file object describing the initial map.
193 underlying file, if anonymous then
194 :c:macro:`!NULL`.
195 :c:member:`!vm_ops` If the VMA is file-backed, then either None - Written once on
196 the driver or file-system provides a initial map by
197 :c:struct:`!struct vm_operations_struct` :c:func:`!f_ops->mmap()`.
198 object describing callbacks to be
199 invoked on VMA lifetime events.
200 :c:member:`!vm_private_data` A :c:member:`!void *` field for Handled by driver.
201 driver-specific metadata.
202 ============================ ======================================== =========================
203
204 These are the core fields which describe the MM the VMA belongs to and its attributes.
205
206 .. table:: Config-specific fields
207
208 ================================= ===================== ======================================== ===============
209 Field Configuration option Description Write lock
210 ================================= ===================== ======================================== ===============
211 :c:member:`!anon_name` CONFIG_ANON_VMA_NAME A field for storing a mmap write,
212 :c:struct:`!struct anon_vma_name` VMA write.
213 object providing a name for anonymous
214 mappings, or :c:macro:`!NULL` if none
215 is set or the VMA is file-backed. The
216 underlying object is reference counted
217 and can be shared across multiple VMAs
218 for scalability.
219 :c:member:`!swap_readahead_info` CONFIG_SWAP Metadata used by the swap mechanism mmap read,
220 to perform readahead. This field is swap-specific
221 accessed atomically. lock.
222 :c:member:`!vm_policy` CONFIG_NUMA :c:type:`!mempolicy` object which mmap write,
223 describes the NUMA behaviour of the VMA write.
224 VMA. The underlying object is reference
225 counted.
226 :c:member:`!numab_state` CONFIG_NUMA_BALANCING :c:type:`!vma_numab_state` object which mmap read,
227 describes the current state of numab-specific
228 NUMA balancing in relation to this VMA. lock.
229 Updated under mmap read lock by
230 :c:func:`!task_numa_work`.
231 :c:member:`!vm_userfaultfd_ctx` CONFIG_USERFAULTFD Userfaultfd context wrapper object of mmap write,
232 type :c:type:`!vm_userfaultfd_ctx`, VMA write.
233 either of zero size if userfaultfd is
234 disabled, or containing a pointer
235 to an underlying
236 :c:type:`!userfaultfd_ctx` object which
237 describes userfaultfd metadata.
238 ================================= ===================== ======================================== ===============
239
240 These fields are present or not depending on whether the relevant kernel
241 configuration option is set.
242
243 .. table:: Reverse mapping fields
244
245 =================================== ========================================= ============================
246 Field Description Write lock
247 =================================== ========================================= ============================
248 :c:member:`!shared.rb` A red/black tree node used, if the mmap write, VMA write,
249 mapping is file-backed, to place the VMA i_mmap write.
250 in the
251 :c:member:`!struct address_space->i_mmap`
252 red/black interval tree.
253 :c:member:`!shared.rb_subtree_last` Metadata used for management of the mmap write, VMA write,
254 interval tree if the VMA is file-backed. i_mmap write.
255 :c:member:`!anon_vma_chain` List of pointers to both forked/CoW’d mmap read, anon_vma write.
256 :c:type:`!anon_vma` objects and
257 :c:member:`!vma->anon_vma` if it is
258 non-:c:macro:`!NULL`.
259 :c:member:`!anon_vma` :c:type:`!anon_vma` object used by When :c:macro:`NULL` and
260 anonymous folios mapped exclusively to setting non-:c:macro:`NULL`:
261 this VMA. Initially set by mmap read, page_table_lock.
262 :c:func:`!anon_vma_prepare` serialised
263 by the :c:macro:`!page_table_lock`. This When non-:c:macro:`NULL` and
264 is set as soon as any page is faulted in. setting :c:macro:`NULL`:
265 mmap write, VMA write,
266 anon_vma write.
267 =================================== ========================================= ============================
268
269 These fields are used to both place the VMA within the reverse mapping, and for
270 anonymous mappings, to be able to access both related :c:struct:`!struct anon_vma` objects
271 and the :c:struct:`!struct anon_vma` in which folios mapped exclusively to this VMA should
272 reside.
273
274 .. note:: If a file-backed mapping is mapped with :c:macro:`!MAP_PRIVATE` set
275 then it can be in both the :c:type:`!anon_vma` and :c:type:`!i_mmap`
276 trees at the same time, so all of these fields might be utilised at
277 once.
278
279 Page tables
280 -----------
281
282 We won't speak exhaustively on the subject but broadly speaking, page tables map
283 virtual addresses to physical ones through a series of page tables, each of
284 which contain entries with physical addresses for the next page table level
285 (along with flags), and at the leaf level the physical addresses of the
286 underlying physical data pages or a special entry such as a swap entry,
287 migration entry or other special marker. Offsets into these pages are provided
288 by the virtual address itself.
289
290 In Linux these are divided into five levels - PGD, P4D, PUD, PMD and PTE. Huge
291 pages might eliminate one or two of these levels, but when this is the case we
292 typically refer to the leaf level as the PTE level regardless.
293
294 .. note:: In instances where the architecture supports fewer page tables than
295 five the kernel cleverly 'folds' page table levels, that is stubbing
296 out functions related to the skipped levels. This allows us to
297 conceptually act as if there were always five levels, even if the
298 compiler might, in practice, eliminate any code relating to missing
299 ones.
300
301 There are four key operations typically performed on page tables:
302
303 1. **Traversing** page tables - Simply reading page tables in order to traverse
304 them. This only requires that the VMA is kept stable, so a lock which
305 establishes this suffices for traversal (there are also lockless variants
306 which eliminate even this requirement, such as :c:func:`!gup_fast`). There is
307 also a special case of page table traversal for non-VMA regions which we
308 consider separately below.
309 2. **Installing** page table mappings - Whether creating a new mapping or
310 modifying an existing one in such a way as to change its identity. This
311 requires that the VMA is kept stable via an mmap or VMA lock (explicitly not
312 rmap locks).
313 3. **Zapping/unmapping** page table entries - This is what the kernel calls
314 clearing page table mappings at the leaf level only, whilst leaving all page
315 tables in place. This is a very common operation in the kernel performed on
316 file truncation, the :c:macro:`!MADV_DONTNEED` operation via
317 :c:func:`!madvise`, and others. This is performed by a number of functions
318 including :c:func:`!unmap_mapping_range` and :c:func:`!unmap_mapping_pages`.
319 The VMA need only be kept stable for this operation.
320 4. **Freeing** page tables - When finally the kernel removes page tables from a
321 userland process (typically via :c:func:`!free_pgtables`) extreme care must
322 be taken to ensure this is done safely, as this logic finally frees all page
323 tables in the specified range, ignoring existing leaf entries (it assumes the
324 caller has both zapped the range and prevented any further faults or
325 modifications within it).
326
327 .. note:: Modifying mappings for reclaim or migration is performed under rmap
328 lock as it, like zapping, does not fundamentally modify the identity
329 of what is being mapped.
330
331 **Traversing** and **zapping** ranges can be performed holding any one of the
332 locks described in the terminology section above - that is the mmap lock, the
333 VMA lock or either of the reverse mapping locks.
334
335 That is - as long as you keep the relevant VMA **stable** - you are good to go
336 ahead and perform these operations on page tables (though internally, kernel
337 operations that perform writes also acquire internal page table locks to
338 serialise - see the page table implementation detail section for more details).
339
340 .. note:: We free empty PTE tables on zap under the RCU lock - this does not
341 change the aforementioned locking requirements around zapping.
342
343 When **installing** page table entries, the mmap or VMA lock must be held to
344 keep the VMA stable. We explore why this is in the page table locking details
345 section below.
346
347 **Freeing** page tables is an entirely internal memory management operation and
348 has special requirements (see the page freeing section below for more details).
349
350 .. warning:: When **freeing** page tables, it must not be possible for VMAs
351 containing the ranges those page tables map to be accessible via
352 the reverse mapping.
353
354 The :c:func:`!free_pgtables` function removes the relevant VMAs
355 from the reverse mappings, but no other VMAs can be permitted to be
356 accessible and span the specified range.
357
358 Traversing non-VMA page tables
359 ------------------------------
360
361 We've focused above on traversal of page tables belonging to VMAs. It is also
362 possible to traverse page tables which are not represented by VMAs.
363
364 Kernel page table mappings themselves are generally managed but whatever part of
365 the kernel established them and the aforementioned locking rules do not apply -
366 for instance vmalloc has its own set of locks which are utilised for
367 establishing and tearing down page its page tables.
368
369 However, for convenience we provide the :c:func:`!walk_kernel_page_table_range`
370 function which is synchronised via the mmap lock on the :c:macro:`!init_mm`
371 kernel instantiation of the :c:struct:`!struct mm_struct` metadata object.
372
373 If an operation requires exclusive access, a write lock is used, but if not, a
374 read lock suffices - we assert only that at least a read lock has been acquired.
375
376 Since, aside from vmalloc and memory hot plug, kernel page tables are not torn
377 down all that often - this usually suffices, however any caller of this
378 functionality must ensure that any additionally required locks are acquired in
379 advance.
380
381 We also permit a truly unusual case is the traversal of non-VMA ranges in
382 **userland** ranges, as provided for by :c:func:`!walk_page_range_debug`.
383
384 This has only one user - the general page table dumping logic (implemented in
385 :c:macro:`!mm/ptdump.c`) - which seeks to expose all mappings for debug purposes
386 even if they are highly unusual (possibly architecture-specific) and are not
387 backed by a VMA.
388
389 We must take great care in this case, as the :c:func:`!munmap` implementation
390 detaches VMAs under an mmap write lock before tearing down page tables under a
391 downgraded mmap read lock.
392
393 This means such an operation could race with this, and thus an mmap **write**
394 lock is required.
395
396 Lock ordering
397 -------------
398
399 As we have multiple locks across the kernel which may or may not be taken at the
400 same time as explicit mm or VMA locks, we have to be wary of lock inversion, and
401 the **order** in which locks are acquired and released becomes very important.
402
403 .. note:: Lock inversion occurs when two threads need to acquire multiple locks,
404 but in doing so inadvertently cause a mutual deadlock.
405
406 For example, consider thread 1 which holds lock A and tries to acquire lock B,
407 while thread 2 holds lock B and tries to acquire lock A.
408
409 Both threads are now deadlocked on each other. However, had they attempted to
410 acquire locks in the same order, one would have waited for the other to
411 complete its work and no deadlock would have occurred.
412
413 The opening comment in :c:macro:`!mm/rmap.c` describes in detail the required
414 ordering of locks within memory management code:
415
416 .. code-block::
417
418 inode->i_rwsem (while writing or truncating, not reading or faulting)
419 mm->mmap_lock
420 mapping->invalidate_lock (in filemap_fault)
421 folio_lock
422 hugetlbfs_i_mmap_rwsem_key (in huge_pmd_share, see hugetlbfs below)
423 vma_start_write
424 mapping->i_mmap_rwsem
425 anon_vma->rwsem
426 mm->page_table_lock or pte_lock
427 swap_lock (in swap_duplicate, swap_info_get)
428 mmlist_lock (in mmput, drain_mmlist and others)
429 mapping->private_lock (in block_dirty_folio)
430 i_pages lock (widely used)
431 lruvec->lru_lock (in folio_lruvec_lock_irq)
432 inode->i_lock (in set_page_dirty's __mark_inode_dirty)
433 bdi.wb->list_lock (in set_page_dirty's __mark_inode_dirty)
434 sb_lock (within inode_lock in fs/fs-writeback.c)
435 i_pages lock (widely used, in set_page_dirty,
436 in arch-dependent flush_dcache_mmap_lock,
437 within bdi.wb->list_lock in __sync_single_inode)
438
439 There is also a file-system specific lock ordering comment located at the top of
440 :c:macro:`!mm/filemap.c`:
441
442 .. code-block::
443
444 ->i_mmap_rwsem (truncate_pagecache)
445 ->private_lock (__free_pte->block_dirty_folio)
446 ->swap_lock (exclusive_swap_page, others)
447 ->i_pages lock
448
449 ->i_rwsem
450 ->invalidate_lock (acquired by fs in truncate path)
451 ->i_mmap_rwsem (truncate->unmap_mapping_range)
452
453 ->mmap_lock
454 ->i_mmap_rwsem
455 ->page_table_lock or pte_lock (various, mainly in memory.c)
456 ->i_pages lock (arch-dependent flush_dcache_mmap_lock)
457
458 ->mmap_lock
459 ->invalidate_lock (filemap_fault)
460 ->lock_page (filemap_fault, access_process_vm)
461
462 ->i_rwsem (generic_perform_write)
463 ->mmap_lock (fault_in_readable->do_page_fault)
464
465 bdi->wb.list_lock
466 sb_lock (fs/fs-writeback.c)
467 ->i_pages lock (__sync_single_inode)
468
469 ->i_mmap_rwsem
470 ->anon_vma.lock (vma_merge)
471
472 ->anon_vma.lock
473 ->page_table_lock or pte_lock (anon_vma_prepare and various)
474
475 ->page_table_lock or pte_lock
476 ->swap_lock (try_to_unmap_one)
477 ->private_lock (try_to_unmap_one)
478 ->i_pages lock (try_to_unmap_one)
479 ->lruvec->lru_lock (follow_page_mask->mark_page_accessed)
480 ->lruvec->lru_lock (check_pte_range->folio_isolate_lru)
481 ->private_lock (folio_remove_rmap_pte->set_page_dirty)
482 ->i_pages lock (folio_remove_rmap_pte->set_page_dirty)
483 bdi.wb->list_lock (folio_remove_rmap_pte->set_page_dirty)
484 ->inode->i_lock (folio_remove_rmap_pte->set_page_dirty)
485 bdi.wb->list_lock (zap_pte_range->set_page_dirty)
486 ->inode->i_lock (zap_pte_range->set_page_dirty)
487 ->private_lock (zap_pte_range->block_dirty_folio)
488
489 Please check the current state of these comments which may have changed since
490 the time of writing of this document.
491
492 ------------------------------
493 Locking Implementation Details
494 ------------------------------
495
496 .. warning:: Locking rules for PTE-level page tables are very different from
497 locking rules for page tables at other levels.
498
499 Page table locking details
500 --------------------------
501
502 .. note:: This section explores page table locking requirements for page tables
503 encompassed by a VMA. See the above section on non-VMA page table
504 traversal for details on how we handle that case.
505
506 In addition to the locks described in the terminology section above, we have
507 additional locks dedicated to page tables:
508
509 * **Higher level page table locks** - Higher level page tables, that is PGD, P4D
510 and PUD each make use of the process address space granularity
511 :c:member:`!mm->page_table_lock` lock when modified.
512
513 * **Fine-grained page table locks** - PMDs and PTEs each have fine-grained locks
514 either kept within the folios describing the page tables or allocated
515 separated and pointed at by the folios if :c:macro:`!ALLOC_SPLIT_PTLOCKS` is
516 set. The PMD spin lock is obtained via :c:func:`!pmd_lock`, however PTEs are
517 mapped into higher memory (if a 32-bit system) and carefully locked via
518 :c:func:`!pte_offset_map_lock`.
519
520 These locks represent the minimum required to interact with each page table
521 level, but there are further requirements.
522
523 Importantly, note that on a **traversal** of page tables, sometimes no such
524 locks are taken. However, at the PTE level, at least concurrent page table
525 deletion must be prevented (using RCU) and the page table must be mapped into
526 high memory, see below.
527
528 Whether care is taken on reading the page table entries depends on the
529 architecture, see the section on atomicity below.
530
531 Locking rules
532 ^^^^^^^^^^^^^
533
534 We establish basic locking rules when interacting with page tables:
535
536 * When changing a page table entry the page table lock for that page table
537 **must** be held, except if you can safely assume nobody can access the page
538 tables concurrently (such as on invocation of :c:func:`!free_pgtables`).
539 * Reads from and writes to page table entries must be *appropriately*
540 atomic. See the section on atomicity below for details.
541 * Populating previously empty entries requires that the mmap or VMA locks are
542 held (read or write), doing so with only rmap locks would be dangerous (see
543 the warning below).
544 * As mentioned previously, zapping can be performed while simply keeping the VMA
545 stable, that is holding any one of the mmap, VMA or rmap locks.
546
547 .. warning:: Populating previously empty entries is dangerous as, when unmapping
548 VMAs, :c:func:`!vms_clear_ptes` has a window of time between
549 zapping (via :c:func:`!unmap_vmas`) and freeing page tables (via
550 :c:func:`!free_pgtables`), where the VMA is still visible in the
551 rmap tree. :c:func:`!free_pgtables` assumes that the zap has
552 already been performed and removes PTEs unconditionally (along with
553 all other page tables in the freed range), so installing new PTE
554 entries could leak memory and also cause other unexpected and
555 dangerous behaviour.
556
557 There are additional rules applicable when moving page tables, which we discuss
558 in the section on this topic below.
559
560 PTE-level page tables are different from page tables at other levels, and there
561 are extra requirements for accessing them:
562
563 * On 32-bit architectures, they may be in high memory (meaning they need to be
564 mapped into kernel memory to be accessible).
565 * When empty, they can be unlinked and RCU-freed while holding an mmap lock or
566 rmap lock for reading in combination with the PTE and PMD page table locks.
567 In particular, this happens in :c:func:`!retract_page_tables` when handling
568 :c:macro:`!MADV_COLLAPSE`.
569 So accessing PTE-level page tables requires at least holding an RCU read lock;
570 but that only suffices for readers that can tolerate racing with concurrent
571 page table updates such that an empty PTE is observed (in a page table that
572 has actually already been detached and marked for RCU freeing) while another
573 new page table has been installed in the same location and filled with
574 entries. Writers normally need to take the PTE lock and revalidate that the
575 PMD entry still refers to the same PTE-level page table.
576 If the writer does not care whether it is the same PTE-level page table, it
577 can take the PMD lock and revalidate that the contents of pmd entry still meet
578 the requirements. In particular, this also happens in :c:func:`!retract_page_tables`
579 when handling :c:macro:`!MADV_COLLAPSE`.
580
581 To access PTE-level page tables, a helper like :c:func:`!pte_offset_map_lock` or
582 :c:func:`!pte_offset_map` can be used depending on stability requirements.
583 These map the page table into kernel memory if required, take the RCU lock, and
584 depending on variant, may also look up or acquire the PTE lock.
585 See the comment on :c:func:`!__pte_offset_map_lock`.
586
587 Atomicity
588 ^^^^^^^^^
589
590 Regardless of page table locks, the MMU hardware concurrently updates accessed
591 and dirty bits (perhaps more, depending on architecture). Additionally, page
592 table traversal operations in parallel (though holding the VMA stable) and
593 functionality like GUP-fast locklessly traverses (that is reads) page tables,
594 without even keeping the VMA stable at all.
595
596 When performing a page table traversal and keeping the VMA stable, whether a
597 read must be performed once and only once or not depends on the architecture
598 (for instance x86-64 does not require any special precautions).
599
600 If a write is being performed, or if a read informs whether a write takes place
601 (on an installation of a page table entry say, for instance in
602 :c:func:`!__pud_install`), special care must always be taken. In these cases we
603 can never assume that page table locks give us entirely exclusive access, and
604 must retrieve page table entries once and only once.
605
606 If we are reading page table entries, then we need only ensure that the compiler
607 does not rearrange our loads. This is achieved via :c:func:`!pXXp_get`
608 functions - :c:func:`!pgdp_get`, :c:func:`!p4dp_get`, :c:func:`!pudp_get`,
609 :c:func:`!pmdp_get`, and :c:func:`!ptep_get`.
610
611 Each of these uses :c:func:`!READ_ONCE` to guarantee that the compiler reads
612 the page table entry only once.
613
614 However, if we wish to manipulate an existing page table entry and care about
615 the previously stored data, we must go further and use an hardware atomic
616 operation as, for example, in :c:func:`!ptep_get_and_clear`.
617
618 Equally, operations that do not rely on the VMA being held stable, such as
619 GUP-fast (see :c:func:`!gup_fast` and its various page table level handlers like
620 :c:func:`!gup_fast_pte_range`), must very carefully interact with page table
621 entries, using functions such as :c:func:`!ptep_get_lockless` and equivalent for
622 higher level page table levels.
623
624 Writes to page table entries must also be appropriately atomic, as established
625 by :c:func:`!set_pXX` functions - :c:func:`!set_pgd`, :c:func:`!set_p4d`,
626 :c:func:`!set_pud`, :c:func:`!set_pmd`, and :c:func:`!set_pte`.
627
628 Equally functions which clear page table entries must be appropriately atomic,
629 as in :c:func:`!pXX_clear` functions - :c:func:`!pgd_clear`,
630 :c:func:`!p4d_clear`, :c:func:`!pud_clear`, :c:func:`!pmd_clear`, and
631 :c:func:`!pte_clear`.
632
633 Page table installation
634 ^^^^^^^^^^^^^^^^^^^^^^^
635
636 Page table installation is performed with the VMA held stable explicitly by an
637 mmap or VMA lock in read or write mode (see the warning in the locking rules
638 section for details as to why).
639
640 When allocating a P4D, PUD or PMD and setting the relevant entry in the above
641 PGD, P4D or PUD, the :c:member:`!mm->page_table_lock` must be held. This is
642 acquired in :c:func:`!__p4d_alloc`, :c:func:`!__pud_alloc` and
643 :c:func:`!__pmd_alloc` respectively.
644
645 .. note:: :c:func:`!__pmd_alloc` actually invokes :c:func:`!pud_lock` and
646 :c:func:`!pud_lockptr` in turn, however at the time of writing it ultimately
647 references the :c:member:`!mm->page_table_lock`.
648
649 Allocating a PTE will either use the :c:member:`!mm->page_table_lock` or, if
650 :c:macro:`!USE_SPLIT_PMD_PTLOCKS` is defined, a lock embedded in the PMD
651 physical page metadata in the form of a :c:struct:`!struct ptdesc`, acquired by
652 :c:func:`!pmd_ptdesc` called from :c:func:`!pmd_lock` and ultimately
653 :c:func:`!__pte_alloc`.
654
655 Finally, modifying the contents of the PTE requires special treatment, as the
656 PTE page table lock must be acquired whenever we want stable and exclusive
657 access to entries contained within a PTE, especially when we wish to modify
658 them.
659
660 This is performed via :c:func:`!pte_offset_map_lock` which carefully checks to
661 ensure that the PTE hasn't changed from under us, ultimately invoking
662 :c:func:`!pte_lockptr` to obtain a spin lock at PTE granularity contained within
663 the :c:struct:`!struct ptdesc` associated with the physical PTE page. The lock
664 must be released via :c:func:`!pte_unmap_unlock`.
665
666 .. note:: There are some variants on this, such as
667 :c:func:`!pte_offset_map_rw_nolock` when we know we hold the PTE stable but
668 for brevity we do not explore this. See the comment for
669 :c:func:`!__pte_offset_map_lock` for more details.
670
671 When modifying data in ranges we typically only wish to allocate higher page
672 tables as necessary, using these locks to avoid races or overwriting anything,
673 and set/clear data at the PTE level as required (for instance when page faulting
674 or zapping).
675
676 A typical pattern taken when traversing page table entries to install a new
677 mapping is to optimistically determine whether the page table entry in the table
678 above is empty, if so, only then acquiring the page table lock and checking
679 again to see if it was allocated underneath us.
680
681 This allows for a traversal with page table locks only being taken when
682 required. An example of this is :c:func:`!__pud_alloc`.
683
684 At the leaf page table, that is the PTE, we can't entirely rely on this pattern
685 as we have separate PMD and PTE locks and a THP collapse for instance might have
686 eliminated the PMD entry as well as the PTE from under us.
687
688 This is why :c:func:`!__pte_offset_map_lock` locklessly retrieves the PMD entry
689 for the PTE, carefully checking it is as expected, before acquiring the
690 PTE-specific lock, and then *again* checking that the PMD entry is as expected.
691
692 If a THP collapse (or similar) were to occur then the lock on both pages would
693 be acquired, so we can ensure this is prevented while the PTE lock is held.
694
695 Installing entries this way ensures mutual exclusion on write.
696
697 Page table freeing
698 ^^^^^^^^^^^^^^^^^^
699
700 Tearing down page tables themselves is something that requires significant
701 care. There must be no way that page tables designated for removal can be
702 traversed or referenced by concurrent tasks.
703
704 It is insufficient to simply hold an mmap write lock and VMA lock (which will
705 prevent racing faults, and rmap operations), as a file-backed mapping can be
706 truncated under the :c:struct:`!struct address_space->i_mmap_rwsem` alone.
707
708 As a result, no VMA which can be accessed via the reverse mapping (either
709 through the :c:struct:`!struct anon_vma->rb_root` or the :c:member:`!struct
710 address_space->i_mmap` interval trees) can have its page tables torn down.
711
712 The operation is typically performed via :c:func:`!free_pgtables`, which assumes
713 either the mmap write lock has been taken (as specified by its
714 :c:member:`!mm_wr_locked` parameter), or that the VMA is already unreachable.
715
716 It carefully removes the VMA from all reverse mappings, however it's important
717 that no new ones overlap these or any route remain to permit access to addresses
718 within the range whose page tables are being torn down.
719
720 Additionally, it assumes that a zap has already been performed and steps have
721 been taken to ensure that no further page table entries can be installed between
722 the zap and the invocation of :c:func:`!free_pgtables`.
723
724 Since it is assumed that all such steps have been taken, page table entries are
725 cleared without page table locks (in the :c:func:`!pgd_clear`, :c:func:`!p4d_clear`,
726 :c:func:`!pud_clear`, and :c:func:`!pmd_clear` functions.
727
728 .. note:: It is possible for leaf page tables to be torn down independent of
729 the page tables above it as is done by
730 :c:func:`!retract_page_tables`, which is performed under the i_mmap
731 read lock, PMD, and PTE page table locks, without this level of care.
732
733 Page table moving
734 ^^^^^^^^^^^^^^^^^
735
736 Some functions manipulate page table levels above PMD (that is PUD, P4D and PGD
737 page tables). Most notable of these is :c:func:`!mremap`, which is capable of
738 moving higher level page tables.
739
740 In these instances, it is required that **all** locks are taken, that is
741 the mmap lock, the VMA lock and the relevant rmap locks.
742
743 You can observe this in the :c:func:`!mremap` implementation in the functions
744 :c:func:`!take_rmap_locks` and :c:func:`!drop_rmap_locks` which perform the rmap
745 side of lock acquisition, invoked ultimately by :c:func:`!move_page_tables`.
746
747 VMA lock internals
748 ------------------
749
750 Overview
751 ^^^^^^^^
752
753 VMA read locking is entirely optimistic - if the lock is contended or a competing
754 write has started, then we do not obtain a read lock.
755
756 A VMA **read** lock is obtained by :c:func:`!lock_vma_under_rcu`, which first
757 calls :c:func:`!rcu_read_lock` to ensure that the VMA is looked up in an RCU
758 critical section, then attempts to VMA lock it via :c:func:`!vma_start_read`,
759 before releasing the RCU lock via :c:func:`!rcu_read_unlock`.
760
761 In cases when the user already holds mmap read lock, :c:func:`!vma_start_read_locked`
762 and :c:func:`!vma_start_read_locked_nested` can be used. These functions do not
763 fail due to lock contention but the caller should still check their return values
764 in case they fail for other reasons.
765
766 VMA read locks increment :c:member:`!vma.vm_refcnt` reference counter for their
767 duration and the caller of :c:func:`!lock_vma_under_rcu` must drop it via
768 :c:func:`!vma_end_read`.
769
770 VMA **write** locks are acquired via :c:func:`!vma_start_write` in instances where a
771 VMA is about to be modified, unlike :c:func:`!vma_start_read` the lock is always
772 acquired. An mmap write lock **must** be held for the duration of the VMA write
773 lock, releasing or downgrading the mmap write lock also releases the VMA write
774 lock so there is no :c:func:`!vma_end_write` function.
775
776 Note that when write-locking a VMA lock, the :c:member:`!vma.vm_refcnt` is temporarily
777 modified so that readers can detect the presense of a writer. The reference counter is
778 restored once the vma sequence number used for serialisation is updated.
779
780 This ensures the semantics we require - VMA write locks provide exclusive write
781 access to the VMA.
782
783 Implementation details
784 ^^^^^^^^^^^^^^^^^^^^^^
785
786 The VMA lock mechanism is designed to be a lightweight means of avoiding the use
787 of the heavily contended mmap lock. It is implemented using a combination of a
788 reference counter and sequence numbers belonging to the containing
789 :c:struct:`!struct mm_struct` and the VMA.
790
791 Read locks are acquired via :c:func:`!vma_start_read`, which is an optimistic
792 operation, i.e. it tries to acquire a read lock but returns false if it is
793 unable to do so. At the end of the read operation, :c:func:`!vma_end_read` is
794 called to release the VMA read lock.
795
796 Invoking :c:func:`!vma_start_read` requires that :c:func:`!rcu_read_lock` has
797 been called first, establishing that we are in an RCU critical section upon VMA
798 read lock acquisition. Once acquired, the RCU lock can be released as it is only
799 required for lookup. This is abstracted by :c:func:`!lock_vma_under_rcu` which
800 is the interface a user should use.
801
802 Writing requires the mmap to be write-locked and the VMA lock to be acquired via
803 :c:func:`!vma_start_write`, however the write lock is released by the termination or
804 downgrade of the mmap write lock so no :c:func:`!vma_end_write` is required.
805
806 All this is achieved by the use of per-mm and per-VMA sequence counts, which are
807 used in order to reduce complexity, especially for operations which write-lock
808 multiple VMAs at once.
809
810 If the mm sequence count, :c:member:`!mm->mm_lock_seq` is equal to the VMA
811 sequence count :c:member:`!vma->vm_lock_seq` then the VMA is write-locked. If
812 they differ, then it is not.
813
814 Each time the mmap write lock is released in :c:func:`!mmap_write_unlock` or
815 :c:func:`!mmap_write_downgrade`, :c:func:`!vma_end_write_all` is invoked which
816 also increments :c:member:`!mm->mm_lock_seq` via
817 :c:func:`!mm_lock_seqcount_end`.
818
819 This way, we ensure that, regardless of the VMA's sequence number, a write lock
820 is never incorrectly indicated and that when we release an mmap write lock we
821 efficiently release **all** VMA write locks contained within the mmap at the
822 same time.
823
824 Since the mmap write lock is exclusive against others who hold it, the automatic
825 release of any VMA locks on its release makes sense, as you would never want to
826 keep VMAs locked across entirely separate write operations. It also maintains
827 correct lock ordering.
828
829 Each time a VMA read lock is acquired, we increment :c:member:`!vma.vm_refcnt`
830 reference counter and check that the sequence count of the VMA does not match
831 that of the mm.
832
833 If it does, the read lock fails and :c:member:`!vma.vm_refcnt` is dropped.
834 If it does not, we keep the reference counter raised, excluding writers, but
835 permitting other readers, who can also obtain this lock under RCU.
836
837 Importantly, maple tree operations performed in :c:func:`!lock_vma_under_rcu`
838 are also RCU safe, so the whole read lock operation is guaranteed to function
839 correctly.
840
841 On the write side, we set a bit in :c:member:`!vma.vm_refcnt` which can't be
842 modified by readers and wait for all readers to drop their reference count.
843 Once there are no readers, the VMA's sequence number is set to match that of
844 the mm. During this entire operation mmap write lock is held.
845
846 This way, if any read locks are in effect, :c:func:`!vma_start_write` will sleep
847 until these are finished and mutual exclusion is achieved.
848
849 After setting the VMA's sequence number, the bit in :c:member:`!vma.vm_refcnt`
850 indicating a writer is cleared. From this point on, VMA's sequence number will
851 indicate VMA's write-locked state until mmap write lock is dropped or downgraded.
852
853 This clever combination of a reference counter and sequence count allows for
854 fast RCU-based per-VMA lock acquisition (especially on page fault, though
855 utilised elsewhere) with minimal complexity around lock ordering.
856
857 mmap write lock downgrading
858 ---------------------------
859
860 When an mmap write lock is held one has exclusive access to resources within the
861 mmap (with the usual caveats about requiring VMA write locks to avoid races with
862 tasks holding VMA read locks).
863
864 It is then possible to **downgrade** from a write lock to a read lock via
865 :c:func:`!mmap_write_downgrade` which, similar to :c:func:`!mmap_write_unlock`,
866 implicitly terminates all VMA write locks via :c:func:`!vma_end_write_all`, but
867 importantly does not relinquish the mmap lock while downgrading, therefore
868 keeping the locked virtual address space stable.
869
870 An interesting consequence of this is that downgraded locks are exclusive
871 against any other task possessing a downgraded lock (since a racing task would
872 have to acquire a write lock first to downgrade it, and the downgraded lock
873 prevents a new write lock from being obtained until the original lock is
874 released).
875
876 For clarity, we map read (R)/downgraded write (D)/write (W) locks against one
877 another showing which locks exclude the others:
878
879 .. list-table:: Lock exclusivity
880 :widths: 5 5 5 5
881 :header-rows: 1
882 :stub-columns: 1
883
884 * -
885 - R
886 - D
887 - W
888 * - R
889 - N
890 - N
891 - Y
892 * - D
893 - N
894 - Y
895 - Y
896 * - W
897 - Y
898 - Y
899 - Y
900
901 Here a Y indicates the locks in the matching row/column are mutually exclusive,
902 and N indicates that they are not.
903
904 Stack expansion
905 ---------------
906
907 Stack expansion throws up additional complexities in that we cannot permit there
908 to be racing page faults, as a result we invoke :c:func:`!vma_start_write` to
909 prevent this in :c:func:`!expand_downwards` or :c:func:`!expand_upwards`.
910

3. 한국어 전문 번역

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

Process address space와 VMA model

1-30

Kernel은 userspace memory range를 `struct vm_area_struct` 유형의 Virtual Memory Area, 즉 VMA로 추적합니다.

각 VMA object는 attribute가 동일한 virtual-contiguous memory range 하나를 설명합니다. 인접한 stack VMA를 accessed address까지 확장할 수 있는 경우를 제외하면, VMA 밖의 userspace access는 invalid입니다.

모든 VMA는 정확히 하나의 virtual-address space에 속합니다. 이 address space는 `struct mm_struct` object가 설명하며, 같은 virtual-address space를 공유하는 모든 task, 즉 thread가 이를 참조합니다. 문서에서는 이 object를 `mm`이라고 부릅니다.

각 `mm` object는 virtual-address space 안의 모든 VMA를 설명하는 maple-tree 자료 구조를 포함합니다.

예외는 `vsyscall`을 사용하는 architecture가 제공하는 `gate` VMA입니다. 이는 특정 `mm`에 속하지 않는 global static object입니다.

.. SPDX-License-Identifier: GPL-2.0

=================
Process Addresses
=================

.. toctree::
   :maxdepth: 3


Userland memory ranges are tracked by the kernel via Virtual Memory Areas or
'VMA's of type :c:struct:`!struct vm_area_struct`.

Each VMA describes a virtually contiguous memory range with identical
attributes, each described by a :c:struct:`!struct vm_area_struct`
object. Userland access outside of VMAs is invalid except in the case where an
adjacent stack VMA could be extended to contain the accessed address.

All VMAs are contained within one and only one virtual address space, described
by a :c:struct:`!struct mm_struct` object which is referenced by all tasks (that is,
threads) which share the virtual address space. We refer to this as the
:c:struct:`!mm`.

Each mm object contains a maple tree data structure which describes all VMAs
within the virtual address space.

.. note:: An exception to this is the 'gate' VMA which is provided by
          architectures which use :c:struct:`!vsyscall` and is a global static
          object which does not belong to any specific mm.

VMA metadata lock 용어

31-70

Kernel은 VMA metadata에 대한 concurrent read operation이 잘 확장되도록 설계됐습니다. Memory corruption을 막기 위해 복잡한 lock set이 필요합니다. VMA metadata를 lock해도 VMA가 설명하는 memory나 이를 mapping하는 page table에는 영향을 주지 않습니다.

  • `mmap lock`: 각 MM의 process-address-space 단위 read/write semaphore인 `mmap_lock`입니다. `mmap_read_lock`, `mmap_write_lock`과 variant로 획득합니다.
  • `VMA lock`: VMA 단위이며 실제로 read/write semaphore처럼 동작합니다. Read lock은 `lock_vma_under_rcu`로 얻고 `vma_end_read`로 놓습니다. Write lock은 `vma_start_write`로 얻으며 mmap write lock을 놓을 때 모든 VMA write lock이 자동 해제됩니다. VMA write lock을 얻기 전에 반드시 `mmap_write_lock`을 획득해야 합니다.
  • `rmap lock`: Folio의 `folio->mapping`에서 도달할 수 있는 `struct address_space` 또는 `struct anon_vma`를 통해 reverse mapping으로 VMA에 접근할 때 사용합니다. Anonymous memory는 `anon_vma_[try]lock_read/write`, file-backed memory는 `i_mmap_[try]lock_read/write`로 VMA를 안정화합니다.

Page-table lock은 뒤의 전용 section에서 별도로 설명합니다.

이 lock들이 가장 먼저 보장하는 것은 MM tree 안에서 VMA를 안정화하는 것입니다. 즉 VMA object가 접근 중 삭제되거나 아래에서 설명하는 일부 field를 제외하고 수정되지 않음을 보장합니다. VMA 안정화는 그 VMA가 설명하는 address space도 계속 존재하게 합니다.

-------
Locking
-------

The kernel is designed to be highly scalable against concurrent read operations
on VMA **metadata** so a complicated set of locks are required to ensure memory
corruption does not occur.

.. note:: Locking VMAs for their metadata does not have any impact on the memory
          they describe nor the page tables that map them.

Terminology
-----------

* **mmap locks** - Each MM has a read/write semaphore :c:member:`!mmap_lock`
  which locks at a process address space granularity which can be acquired via
  :c:func:`!mmap_read_lock`, :c:func:`!mmap_write_lock` and variants.
* **VMA locks** - The VMA lock is at VMA granularity (of course) which behaves
  as a read/write semaphore in practice. A VMA read lock is obtained via
  :c:func:`!lock_vma_under_rcu` (and unlocked via :c:func:`!vma_end_read`) and a
  write lock via :c:func:`!vma_start_write` (all VMA write locks are unlocked
  automatically when the mmap write lock is released). To take a VMA write lock
  you **must** have already acquired an :c:func:`!mmap_write_lock`.
* **rmap locks** - When trying to access VMAs through the reverse mapping via a
  :c:struct:`!struct address_space` or :c:struct:`!struct anon_vma` object
  (reachable from a folio via :c:member:`!folio->mapping`). VMAs must be stabilised via
  :c:func:`!anon_vma_[try]lock_read` or :c:func:`!anon_vma_[try]lock_write` for
  anonymous memory and :c:func:`!i_mmap_[try]lock_read` or
  :c:func:`!i_mmap_[try]lock_write` for file-backed memory. We refer to these
  locks as the reverse mapping locks, or 'rmap locks' for brevity.

We discuss page table locks separately in the dedicated section below.

The first thing **any** of these locks achieve is to **stabilise** the VMA
within the MM tree. That is, guaranteeing that the VMA object will not be
deleted from under you nor modified (except for some specific fields
described below).

Stabilising a VMA also keeps the address space described by it around.

Read·write lock 사용과 유효 상태

71-141

VMA metadata를 읽거나 VMA를 stable하게 유지하려면 다음 중 하나를 수행합니다.

  • `mmap_read_lock` 또는 알맞은 variant로 MM 단위 mmap read lock을 얻고, 작업 후 대응하는 `mmap_read_unlock`으로 놓습니다.
  • `lock_vma_under_rcu`로 VMA read lock을 시도합니다. Atomic하게 획득하므로 실패할 수 있습니다. `NULL`을 반환하면 fallback logic으로 mmap read lock을 얻어야 합니다.
  • Anonymous 또는 file-backed locked interval tree를 순회하기 전에 rmap lock을 얻고 필요한 VMA를 찾습니다.

VMA metadata 대부분을 write하려면 다음 lock을 함께 사용합니다.

  • `mmap_write_lock` 또는 variant로 MM 단위 mmap write lock을 얻고 작업 후 `mmap_write_unlock`으로 놓습니다.
  • 수정할 각 VMA에 `vma_start_write`를 호출해 VMA write lock을 얻습니다. `mmap_write_unlock` 때 자동 해제됩니다.
  • 어떤 field든 제한 없이 write하려면 rmap write lock을 얻어 reverse mapping에서 VMA를 숨겨야 합니다.

VMA write lock을 얻으려면 mmap write lock을 먼저 얻어야 합니다. 반면 VMA read lock은 다른 lock 없이 얻을 수 있습니다. `lock_vma_under_rcu`가 VMA lookup을 위해 RCU lock을 얻었다가 놓습니다. 이 방식은 writer가 한 VMA를 다루는 동안 reader가 다른 VMA를 동시에 다룰 수 있게 해 writer의 영향을 제한합니다.

VMA read lock의 주 사용자는 page-fault handler입니다. 따라서 VMA write lock이 없으면 수행 중인 작업과 page fault가 동시에 실행될 수 있습니다.

유효 lock-state 표의 의미는 다음과 같습니다. Lock이 전혀 없으면 stable·read·write 모두 불가능합니다. VMA read 또는 rmap read/write만 있어도 stable과 read가 가능합니다. Mmap read/write가 있으면 VMA와 rmap lock 조합에 관계없이 stable과 read가 가능합니다. Mmap write와 VMA write가 있으면 대부분 field를 write할 수 있고, rmap write까지 있으면 모든 field를 write할 수 있습니다.

Mmap read lock을 가진 채 VMA lock을 얻을 수는 있지만, 반대로 VMA read lock을 가진 채 mmap lock을 얻으려 하면 deadlock이 생길 수 있어 invalid입니다. 다른 task가 mmap write lock을 가진 상태에서 VMA write lock을 기다리면 현재 VMA read lock과 서로 막힐 수 있습니다.

세 lock은 실제로 read/write semaphore처럼 동작합니다. 여러 reader는 concurrent하지만 writer는 모든 reader가 critical region을 떠날 때까지 기다리며 pending reader도 대기시킵니다. 따라서 read lock끼리는 concurrent이고 write lock은 다른 모든 holder에 대해 exclusive입니다.

Lock usage
----------

If you want to **read** VMA metadata fields or just keep the VMA stable, you
must do one of the following:

* Obtain an mmap read lock at the MM granularity via :c:func:`!mmap_read_lock` (or a
  suitable variant), unlocking it with a matching :c:func:`!mmap_read_unlock` when
  you're done with the VMA, *or*
* Try to obtain a VMA read lock via :c:func:`!lock_vma_under_rcu`. This tries to
  acquire the lock atomically so might fail, in which case fall-back logic is
  required to instead obtain an mmap read lock if this returns :c:macro:`!NULL`,
  *or*
* Acquire an rmap lock before traversing the locked interval tree (whether
  anonymous or file-backed) to obtain the required VMA.

If you want to **write** VMA metadata fields, then things vary depending on the
field (we explore each VMA field in detail below). For the majority you must:

* Obtain an mmap write lock at the MM granularity via :c:func:`!mmap_write_lock` (or a
  suitable variant), unlocking it with a matching :c:func:`!mmap_write_unlock` when
  you're done with the VMA, *and*
* Obtain a VMA write lock via :c:func:`!vma_start_write` for each VMA you wish to
  modify, which will be released automatically when :c:func:`!mmap_write_unlock` is
  called.
* If you want to be able to write to **any** field, you must also hide the VMA
  from the reverse mapping by obtaining an **rmap write lock**.

VMA locks are special in that you must obtain an mmap **write** lock **first**
in order to obtain a VMA **write** lock. A VMA **read** lock however can be
obtained without any other lock (:c:func:`!lock_vma_under_rcu` will acquire then
release an RCU lock to lookup the VMA for you).

This constrains the impact of writers on readers, as a writer can interact with
one VMA while a reader interacts with another simultaneously.

.. note:: The primary users of VMA read locks are page fault handlers, which
          means that without a VMA write lock, page faults will run concurrent with
          whatever you are doing.

Examining all valid lock states:

.. table::

   ========= ======== ========= ======= ===== =========== ==========
   mmap lock VMA lock rmap lock Stable? Read? Write most? Write all?
   ========= ======== ========= ======= ===== =========== ==========
   \-        \-       \-        N       N     N           N
   \-        R        \-        Y       Y     N           N
   \-        \-       R/W       Y       Y     N           N
   R/W       \-/R     \-/R/W    Y       Y     N           N
   W         W        \-/R      Y       Y     Y           N
   W         W        W         Y       Y     Y           Y
   ========= ======== ========= ======= ===== =========== ==========

.. warning:: While it's possible to obtain a VMA lock while holding an mmap read lock,
             attempting to do the reverse is invalid as it can result in deadlock - if
             another task already holds an mmap write lock and attempts to acquire a VMA
             write lock that will deadlock on the VMA read lock.

All of these locks behave as read/write semaphores in practice, so you can
obtain either a read or a write lock for each of these.

.. note:: Generally speaking, a read/write semaphore is a class of lock which
          permits concurrent readers. However a write lock can only be obtained
          once all readers have left the critical region (and pending readers
          made to wait).

          This renders read locks on a read/write semaphore concurrent with other
          readers and write locks exclusive against all others holding the semaphore.

VMA field와 write-lock 요구

142-278

`struct vm_area_struct` field를 목적별로 나누면 locking 특성을 이해하기 쉽습니다. 내부 구현 detail인 VMA-lock 전용 field는 제외합니다.

Virtual-layout field는 다음과 같습니다.

  • `vm_start`: VMA range의 inclusive 시작 virtual address입니다. Write에는 mmap write, VMA write, rmap write가 모두 필요합니다.
  • `vm_end`: VMA range의 exclusive 끝 virtual address입니다. Write에는 mmap write, VMA write, rmap write가 모두 필요합니다.
  • `vm_pgoff`: File 안의 page offset, `mremap` 전 virtual-address space의 original page offset, 또는 PFN map이면서 architecture가 `CONFIG_ARCH_HAS_PTE_SPECIAL`을 지원하지 않을 때 PFN을 설명합니다. Write에는 mmap write, VMA write, rmap write가 모두 필요합니다.

이 field는 VMA의 크기·시작·끝을 나타내며 reverse-mapping interval tree에서 VMA를 찾는 데 사용됩니다. 따라서 reverse mapping에서 VMA를 숨기기 전에는 수정할 수 없습니다.

Core field는 다음과 같습니다.

  • `vm_mm`: VMA를 포함하는 `mm_struct`입니다. Initial map 때 한 번만 쓰므로 별도 write lock이 없습니다.
  • `vm_page_prot`: VMA flag에서 결정된 architecture-specific page-table protection bit입니다. Mmap write와 VMA write가 필요합니다.
  • `vm_flags`: VMA attribute를 설명하는 read-only VMA flag access이며 private writable `__vm_flags`와 union입니다. 직접 write 대상이 아닙니다.
  • `__vm_flags`: Private writable VMA-flag field이며 `vm_flags_*` 함수로 갱신합니다. Mmap write와 VMA write가 필요합니다.
  • `vm_file`: File-backed VMA이면 underlying file을 설명하는 `struct file` pointer이고 anonymous이면 `NULL`입니다. Initial map 때 한 번만 씁니다.
  • `vm_ops`: File-backed VMA에서 driver 또는 filesystem이 VMA-lifetime event callback을 설명하는 `struct vm_operations_struct`를 제공합니다. Initial map 때 `f_ops->mmap()`이 한 번 씁니다.
  • `vm_private_data`: Driver-specific metadata용 `void *` field이며 driver가 locking을 처리합니다.

Kernel config에 따라 존재하는 field는 다음과 같습니다.

  • `anon_name` (`CONFIG_ANON_VMA_NAME`): Anonymous mapping 이름을 제공하는 reference-counted `struct anon_vma_name`입니다. 이름이 없거나 file-backed이면 `NULL`이며 확장성을 위해 여러 VMA가 공유할 수 있습니다. Mmap write와 VMA write가 필요합니다.
  • `swap_readahead_info` (`CONFIG_SWAP`): Swap readahead용 metadata이며 atomic하게 접근합니다. Mmap read와 swap-specific lock이 필요합니다.
  • `vm_policy` (`CONFIG_NUMA`): VMA의 NUMA behavior를 설명하는 reference-counted `mempolicy`입니다. Mmap write와 VMA write가 필요합니다.
  • `numab_state` (`CONFIG_NUMA_BALANCING`): 이 VMA와 관련된 현재 NUMA-balancing state를 설명하는 `vma_numab_state`입니다. `task_numa_work`가 mmap read lock 아래에서 갱신하며 mmap read와 numab-specific lock을 사용합니다.
  • `vm_userfaultfd_ctx` (`CONFIG_USERFAULTFD`): `vm_userfaultfd_ctx` wrapper입니다. Userfaultfd가 disable되면 크기 0이고, enable되면 metadata를 설명하는 underlying `userfaultfd_ctx` pointer를 담습니다. Mmap write와 VMA write가 필요합니다.

Reverse-mapping field는 다음과 같습니다.

  • `shared.rb`: File-backed mapping이면 VMA를 `struct address_space->i_mmap` red/black interval tree에 넣는 red/black-tree node입니다. Mmap write, VMA write, i_mmap write가 필요합니다.
  • `shared.rb_subtree_last`: File-backed VMA interval-tree 관리 metadata입니다. Mmap write, VMA write, i_mmap write가 필요합니다.
  • `anon_vma_chain`: Fork·CoW된 `anon_vma` object와 non-NULL인 `vma->anon_vma`를 모두 가리키는 pointer list입니다. Mmap read와 anon_vma write가 필요합니다.
  • `anon_vma`: 이 VMA에 exclusive하게 mapping된 anonymous folio가 속할 `anon_vma`입니다. Page 하나라도 fault-in되면 set됩니다. 처음에는 `anon_vma_prepare`가 `page_table_lock`으로 serialize해 설정합니다. NULL에서 non-NULL로 바꿀 때는 mmap read와 page-table lock, non-NULL에서 NULL로 바꿀 때는 mmap write·VMA write·anon_vma write가 필요합니다.

이 field들은 VMA를 reverse mapping에 배치하고, anonymous mapping에서 관련 `anon_vma`와 exclusive folio용 `anon_vma`에 접근하는 데 사용합니다. File-backed mapping에 `MAP_PRIVATE`가 set되면 `anon_vma`와 `i_mmap` tree에 동시에 들어갈 수 있어 모든 reverse-mapping field를 한꺼번에 사용할 수 있습니다.

VMA fields
^^^^^^^^^^

We can subdivide :c:struct:`!struct vm_area_struct` fields by their purpose, which makes it
easier to explore their locking characteristics:

.. note:: We exclude VMA lock-specific fields here to avoid confusion, as these
          are in effect an internal implementation detail.

.. table:: Virtual layout fields

   ===================== ======================================== ===========
   Field                 Description                              Write lock
   ===================== ======================================== ===========
   :c:member:`!vm_start` Inclusive start virtual address of range mmap write,
                         VMA describes.                           VMA write,
                                                                  rmap write.
   :c:member:`!vm_end`   Exclusive end virtual address of range   mmap write,
                         VMA describes.                           VMA write,
                                                                  rmap write.
   :c:member:`!vm_pgoff` Describes the page offset into the file, mmap write,
                         the original page offset within the      VMA write,
                         virtual address space (prior to any      rmap write.
                         :c:func:`!mremap`), or PFN if a PFN map
                         and the architecture does not support
                         :c:macro:`!CONFIG_ARCH_HAS_PTE_SPECIAL`.
   ===================== ======================================== ===========

These fields describes the size, start and end of the VMA, and as such cannot be
modified without first being hidden from the reverse mapping since these fields
are used to locate VMAs within the reverse mapping interval trees.

.. table:: Core fields

   ============================ ======================================== =========================
   Field                        Description                              Write lock
   ============================ ======================================== =========================
   :c:member:`!vm_mm`           Containing mm_struct.                    None - written once on
                                                                         initial map.
   :c:member:`!vm_page_prot`    Architecture-specific page table         mmap write, VMA write.
                                protection bits determined from VMA
                                flags.
   :c:member:`!vm_flags`        Read-only access to VMA flags describing N/A
                                attributes of the VMA, in union with
                                private writable
                                :c:member:`!__vm_flags`.
   :c:member:`!__vm_flags`      Private, writable access to VMA flags    mmap write, VMA write.
                                field, updated by
                                :c:func:`!vm_flags_*` functions.
   :c:member:`!vm_file`         If the VMA is file-backed, points to a   None - written once on
                                struct file object describing the        initial map.
                                underlying file, if anonymous then
                                :c:macro:`!NULL`.
   :c:member:`!vm_ops`          If the VMA is file-backed, then either   None - Written once on
                                the driver or file-system provides a     initial map by
                                :c:struct:`!struct vm_operations_struct` :c:func:`!f_ops->mmap()`.
                                object describing callbacks to be
                                invoked on VMA lifetime events.
   :c:member:`!vm_private_data` A :c:member:`!void *` field for          Handled by driver.
                                driver-specific metadata.
   ============================ ======================================== =========================

These are the core fields which describe the MM the VMA belongs to and its attributes.

.. table:: Config-specific fields

   ================================= ===================== ======================================== ===============
   Field                             Configuration option  Description                              Write lock
   ================================= ===================== ======================================== ===============
   :c:member:`!anon_name`            CONFIG_ANON_VMA_NAME  A field for storing a                    mmap write,
                                                           :c:struct:`!struct anon_vma_name`        VMA write.
                                                           object providing a name for anonymous
                                                           mappings, or :c:macro:`!NULL` if none
                                                           is set or the VMA is file-backed. The
                                                           underlying object is reference counted
                                                           and can be shared across multiple VMAs
                                                           for scalability.
   :c:member:`!swap_readahead_info`  CONFIG_SWAP           Metadata used by the swap mechanism      mmap read,
                                                           to perform readahead. This field is      swap-specific
                                                           accessed atomically.                     lock.
   :c:member:`!vm_policy`            CONFIG_NUMA           :c:type:`!mempolicy` object which        mmap write,
                                                           describes the NUMA behaviour of the      VMA write.
                                                           VMA. The underlying object is reference
                                                           counted.
   :c:member:`!numab_state`          CONFIG_NUMA_BALANCING :c:type:`!vma_numab_state` object which  mmap read,
                                                           describes the current state of           numab-specific
                                                           NUMA balancing in relation to this VMA.  lock.
                                                           Updated under mmap read lock by
                                                           :c:func:`!task_numa_work`.
   :c:member:`!vm_userfaultfd_ctx`   CONFIG_USERFAULTFD    Userfaultfd context wrapper object of    mmap write,
                                                           type :c:type:`!vm_userfaultfd_ctx`,      VMA write.
                                                           either of zero size if userfaultfd is
                                                           disabled, or containing a pointer
                                                           to an underlying
                                                           :c:type:`!userfaultfd_ctx` object which
                                                           describes userfaultfd metadata.
   ================================= ===================== ======================================== ===============

These fields are present or not depending on whether the relevant kernel
configuration option is set.

.. table:: Reverse mapping fields

   =================================== ========================================= ============================
   Field                               Description                               Write lock
   =================================== ========================================= ============================
   :c:member:`!shared.rb`              A red/black tree node used, if the        mmap write, VMA write,
                                       mapping is file-backed, to place the VMA  i_mmap write.
                                       in the
                                       :c:member:`!struct address_space->i_mmap`
                                       red/black interval tree.
   :c:member:`!shared.rb_subtree_last` Metadata used for management of the       mmap write, VMA write,
                                       interval tree if the VMA is file-backed.  i_mmap write.
   :c:member:`!anon_vma_chain`         List of pointers to both forked/CoW’d     mmap read, anon_vma write.
                                       :c:type:`!anon_vma` objects and
                                       :c:member:`!vma->anon_vma` if it is
                                       non-:c:macro:`!NULL`.
   :c:member:`!anon_vma`               :c:type:`!anon_vma` object used by        When :c:macro:`NULL` and
                                       anonymous folios mapped exclusively to    setting non-:c:macro:`NULL`:
                                       this VMA. Initially set by                mmap read, page_table_lock.
                                       :c:func:`!anon_vma_prepare` serialised
                                       by the :c:macro:`!page_table_lock`. This  When non-:c:macro:`NULL` and
                                       is set as soon as any page is faulted in. setting :c:macro:`NULL`:
                                                                                 mmap write, VMA write,
                                                                                 anon_vma write.
   =================================== ========================================= ============================

These fields are used to both place the VMA within the reverse mapping, and for
anonymous mappings, to be able to access both related :c:struct:`!struct anon_vma` objects
and the :c:struct:`!struct anon_vma` in which folios mapped exclusively to this VMA should
reside.

.. note:: If a file-backed mapping is mapped with :c:macro:`!MAP_PRIVATE` set
          then it can be in both the :c:type:`!anon_vma` and :c:type:`!i_mmap`
          trees at the same time, so all of these fields might be utilised at
          once.

Page-table model과 네 가지 operation

279-357

Page table은 여러 단계 table을 통해 virtual address를 physical address에 mapping합니다. 각 non-leaf entry는 flag와 함께 다음 level table의 physical address를 담습니다. Leaf entry는 physical data page 주소 또는 swap entry, migration entry, 그 밖의 special marker를 담습니다. 각 page 안의 offset은 virtual address 자체가 제공합니다.

Linux는 PGD, P4D, PUD, PMD, PTE의 5단계로 나눕니다. Huge page가 한두 단계를 없앨 수 있지만 그 경우에도 보통 leaf level을 PTE level이라고 부릅니다. 5단계보다 적은 architecture에서는 빠진 level의 함수를 stub 처리하는 `folding`으로 항상 5단계인 것처럼 다룹니다. Compiler는 실제로 없는 단계의 code를 제거할 수 있습니다.

  • `Traversing`: Page table을 읽어 순회합니다. VMA를 stable하게 유지하는 lock 하나면 충분합니다. `gup_fast`처럼 이 요구도 없애는 lockless variant가 있습니다. Non-VMA 영역은 별도로 다룹니다.
  • `Installing`: 새 mapping을 만들거나 기존 mapping의 identity를 바꾸는 수정입니다. Rmap lock이 아니라 mmap 또는 VMA lock으로 VMA를 stable하게 유지해야 합니다.
  • `Zapping/unmapping`: Page table 자체는 남기고 leaf mapping만 clear합니다. File truncation, `madvise`의 `MADV_DONTNEED` 등에 흔히 사용하며 `unmap_mapping_range`, `unmap_mapping_pages` 등이 수행합니다. VMA를 stable하게만 유지하면 됩니다.
  • `Freeing`: 보통 `free_pgtables`로 userspace process에서 page table 자체를 제거합니다. Range를 이미 zap했고 추가 fault나 수정이 없도록 막았다고 가정한 채 existing leaf entry를 무시하고 모든 table을 free하므로 매우 조심해야 합니다.

Reclaim 또는 migration을 위한 mapping 수정은 mapping identity를 근본적으로 바꾸지 않으므로 zapping처럼 rmap lock 아래에서 수행합니다.

Traversal과 zapping은 mmap, VMA, rmap lock 중 하나로 VMA를 stable하게 유지하면 수행할 수 있습니다. Write를 수행하는 내부 kernel operation은 serialize를 위해 page-table lock도 얻습니다. Zap 중 빈 PTE table은 RCU 아래에서 free하지만 이 사실은 zapping의 앞선 lock 요구를 바꾸지 않습니다.

Entry installation에는 mmap 또는 VMA lock이 필요합니다. Page-table freeing은 특수한 internal operation입니다. Free하려는 table이 mapping하는 range를 포함하는 VMA에 reverse mapping으로 접근할 수 없어야 합니다. `free_pgtables`가 관련 VMA를 rmap에서 제거하지만, 다른 접근 가능한 VMA가 해당 range와 겹쳐서도 안 됩니다.

Page tables
-----------

We won't speak exhaustively on the subject but broadly speaking, page tables map
virtual addresses to physical ones through a series of page tables, each of
which contain entries with physical addresses for the next page table level
(along with flags), and at the leaf level the physical addresses of the
underlying physical data pages or a special entry such as a swap entry,
migration entry or other special marker. Offsets into these pages are provided
by the virtual address itself.

In Linux these are divided into five levels - PGD, P4D, PUD, PMD and PTE. Huge
pages might eliminate one or two of these levels, but when this is the case we
typically refer to the leaf level as the PTE level regardless.

.. note:: In instances where the architecture supports fewer page tables than
          five the kernel cleverly 'folds' page table levels, that is stubbing
          out functions related to the skipped levels. This allows us to
          conceptually act as if there were always five levels, even if the
          compiler might, in practice, eliminate any code relating to missing
          ones.

There are four key operations typically performed on page tables:

1. **Traversing** page tables - Simply reading page tables in order to traverse
   them. This only requires that the VMA is kept stable, so a lock which
   establishes this suffices for traversal (there are also lockless variants
   which eliminate even this requirement, such as :c:func:`!gup_fast`). There is
   also a special case of page table traversal for non-VMA regions which we
   consider separately below.
2. **Installing** page table mappings - Whether creating a new mapping or
   modifying an existing one in such a way as to change its identity. This
   requires that the VMA is kept stable via an mmap or VMA lock (explicitly not
   rmap locks).
3. **Zapping/unmapping** page table entries - This is what the kernel calls
   clearing page table mappings at the leaf level only, whilst leaving all page
   tables in place. This is a very common operation in the kernel performed on
   file truncation, the :c:macro:`!MADV_DONTNEED` operation via
   :c:func:`!madvise`, and others. This is performed by a number of functions
   including :c:func:`!unmap_mapping_range` and :c:func:`!unmap_mapping_pages`.
   The VMA need only be kept stable for this operation.
4. **Freeing** page tables - When finally the kernel removes page tables from a
   userland process (typically via :c:func:`!free_pgtables`) extreme care must
   be taken to ensure this is done safely, as this logic finally frees all page
   tables in the specified range, ignoring existing leaf entries (it assumes the
   caller has both zapped the range and prevented any further faults or
   modifications within it).

.. note:: Modifying mappings for reclaim or migration is performed under rmap
          lock as it, like zapping, does not fundamentally modify the identity
          of what is being mapped.

**Traversing** and **zapping** ranges can be performed holding any one of the
locks described in the terminology section above - that is the mmap lock, the
VMA lock or either of the reverse mapping locks.

That is - as long as you keep the relevant VMA **stable** - you are good to go
ahead and perform these operations on page tables (though internally, kernel
operations that perform writes also acquire internal page table locks to
serialise - see the page table implementation detail section for more details).

.. note:: We free empty PTE tables on zap under the RCU lock - this does not
          change the aforementioned locking requirements around zapping.

When **installing** page table entries, the mmap or VMA lock must be held to
keep the VMA stable. We explore why this is in the page table locking details
section below.

**Freeing** page tables is an entirely internal memory management operation and
has special requirements (see the page freeing section below for more details).

.. warning:: When **freeing** page tables, it must not be possible for VMAs
             containing the ranges those page tables map to be accessible via
             the reverse mapping.

             The :c:func:`!free_pgtables` function removes the relevant VMAs
             from the reverse mappings, but no other VMAs can be permitted to be
             accessible and span the specified range.

Non-VMA traversal과 lock ordering

358-491

VMA가 나타내지 않는 page table도 순회할 수 있습니다. Kernel page-table mapping은 이를 만든 subsystem이 자체 lock으로 관리하므로 앞의 VMA lock 규칙이 적용되지 않습니다. 예를 들어 vmalloc은 page table 생성과 해제에 자체 lock set을 사용합니다.

편의를 위해 `walk_kernel_page_table_range`를 제공하며, kernel `mm_struct` instance인 `init_mm`의 mmap lock으로 synchronize합니다. Exclusive access가 필요하면 write lock을, 아니면 read lock을 사용하며 최소 read lock 획득을 assert합니다. Vmalloc과 memory hotplug 외에는 kernel page table을 자주 해제하지 않으므로 대체로 충분하지만 caller가 필요한 추가 lock을 미리 얻어야 합니다.

`walk_page_range_debug`는 userspace range의 non-VMA 영역을 순회하는 매우 이례적인 경우를 지원합니다. 유일한 사용자는 `mm/ptdump.c`의 일반 page-table dump logic으로, architecture-specific일 수 있고 VMA backing이 없는 mapping까지 debug 목적으로 노출합니다.

`munmap`은 mmap write lock 아래에서 VMA를 detach한 뒤 downgraded mmap read lock 아래에서 page table을 해제합니다. Debug traversal이 이 과정과 race할 수 있으므로 mmap write lock이 필요합니다.

여러 lock을 함께 쓸 수 있어 lock inversion을 피하려면 획득·해제 순서가 중요합니다. Thread 1이 A를 들고 B를 기다리는 동안 thread 2가 B를 들고 A를 기다리면 mutual deadlock입니다. 같은 순서로 lock을 얻었다면 한쪽이 다른 쪽 완료를 기다려 deadlock을 피할 수 있습니다.

`mm/rmap.c`가 제시하는 주 lock-order chain은 다음 순서입니다.

inode->i_rwsem
  mm->mmap_lock
    mapping->invalidate_lock
      folio_lock
        hugetlbfs_i_mmap_rwsem_key
          vma_start_write
            mapping->i_mmap_rwsem
              anon_vma->rwsem
                mm->page_table_lock or pte_lock
                  swap_lock
                    mmlist_lock / mapping->private_lock / inode->i_lock / bdi.wb->list_lock
                      i_pages lock / sb_lock / lruvec->lru_lock

`mm/filemap.c`에는 filesystem-specific lock-order 조합이 별도로 나옵니다. `i_mmap_rwsem → private_lock → swap_lock → i_pages`, `i_rwsem → invalidate_lock → i_mmap_rwsem`, `mmap_lock → i_mmap_rwsem → page_table_lock 또는 pte_lock → i_pages`, `mmap_lock → invalidate_lock → lock_page`, `i_rwsem → mmap_lock`, `bdi->wb.list_lock → sb_lock 또는 i_pages`, `i_mmap_rwsem → anon_vma.lock`, `anon_vma.lock → page_table_lock 또는 pte_lock` 순서를 포함합니다.

`page_table_lock` 또는 `pte_lock` 아래에서는 `swap_lock`, `private_lock`, `i_pages`, `lruvec->lru_lock`, `bdi.wb->list_lock`, `inode->i_lock`을 여러 unmap·dirty path에서 얻을 수 있습니다. 문서 작성 뒤 comment가 바뀌었을 수 있으므로 현재 source comment 상태를 확인해야 합니다.

Traversing non-VMA page tables
------------------------------

We've focused above on traversal of page tables belonging to VMAs. It is also
possible to traverse page tables which are not represented by VMAs.

Kernel page table mappings themselves are generally managed but whatever part of
the kernel established them and the aforementioned locking rules do not apply -
for instance vmalloc has its own set of locks which are utilised for
establishing and tearing down page its page tables.

However, for convenience we provide the :c:func:`!walk_kernel_page_table_range`
function which is synchronised via the mmap lock on the :c:macro:`!init_mm`
kernel instantiation of the :c:struct:`!struct mm_struct` metadata object.

If an operation requires exclusive access, a write lock is used, but if not, a
read lock suffices - we assert only that at least a read lock has been acquired.

Since, aside from vmalloc and memory hot plug, kernel page tables are not torn
down all that often - this usually suffices, however any caller of this
functionality must ensure that any additionally required locks are acquired in
advance.

We also permit a truly unusual case is the traversal of non-VMA ranges in
**userland** ranges, as provided for by :c:func:`!walk_page_range_debug`.

This has only one user - the general page table dumping logic (implemented in
:c:macro:`!mm/ptdump.c`) - which seeks to expose all mappings for debug purposes
even if they are highly unusual (possibly architecture-specific) and are not
backed by a VMA.

We must take great care in this case, as the :c:func:`!munmap` implementation
detaches VMAs under an mmap write lock before tearing down page tables under a
downgraded mmap read lock.

This means such an operation could race with this, and thus an mmap **write**
lock is required.

Lock ordering
-------------

As we have multiple locks across the kernel which may or may not be taken at the
same time as explicit mm or VMA locks, we have to be wary of lock inversion, and
the **order** in which locks are acquired and released becomes very important.

.. note:: Lock inversion occurs when two threads need to acquire multiple locks,
   but in doing so inadvertently cause a mutual deadlock.

   For example, consider thread 1 which holds lock A and tries to acquire lock B,
   while thread 2 holds lock B and tries to acquire lock A.

   Both threads are now deadlocked on each other. However, had they attempted to
   acquire locks in the same order, one would have waited for the other to
   complete its work and no deadlock would have occurred.

The opening comment in :c:macro:`!mm/rmap.c` describes in detail the required
ordering of locks within memory management code:

.. code-block::

  inode->i_rwsem        (while writing or truncating, not reading or faulting)
    mm->mmap_lock
      mapping->invalidate_lock (in filemap_fault)
        folio_lock
          hugetlbfs_i_mmap_rwsem_key (in huge_pmd_share, see hugetlbfs below)
            vma_start_write
              mapping->i_mmap_rwsem
                anon_vma->rwsem
                  mm->page_table_lock or pte_lock
                    swap_lock (in swap_duplicate, swap_info_get)
                      mmlist_lock (in mmput, drain_mmlist and others)
                      mapping->private_lock (in block_dirty_folio)
                          i_pages lock (widely used)
                            lruvec->lru_lock (in folio_lruvec_lock_irq)
                      inode->i_lock (in set_page_dirty's __mark_inode_dirty)
                      bdi.wb->list_lock (in set_page_dirty's __mark_inode_dirty)
                        sb_lock (within inode_lock in fs/fs-writeback.c)
                        i_pages lock (widely used, in set_page_dirty,
                                  in arch-dependent flush_dcache_mmap_lock,
                                  within bdi.wb->list_lock in __sync_single_inode)

There is also a file-system specific lock ordering comment located at the top of
:c:macro:`!mm/filemap.c`:

.. code-block::

  ->i_mmap_rwsem                        (truncate_pagecache)
    ->private_lock                      (__free_pte->block_dirty_folio)
      ->swap_lock                       (exclusive_swap_page, others)
        ->i_pages lock

  ->i_rwsem
    ->invalidate_lock                   (acquired by fs in truncate path)
      ->i_mmap_rwsem                    (truncate->unmap_mapping_range)

  ->mmap_lock
    ->i_mmap_rwsem
      ->page_table_lock or pte_lock     (various, mainly in memory.c)
        ->i_pages lock                  (arch-dependent flush_dcache_mmap_lock)

  ->mmap_lock
    ->invalidate_lock                   (filemap_fault)
      ->lock_page                       (filemap_fault, access_process_vm)

  ->i_rwsem                             (generic_perform_write)
    ->mmap_lock                         (fault_in_readable->do_page_fault)

  bdi->wb.list_lock
    sb_lock                             (fs/fs-writeback.c)
    ->i_pages lock                      (__sync_single_inode)

  ->i_mmap_rwsem
    ->anon_vma.lock                     (vma_merge)

  ->anon_vma.lock
    ->page_table_lock or pte_lock       (anon_vma_prepare and various)

  ->page_table_lock or pte_lock
    ->swap_lock                         (try_to_unmap_one)
    ->private_lock                      (try_to_unmap_one)
    ->i_pages lock                      (try_to_unmap_one)
    ->lruvec->lru_lock                  (follow_page_mask->mark_page_accessed)
    ->lruvec->lru_lock                  (check_pte_range->folio_isolate_lru)
    ->private_lock                      (folio_remove_rmap_pte->set_page_dirty)
    ->i_pages lock                      (folio_remove_rmap_pte->set_page_dirty)
    bdi.wb->list_lock                   (folio_remove_rmap_pte->set_page_dirty)
    ->inode->i_lock                     (folio_remove_rmap_pte->set_page_dirty)
    bdi.wb->list_lock                   (zap_pte_range->set_page_dirty)
    ->inode->i_lock                     (zap_pte_range->set_page_dirty)
    ->private_lock                      (zap_pte_range->block_dirty_folio)

Please check the current state of these comments which may have changed since
the time of writing of this document.

Page-table locking 규칙과 atomicity

492-632

PTE-level page table의 locking 규칙은 다른 level과 매우 다릅니다. 이 section은 VMA가 포함하는 page table만 다룹니다.

  • `Higher-level page-table lock`: PGD, P4D, PUD를 수정할 때 process-address-space 단위 `mm->page_table_lock`을 사용합니다.
  • `Fine-grained page-table lock`: PMD와 PTE는 page-table folio 안에 둔 lock을 쓰거나 `ALLOC_SPLIT_PTLOCKS`가 set되면 별도로 할당해 folio가 가리키게 합니다. PMD spinlock은 `pmd_lock`, PTE는 32bit system의 high memory에 mapping한 뒤 `pte_offset_map_lock`으로 조심스럽게 lock합니다.

이 lock은 각 level과 상호작용하는 최소 요구입니다. Traversal에서는 아무 page-table lock도 얻지 않을 수 있습니다. 다만 PTE level에서는 적어도 RCU로 concurrent deletion을 막고 high memory의 table을 mapping해야 합니다. Entry read에 추가 조치가 필요한지는 architecture에 따라 다릅니다.

  • Page-table entry를 바꿀 때는 `free_pgtables`처럼 concurrent access가 없다고 안전하게 가정할 수 있는 경우를 제외하고 해당 table의 page-table lock을 반드시 가져야 합니다.
  • Entry read와 write는 적절히 atomic해야 합니다.
  • 비어 있던 entry를 populate하려면 read 또는 write mode의 mmap 또는 VMA lock이 필요합니다. Rmap lock만으로 수행하면 위험합니다.
  • Zapping은 mmap, VMA, rmap lock 중 하나로 VMA를 stable하게 유지한 채 수행할 수 있습니다.

VMA unmap 때 `vms_clear_ptes`에는 `unmap_vmas`의 zap과 `free_pgtables`의 table free 사이에 VMA가 rmap tree에 여전히 보이는 window가 있습니다. `free_pgtables`는 zap이 끝났다고 가정해 PTE와 range의 다른 table을 무조건 제거합니다. 이 사이에 새 PTE를 install하면 memory leak과 예기치 않은 위험한 동작이 생길 수 있습니다.

PTE-level table은 32bit architecture에서 high memory에 있을 수 있어 kernel memory에 mapping해야 합니다. Empty PTE table은 mmap 또는 rmap read lock과 PTE·PMD lock을 함께 든 채 unlink하고 RCU-free할 수 있습니다. `MADV_COLLAPSE`를 처리하는 `retract_page_tables`가 그 예입니다.

따라서 PTE-level table 접근에는 최소 RCU read lock이 필요합니다. 그러나 이는 detached되어 RCU free 예정인 table의 empty PTE를 보는 동시에 같은 위치에 새 table이 설치돼 채워지는 race를 허용할 수 있는 reader에만 충분합니다. Writer는 보통 PTE lock을 얻고 PMD가 같은 PTE table을 가리키는지 revalidate해야 합니다. 동일 table인지 중요하지 않다면 PMD lock을 얻고 PMD entry 내용이 요구를 충족하는지 다시 확인할 수 있습니다.

Stability 요구에 따라 `pte_offset_map_lock` 또는 `pte_offset_map` helper를 사용합니다. 필요하면 kernel memory에 table을 mapping하고 RCU lock을 얻으며 variant에 따라 PTE lock lookup 또는 획득도 수행합니다. `__pte_offset_map_lock` comment를 참조하십시오.

Page-table lock과 무관하게 MMU hardware는 accessed·dirty bit를 concurrent하게 갱신합니다. Stable VMA를 둔 parallel traversal과 VMA 안정화 없이 lockless하게 읽는 GUP-fast도 동시에 동작합니다.

Stable VMA 아래 traversal read가 정확히 한 번만 이뤄져야 하는지는 architecture에 따라 다르며 x86-64는 특별한 조치가 필요 없습니다. 그러나 write하거나 read 결과가 write 여부를 결정하는 `__pud_install` 같은 경우에는 entry를 정확히 한 번 가져와야 합니다. Page-table lock이 완전한 exclusive access를 준다고 가정할 수 없습니다.

Read에서는 compiler load 재배치를 막기 위해 `pgdp_get`, `p4dp_get`, `pudp_get`, `pmdp_get`, `ptep_get`이라는 `pXXp_get` 함수를 사용합니다. 각 함수는 `READ_ONCE`로 entry를 한 번만 읽게 합니다.

기존 entry를 조작하면서 저장된 이전 data가 중요하면 `ptep_get_and_clear` 같은 hardware atomic operation이 필요합니다. VMA stability에 의존하지 않는 GUP-fast와 `gup_fast_pte_range` 같은 handler는 `ptep_get_lockless` 및 higher-level 대응 함수를 사용해 매우 조심스럽게 entry와 상호작용해야 합니다.

Write는 `set_pgd`, `set_p4d`, `set_pud`, `set_pmd`, `set_pte` 같은 `set_pXX` 함수로 atomic하게 수행합니다. Clear도 `pgd_clear`, `p4d_clear`, `pud_clear`, `pmd_clear`, `pte_clear` 같은 `pXX_clear` 함수로 atomic하게 수행해야 합니다.

------------------------------
Locking Implementation Details
------------------------------

.. warning:: Locking rules for PTE-level page tables are very different from
             locking rules for page tables at other levels.

Page table locking details
--------------------------

.. note:: This section explores page table locking requirements for page tables
          encompassed by a VMA. See the above section on non-VMA page table
          traversal for details on how we handle that case.

In addition to the locks described in the terminology section above, we have
additional locks dedicated to page tables:

* **Higher level page table locks** - Higher level page tables, that is PGD, P4D
  and PUD each make use of the process address space granularity
  :c:member:`!mm->page_table_lock` lock when modified.

* **Fine-grained page table locks** - PMDs and PTEs each have fine-grained locks
  either kept within the folios describing the page tables or allocated
  separated and pointed at by the folios if :c:macro:`!ALLOC_SPLIT_PTLOCKS` is
  set. The PMD spin lock is obtained via :c:func:`!pmd_lock`, however PTEs are
  mapped into higher memory (if a 32-bit system) and carefully locked via
  :c:func:`!pte_offset_map_lock`.

These locks represent the minimum required to interact with each page table
level, but there are further requirements.

Importantly, note that on a **traversal** of page tables, sometimes no such
locks are taken. However, at the PTE level, at least concurrent page table
deletion must be prevented (using RCU) and the page table must be mapped into
high memory, see below.

Whether care is taken on reading the page table entries depends on the
architecture, see the section on atomicity below.

Locking rules
^^^^^^^^^^^^^

We establish basic locking rules when interacting with page tables:

* When changing a page table entry the page table lock for that page table
  **must** be held, except if you can safely assume nobody can access the page
  tables concurrently (such as on invocation of :c:func:`!free_pgtables`).
* Reads from and writes to page table entries must be *appropriately*
  atomic. See the section on atomicity below for details.
* Populating previously empty entries requires that the mmap or VMA locks are
  held (read or write), doing so with only rmap locks would be dangerous (see
  the warning below).
* As mentioned previously, zapping can be performed while simply keeping the VMA
  stable, that is holding any one of the mmap, VMA or rmap locks.

.. warning:: Populating previously empty entries is dangerous as, when unmapping
             VMAs, :c:func:`!vms_clear_ptes` has a window of time between
             zapping (via :c:func:`!unmap_vmas`) and freeing page tables (via
             :c:func:`!free_pgtables`), where the VMA is still visible in the
             rmap tree. :c:func:`!free_pgtables` assumes that the zap has
             already been performed and removes PTEs unconditionally (along with
             all other page tables in the freed range), so installing new PTE
             entries could leak memory and also cause other unexpected and
             dangerous behaviour.

There are additional rules applicable when moving page tables, which we discuss
in the section on this topic below.

PTE-level page tables are different from page tables at other levels, and there
are extra requirements for accessing them:

* On 32-bit architectures, they may be in high memory (meaning they need to be
  mapped into kernel memory to be accessible).
* When empty, they can be unlinked and RCU-freed while holding an mmap lock or
  rmap lock for reading in combination with the PTE and PMD page table locks.
  In particular, this happens in :c:func:`!retract_page_tables` when handling
  :c:macro:`!MADV_COLLAPSE`.
  So accessing PTE-level page tables requires at least holding an RCU read lock;
  but that only suffices for readers that can tolerate racing with concurrent
  page table updates such that an empty PTE is observed (in a page table that
  has actually already been detached and marked for RCU freeing) while another
  new page table has been installed in the same location and filled with
  entries. Writers normally need to take the PTE lock and revalidate that the
  PMD entry still refers to the same PTE-level page table.
  If the writer does not care whether it is the same PTE-level page table, it
  can take the PMD lock and revalidate that the contents of pmd entry still meet
  the requirements. In particular, this also happens in :c:func:`!retract_page_tables`
  when handling :c:macro:`!MADV_COLLAPSE`.

To access PTE-level page tables, a helper like :c:func:`!pte_offset_map_lock` or
:c:func:`!pte_offset_map` can be used depending on stability requirements.
These map the page table into kernel memory if required, take the RCU lock, and
depending on variant, may also look up or acquire the PTE lock.
See the comment on :c:func:`!__pte_offset_map_lock`.

Atomicity
^^^^^^^^^

Regardless of page table locks, the MMU hardware concurrently updates accessed
and dirty bits (perhaps more, depending on architecture). Additionally, page
table traversal operations in parallel (though holding the VMA stable) and
functionality like GUP-fast locklessly traverses (that is reads) page tables,
without even keeping the VMA stable at all.

When performing a page table traversal and keeping the VMA stable, whether a
read must be performed once and only once or not depends on the architecture
(for instance x86-64 does not require any special precautions).

If a write is being performed, or if a read informs whether a write takes place
(on an installation of a page table entry say, for instance in
:c:func:`!__pud_install`), special care must always be taken. In these cases we
can never assume that page table locks give us entirely exclusive access, and
must retrieve page table entries once and only once.

If we are reading page table entries, then we need only ensure that the compiler
does not rearrange our loads. This is achieved via :c:func:`!pXXp_get`
functions - :c:func:`!pgdp_get`, :c:func:`!p4dp_get`, :c:func:`!pudp_get`,
:c:func:`!pmdp_get`, and :c:func:`!ptep_get`.

Each of these uses :c:func:`!READ_ONCE` to guarantee that the compiler reads
the page table entry only once.

However, if we wish to manipulate an existing page table entry and care about
the previously stored data, we must go further and use an hardware atomic
operation as, for example, in :c:func:`!ptep_get_and_clear`.

Equally, operations that do not rely on the VMA being held stable, such as
GUP-fast (see :c:func:`!gup_fast` and its various page table level handlers like
:c:func:`!gup_fast_pte_range`), must very carefully interact with page table
entries, using functions such as :c:func:`!ptep_get_lockless` and equivalent for
higher level page table levels.

Writes to page table entries must also be appropriately atomic, as established
by :c:func:`!set_pXX` functions - :c:func:`!set_pgd`, :c:func:`!set_p4d`,
:c:func:`!set_pud`, :c:func:`!set_pmd`, and :c:func:`!set_pte`.

Equally functions which clear page table entries must be appropriately atomic,
as in :c:func:`!pXX_clear` functions - :c:func:`!pgd_clear`,
:c:func:`!p4d_clear`, :c:func:`!pud_clear`, :c:func:`!pmd_clear`, and
:c:func:`!pte_clear`.

Page-table installation

633-696

Page-table installation은 read 또는 write mode의 mmap 또는 VMA lock으로 VMA를 명시적으로 stable하게 유지한 상태에서 수행합니다.

P4D, PUD, PMD를 할당하고 상위 PGD, P4D, PUD에 대응 entry를 set할 때 `mm->page_table_lock`을 가져야 합니다. `__p4d_alloc`, `__pud_alloc`, `__pmd_alloc`이 각각 이 lock을 얻습니다. `__pmd_alloc`은 `pud_lock`과 `pud_lockptr`을 호출하지만 문서 작성 시점에는 결국 `mm->page_table_lock`을 참조합니다.

PTE allocation은 `mm->page_table_lock`을 사용하거나, `USE_SPLIT_PMD_PTLOCKS`가 정의되면 PMD physical-page metadata의 `struct ptdesc`에 embedded된 lock을 사용합니다. 이 lock은 `pmd_lock`이 호출한 `pmd_ptdesc`를 거쳐 최종적으로 `__pte_alloc`에서 얻습니다.

PTE 내용을 수정하려면 stable하고 exclusive한 access를 위해 PTE page-table lock을 얻어야 합니다. `pte_offset_map_lock`이 PTE가 아래에서 바뀌지 않았는지 확인하고, physical PTE page의 `struct ptdesc`에 든 PTE-granularity spinlock을 `pte_lockptr`로 얻습니다. `pte_unmap_unlock`으로 놓아야 합니다. Stable PTE를 이미 보유한 경우의 `pte_offset_map_rw_nolock` 같은 variant도 있습니다.

Range data를 수정할 때는 보통 필요한 higher table만 할당하고 lock으로 race와 overwrite를 막은 뒤 page fault 또는 zap 요구에 따라 PTE level data를 set 또는 clear합니다.

새 mapping 설치를 위한 전형적인 pattern은 상위 table entry가 empty인지 optimistic하게 보고, empty일 때만 page-table lock을 얻어 그 사이 allocation됐는지 다시 확인하는 것입니다. `__pud_alloc`이 예입니다. 필요한 때만 lock을 얻어 순회할 수 있습니다.

Leaf PTE에서는 PMD lock과 PTE lock이 분리되어 있고 THP collapse가 PMD entry와 PTE를 아래에서 없앨 수 있어 이 pattern만 믿을 수 없습니다. `__pte_offset_map_lock`은 lockless하게 PMD entry를 가져와 예상값인지 확인하고 PTE-specific lock을 얻은 뒤 PMD를 다시 확인합니다. THP collapse는 두 page lock을 모두 필요로 하므로 PTE lock을 든 동안 막을 수 있습니다. 이 방식으로 entry를 설치하면 write mutual exclusion을 보장합니다.

Page table installation
^^^^^^^^^^^^^^^^^^^^^^^

Page table installation is performed with the VMA held stable explicitly by an
mmap or VMA lock in read or write mode (see the warning in the locking rules
section for details as to why).

When allocating a P4D, PUD or PMD and setting the relevant entry in the above
PGD, P4D or PUD, the :c:member:`!mm->page_table_lock` must be held. This is
acquired in :c:func:`!__p4d_alloc`, :c:func:`!__pud_alloc` and
:c:func:`!__pmd_alloc` respectively.

.. note:: :c:func:`!__pmd_alloc` actually invokes :c:func:`!pud_lock` and
   :c:func:`!pud_lockptr` in turn, however at the time of writing it ultimately
   references the :c:member:`!mm->page_table_lock`.

Allocating a PTE will either use the :c:member:`!mm->page_table_lock` or, if
:c:macro:`!USE_SPLIT_PMD_PTLOCKS` is defined, a lock embedded in the PMD
physical page metadata in the form of a :c:struct:`!struct ptdesc`, acquired by
:c:func:`!pmd_ptdesc` called from :c:func:`!pmd_lock` and ultimately
:c:func:`!__pte_alloc`.

Finally, modifying the contents of the PTE requires special treatment, as the
PTE page table lock must be acquired whenever we want stable and exclusive
access to entries contained within a PTE, especially when we wish to modify
them.

This is performed via :c:func:`!pte_offset_map_lock` which carefully checks to
ensure that the PTE hasn't changed from under us, ultimately invoking
:c:func:`!pte_lockptr` to obtain a spin lock at PTE granularity contained within
the :c:struct:`!struct ptdesc` associated with the physical PTE page. The lock
must be released via :c:func:`!pte_unmap_unlock`.

.. note:: There are some variants on this, such as
   :c:func:`!pte_offset_map_rw_nolock` when we know we hold the PTE stable but
   for brevity we do not explore this.  See the comment for
   :c:func:`!__pte_offset_map_lock` for more details.

When modifying data in ranges we typically only wish to allocate higher page
tables as necessary, using these locks to avoid races or overwriting anything,
and set/clear data at the PTE level as required (for instance when page faulting
or zapping).

A typical pattern taken when traversing page table entries to install a new
mapping is to optimistically determine whether the page table entry in the table
above is empty, if so, only then acquiring the page table lock and checking
again to see if it was allocated underneath us.

This allows for a traversal with page table locks only being taken when
required. An example of this is :c:func:`!__pud_alloc`.

At the leaf page table, that is the PTE, we can't entirely rely on this pattern
as we have separate PMD and PTE locks and a THP collapse for instance might have
eliminated the PMD entry as well as the PTE from under us.

This is why :c:func:`!__pte_offset_map_lock` locklessly retrieves the PMD entry
for the PTE, carefully checking it is as expected, before acquiring the
PTE-specific lock, and then *again* checking that the PMD entry is as expected.

If a THP collapse (or similar) were to occur then the lock on both pages would
be acquired, so we can ensure this is prevented while the PTE lock is held.

Installing entries this way ensures mutual exclusion on write.

Page-table freeing

697-732

Page table 자체를 해제할 때는 제거 대상 table을 concurrent task가 순회하거나 참조할 방법이 전혀 없어야 합니다.

Mmap write lock과 VMA lock만으로는 충분하지 않습니다. 이 lock은 racing fault와 rmap operation을 막지만 file-backed mapping은 `struct address_space->i_mmap_rwsem`만으로 truncate될 수 있습니다.

따라서 `struct anon_vma->rb_root` 또는 `struct address_space->i_mmap` interval tree를 통해 reverse mapping으로 접근할 수 있는 VMA의 page table은 해제하면 안 됩니다.

보통 `free_pgtables`가 수행하며, `mm_wr_locked` parameter가 나타내듯 mmap write lock을 얻었거나 VMA가 이미 unreachable하다고 가정합니다. VMA를 모든 reverse mapping에서 조심스럽게 제거하고, 새 VMA가 겹치거나 해제 range 주소에 접근할 route가 남지 않아야 합니다.

또한 zap이 이미 끝났고 zap과 `free_pgtables` 사이에 추가 entry를 설치할 수 없도록 조치했다고 가정합니다. 그러므로 `pgd_clear`, `p4d_clear`, `pud_clear`, `pmd_clear`는 page-table lock 없이 entry를 clear합니다.

`retract_page_tables`처럼 leaf table만 상위 table과 독립적으로 해제할 수는 있습니다. 이 경우 i_mmap read lock, PMD와 PTE page-table lock 아래에서 수행하므로 같은 수준의 전체 조치는 필요하지 않습니다.

Page table freeing
^^^^^^^^^^^^^^^^^^

Tearing down page tables themselves is something that requires significant
care. There must be no way that page tables designated for removal can be
traversed or referenced by concurrent tasks.

It is insufficient to simply hold an mmap write lock and VMA lock (which will
prevent racing faults, and rmap operations), as a file-backed mapping can be
truncated under the :c:struct:`!struct address_space->i_mmap_rwsem` alone.

As a result, no VMA which can be accessed via the reverse mapping (either
through the :c:struct:`!struct anon_vma->rb_root` or the :c:member:`!struct
address_space->i_mmap` interval trees) can have its page tables torn down.

The operation is typically performed via :c:func:`!free_pgtables`, which assumes
either the mmap write lock has been taken (as specified by its
:c:member:`!mm_wr_locked` parameter), or that the VMA is already unreachable.

It carefully removes the VMA from all reverse mappings, however it's important
that no new ones overlap these or any route remain to permit access to addresses
within the range whose page tables are being torn down.

Additionally, it assumes that a zap has already been performed and steps have
been taken to ensure that no further page table entries can be installed between
the zap and the invocation of :c:func:`!free_pgtables`.

Since it is assumed that all such steps have been taken, page table entries are
cleared without page table locks (in the :c:func:`!pgd_clear`, :c:func:`!p4d_clear`,
:c:func:`!pud_clear`, and :c:func:`!pmd_clear` functions.

.. note:: It is possible for leaf page tables to be torn down independent of
          the page tables above it as is done by
          :c:func:`!retract_page_tables`, which is performed under the i_mmap
          read lock, PMD, and PTE page table locks, without this level of care.

Page-table moving

733-746

일부 함수는 PMD보다 높은 PUD, P4D, PGD page table을 조작합니다. 대표적으로 `mremap`은 higher-level page table을 이동할 수 있습니다.

이 경우 mmap lock, VMA lock, 관련 rmap lock을 모두 얻어야 합니다. `mremap` 구현에서 `move_page_tables`가 최종 호출하는 `take_rmap_locks`와 `drop_rmap_locks`가 rmap 쪽 lock 획득과 해제를 수행합니다.

Page table moving
^^^^^^^^^^^^^^^^^

Some functions manipulate page table levels above PMD (that is PUD, P4D and PGD
page tables). Most notable of these is :c:func:`!mremap`, which is capable of
moving higher level page tables.

In these instances, it is required that **all** locks are taken, that is
the mmap lock, the VMA lock and the relevant rmap locks.

You can observe this in the :c:func:`!mremap` implementation in the functions
:c:func:`!take_rmap_locks` and :c:func:`!drop_rmap_locks` which perform the rmap
side of lock acquisition, invoked ultimately by :c:func:`!move_page_tables`.

VMA lock 내부 동작

747-856

VMA read locking은 완전히 optimistic합니다. Lock이 contended되거나 경쟁 write가 시작되면 read lock을 얻지 않습니다.

`lock_vma_under_rcu`는 먼저 `rcu_read_lock`으로 RCU critical section에서 VMA를 lookup하고 `vma_start_read`로 VMA lock을 시도한 뒤 `rcu_read_unlock`으로 RCU lock을 놓습니다. Caller가 mmap read lock을 이미 가진 경우 `vma_start_read_locked`와 nested variant를 쓸 수 있습니다. Contention으로 실패하지 않지만 다른 이유의 실패는 return value로 검사해야 합니다.

VMA read lock은 유지되는 동안 `vma.vm_refcnt`를 증가시킵니다. `lock_vma_under_rcu` caller는 `vma_end_read`로 이를 내려야 합니다.

VMA 수정 전에는 `vma_start_write`로 write lock을 얻으며 read와 달리 항상 획득합니다. 유지 시간 내내 mmap write lock이 필요하고, mmap write lock을 놓거나 downgrade하면 VMA write lock도 놓이므로 `vma_end_write`는 없습니다. Write lock을 얻는 동안 reader가 writer 존재를 감지하도록 `vma.vm_refcnt`를 잠시 수정하고 serialization sequence number를 갱신한 뒤 복원합니다.

VMA lock은 contention이 심한 mmap lock 사용을 피하는 가벼운 mechanism입니다. Containing `mm_struct`와 VMA의 reference counter 및 sequence number 조합으로 구현합니다.

`vma_start_read`는 optimistic하게 read lock을 시도하고 실패하면 false를 반환합니다. 작업 후 `vma_end_read`로 놓습니다. 호출 전 `rcu_read_lock`이 필요하지만 RCU는 lookup에만 필요하므로 VMA lock 획득 뒤 놓을 수 있습니다. User-facing interface는 이를 추상화한 `lock_vma_under_rcu`입니다.

Write에는 mmap write lock과 `vma_start_write`가 필요합니다. Mmap write lock 종료나 downgrade가 VMA write lock을 해제합니다. 여러 VMA를 동시에 write-lock하는 operation의 복잡성을 줄이려고 per-mm과 per-VMA sequence count를 사용합니다.

`mm->mm_lock_seq`와 `vma->vm_lock_seq`가 같으면 VMA가 write-locked이고 다르면 아닙니다. `mmap_write_unlock` 또는 `mmap_write_downgrade` 때 `vma_end_write_all`이 호출되고 `mm_lock_seqcount_end`로 `mm->mm_lock_seq`도 증가합니다. 따라서 VMA sequence 값과 무관하게 write-lock 상태를 잘못 표시하지 않으며 mmap의 모든 VMA write lock을 한꺼번에 효율적으로 놓습니다.

Mmap write lock은 holder끼리 exclusive이므로 별도 write operation 사이까지 VMA lock을 유지할 이유가 없고, 자동 해제가 올바른 lock ordering도 보존합니다.

VMA read lock 획득 때 `vma.vm_refcnt`를 증가시키고 VMA sequence가 mm sequence와 다른지 확인합니다. 같으면 writer가 있으므로 실패하고 refcount를 내립니다. 다르면 refcount를 높인 채 writer를 배제하고 RCU 아래 다른 reader의 동시 획득을 허용합니다. `lock_vma_under_rcu`의 maple-tree operation도 RCU-safe입니다.

Writer는 reader가 수정할 수 없는 bit를 `vma.vm_refcnt`에 set하고 모든 reader가 refcount를 내릴 때까지 기다립니다. Reader가 사라지면 mmap write lock을 든 채 VMA sequence를 mm sequence와 같게 합니다. 이 때문에 read lock이 있으면 `vma_start_write`가 완료를 기다려 mutual exclusion을 얻습니다. 그 뒤 writer bit를 clear하고, mmap write lock을 놓거나 downgrade할 때까지 sequence가 write-locked 상태를 나타냅니다.

Reference counter와 sequence count의 조합은 특히 page fault에서 빠른 RCU 기반 per-VMA lock 획득을 제공하면서 lock-ordering 복잡성을 최소화합니다.

VMA lock internals
------------------

Overview
^^^^^^^^

VMA read locking is entirely optimistic - if the lock is contended or a competing
write has started, then we do not obtain a read lock.

A VMA **read** lock is obtained by :c:func:`!lock_vma_under_rcu`, which first
calls :c:func:`!rcu_read_lock` to ensure that the VMA is looked up in an RCU
critical section, then attempts to VMA lock it via :c:func:`!vma_start_read`,
before releasing the RCU lock via :c:func:`!rcu_read_unlock`.

In cases when the user already holds mmap read lock, :c:func:`!vma_start_read_locked`
and :c:func:`!vma_start_read_locked_nested` can be used. These functions do not
fail due to lock contention but the caller should still check their return values
in case they fail for other reasons.

VMA read locks increment :c:member:`!vma.vm_refcnt` reference counter for their
duration and the caller of :c:func:`!lock_vma_under_rcu` must drop it via
:c:func:`!vma_end_read`.

VMA **write** locks are acquired via :c:func:`!vma_start_write` in instances where a
VMA is about to be modified, unlike :c:func:`!vma_start_read` the lock is always
acquired. An mmap write lock **must** be held for the duration of the VMA write
lock, releasing or downgrading the mmap write lock also releases the VMA write
lock so there is no :c:func:`!vma_end_write` function.

Note that when write-locking a VMA lock, the :c:member:`!vma.vm_refcnt` is temporarily
modified so that readers can detect the presense of a writer. The reference counter is
restored once the vma sequence number used for serialisation is updated.

This ensures the semantics we require - VMA write locks provide exclusive write
access to the VMA.

Implementation details
^^^^^^^^^^^^^^^^^^^^^^

The VMA lock mechanism is designed to be a lightweight means of avoiding the use
of the heavily contended mmap lock. It is implemented using a combination of a
reference counter and sequence numbers belonging to the containing
:c:struct:`!struct mm_struct` and the VMA.

Read locks are acquired via :c:func:`!vma_start_read`, which is an optimistic
operation, i.e. it tries to acquire a read lock but returns false if it is
unable to do so. At the end of the read operation, :c:func:`!vma_end_read` is
called to release the VMA read lock.

Invoking :c:func:`!vma_start_read` requires that :c:func:`!rcu_read_lock` has
been called first, establishing that we are in an RCU critical section upon VMA
read lock acquisition. Once acquired, the RCU lock can be released as it is only
required for lookup. This is abstracted by :c:func:`!lock_vma_under_rcu` which
is the interface a user should use.

Writing requires the mmap to be write-locked and the VMA lock to be acquired via
:c:func:`!vma_start_write`, however the write lock is released by the termination or
downgrade of the mmap write lock so no :c:func:`!vma_end_write` is required.

All this is achieved by the use of per-mm and per-VMA sequence counts, which are
used in order to reduce complexity, especially for operations which write-lock
multiple VMAs at once.

If the mm sequence count, :c:member:`!mm->mm_lock_seq` is equal to the VMA
sequence count :c:member:`!vma->vm_lock_seq` then the VMA is write-locked. If
they differ, then it is not.

Each time the mmap write lock is released in :c:func:`!mmap_write_unlock` or
:c:func:`!mmap_write_downgrade`, :c:func:`!vma_end_write_all` is invoked which
also increments :c:member:`!mm->mm_lock_seq` via
:c:func:`!mm_lock_seqcount_end`.

This way, we ensure that, regardless of the VMA's sequence number, a write lock
is never incorrectly indicated and that when we release an mmap write lock we
efficiently release **all** VMA write locks contained within the mmap at the
same time.

Since the mmap write lock is exclusive against others who hold it, the automatic
release of any VMA locks on its release makes sense, as you would never want to
keep VMAs locked across entirely separate write operations. It also maintains
correct lock ordering.

Each time a VMA read lock is acquired, we increment :c:member:`!vma.vm_refcnt`
reference counter and check that the sequence count of the VMA does not match
that of the mm.

If it does, the read lock fails and :c:member:`!vma.vm_refcnt` is dropped.
If it does not, we keep the reference counter raised, excluding writers, but
permitting other readers, who can also obtain this lock under RCU.

Importantly, maple tree operations performed in :c:func:`!lock_vma_under_rcu`
are also RCU safe, so the whole read lock operation is guaranteed to function
correctly.

On the write side, we set a bit in :c:member:`!vma.vm_refcnt` which can't be
modified by readers and wait for all readers to drop their reference count.
Once there are no readers, the VMA's sequence number is set to match that of
the mm. During this entire operation mmap write lock is held.

This way, if any read locks are in effect, :c:func:`!vma_start_write` will sleep
until these are finished and mutual exclusion is achieved.

After setting the VMA's sequence number, the bit in :c:member:`!vma.vm_refcnt`
indicating a writer is cleared. From this point on, VMA's sequence number will
indicate VMA's write-locked state until mmap write lock is dropped or downgraded.

This clever combination of a reference counter and sequence count allows for
fast RCU-based per-VMA lock acquisition (especially on page fault, though
utilised elsewhere) with minimal complexity around lock ordering.

mmap write-lock downgrade

857-903

Mmap write lock을 가지면 mmap 안 resource에 exclusive access가 있습니다. 다만 VMA read-lock holder와 race하지 않으려면 VMA write lock이 필요하다는 일반 주의는 그대로입니다.

`mmap_write_downgrade`로 write lock을 read lock으로 downgrade할 수 있습니다. `mmap_write_unlock`과 마찬가지로 `vma_end_write_all`을 통해 모든 VMA write lock을 암시적으로 끝내지만, downgrade 동안 mmap lock 자체는 놓지 않으므로 locked virtual-address space는 stable하게 유지됩니다.

흥미롭게도 downgraded lock끼리는 서로 exclusive입니다. 경쟁 task가 downgraded lock을 얻으려면 먼저 write lock을 얻어야 하지만 기존 downgraded lock이 새 write lock을 막기 때문입니다.

Exclusivity matrix에서 read(R)와 read, read와 downgraded(D)는 서로 배제하지 않습니다. R과 W는 배제합니다. D와 D, D와 W는 배제합니다. W는 R·D·W 모두와 배제합니다. 원문 표의 Y는 mutual exclusion, N은 비배제를 뜻합니다.

mmap write lock downgrading
---------------------------

When an mmap write lock is held one has exclusive access to resources within the
mmap (with the usual caveats about requiring VMA write locks to avoid races with
tasks holding VMA read locks).

It is then possible to **downgrade** from a write lock to a read lock via
:c:func:`!mmap_write_downgrade` which, similar to :c:func:`!mmap_write_unlock`,
implicitly terminates all VMA write locks via :c:func:`!vma_end_write_all`, but
importantly does not relinquish the mmap lock while downgrading, therefore
keeping the locked virtual address space stable.

An interesting consequence of this is that downgraded locks are exclusive
against any other task possessing a downgraded lock (since a racing task would
have to acquire a write lock first to downgrade it, and the downgraded lock
prevents a new write lock from being obtained until the original lock is
released).

For clarity, we map read (R)/downgraded write (D)/write (W) locks against one
another showing which locks exclude the others:

.. list-table:: Lock exclusivity
   :widths: 5 5 5 5
   :header-rows: 1
   :stub-columns: 1

   * -
     - R
     - D
     - W
   * - R
     - N
     - N
     - Y
   * - D
     - N
     - Y
     - Y
   * - W
     - Y
     - Y
     - Y

Here a Y indicates the locks in the matching row/column are mutually exclusive,
and N indicates that they are not.

Stack expansion

904-909

Stack expansion은 racing page fault를 허용할 수 없다는 추가 복잡성을 만듭니다. `expand_downwards` 또는 `expand_upwards`에서 이를 막기 위해 `vma_start_write`를 호출합니다.

Stack expansion
---------------

Stack expansion throws up additional complexities in that we cannot permit there
to be racing page faults, as a result we invoke :c:func:`!vma_start_write` to
prevent this in :c:func:`!expand_downwards` or :c:func:`!expand_upwards`.