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

Linux 6.18.37 · Memory management

Physical Memory

NUMA node와 zone 배치, pglist_data·zone field, PCP·buddy·reclaim·compaction 상태를 설명합니다.

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

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

1. 요약·해설

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

요약·해설

physical_memory.rst:1-635

Linux physical-memory model은 memory bank를 node로, node 안의 address-constrained range를 zone으로 표현합니다. Node의 `pg_data_t`는 zone·reclaim·compaction state를 모으고, 각 `struct zone`은 watermark·PCP·buddy free area·extent와 statistic을 관리합니다.

Physical-memory 관리 계층
Firmware physical-memory mapNUMA node / `pg_data_t``struct zone`PCP와 buddy `free_area``struct page` / folio

Architecture가 보고한 memory range를 node와 zone으로 나누고 page allocator가 page 단위로 관리합니다.

Zone 유형
Zone용도주요 조건
`ZONE_DMA`제한된 DMA address range`CONFIG_ZONE_DMA`
`ZONE_DMA32`32bit DMA address range`CONFIG_ZONE_DMA32`
`ZONE_NORMAL`Kernel이 항상 접근하는 일반 memory항상 enable
`ZONE_HIGHMEM`Permanent kernel mapping 밖의 memory일부 32bit, `CONFIG_HIGHMEM`
`ZONE_MOVABLE`Content를 옮길 수 있는 일반 memoryHotplug·`kernelcore`·`movablecore`·`movable_node`
`ZONE_DEVICE`PMEM·GPU device memory`CONFIG_ZONE_DEVICE`

접근 제약과 이동 가능성에 따라 physical-memory range를 구분합니다.

x86 UMA 2GB layout
Node주소 범위Zone
node 00~16MB`ZONE_DMA`
node 016~896MB`ZONE_NORMAL`
node 0896MB~2GB`ZONE_HIGHMEM`

원문의 첫 ASCII layout을 동일한 주소 경계로 구조화했습니다.

arm64 16GB movablecore=80% layout
Node주소 범위Zone
node 01~4GB`ZONE_DMA32`
node 04GB~4200MB`ZONE_NORMAL`
node 04200MB~9GB`ZONE_MOVABLE`
node 19GB~9320MB`ZONE_NORMAL`
node 19320MB~17GB`ZONE_MOVABLE`

원문에 표시된 1GB~17GB 주소와 zone 경계를 그대로 보존했습니다.

Interleaved node layout
Bank rangeNodeZone
0~16MBnode 0`ZONE_DMA`
16MB~4GBnode 0`ZONE_DMA32`
4~8GBnode 1`ZONE_NORMAL`
8~12GBnode 0`ZONE_NORMAL`
12~16GBnode 1`ZONE_NORMAL`

4GB bank 네 개가 node 0과 node 1에 번갈아 속하는 원문 구조입니다.

node_states mask
State의미
`N_POSSIBLE`Online 가능
`N_ONLINE`현재 online
`N_NORMAL_MEMORY`Regular memory 보유
`N_HIGH_MEMORY`Regular 또는 high memory 보유
`N_MEMORY`Regular·high·movable memory 보유
`N_CPU`CPU 하나 이상 보유
`N_GENERIC_INITIATOR`Generic Initiator 하나 이상 보유

각 property mask의 node-ID bit가 해당 속성 보유 여부를 나타냅니다.

Zone allocation의 2단계 경로
Allocation request와 GFP 최고 zone해당 zone의 CPU별 PCPPCP 부족Buddy `free_area`Batch refillPCP
Page freeCPU별 PCPHigh threshold 초과Batch 반환Buddy `free_area`

CPU-local fast path를 먼저 사용하고 필요한 경우 global buddy allocator로 이동합니다.

Zone watermark 동작
경계Free pages 상태주요 동작
minmin 아래Direct reclaim·compaction·throttle 가능
lowlow 아래kswapd wake
highhigh 위일반 NUMA mode에서 kswapd stop
promopromo 위Memory-tiering NUMA mode에서 kswapd stop

Free-page 수가 각 경계를 지날 때 reclaim·kswapd 동작이 달라집니다.

Zone page-count 계산
Field계산
`spanned_pages``zone_end_pfn - zone_start_pfn`
`present_pages``spanned_pages - absent_pages`
`managed_pages``present_pages - reserved_pages`
Unmanaged pages`present_pages - managed_pages`

Span, presence와 buddy 관리 범위를 구분합니다.

Buddy block split과 merge
큰 free block요청보다 큼다음 작은 order로 split충분한 최소 blockAllocation
Freed blockFree buddy 확인Merge더 큰 order의 free block

Allocation은 충분한 block을 나누고 free는 buddy와 다시 합칩니다.

Compaction scanner
`compact_cached_migrate_pfn`Migratable page 탐색Page migrationScanners meet`compact_blockskip_flush`
`compact_cached_free_pfn`Free page 탐색Migration destinationScanners meet`PB_compact_skip` clear 대상

Migration scanner와 free scanner가 zone 양쪽을 탐색하며 만남 여부와 다음 시작 PFN을 기록합니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ===============
4 Physical Memory
5 ===============
6
7 Linux is available for a wide range of architectures so there is a need for an
8 architecture-independent abstraction to represent the physical memory. This
9 chapter describes the structures used to manage physical memory in a running
10 system.
11
12 The first principal concept prevalent in the memory management is
13 `Non-Uniform Memory Access (NUMA)
14 <https://en.wikipedia.org/wiki/Non-uniform_memory_access>`_.
15 With multi-core and multi-socket machines, memory may be arranged into banks
16 that incur a different cost to access depending on the “distance” from the
17 processor. For example, there might be a bank of memory assigned to each CPU or
18 a bank of memory very suitable for DMA near peripheral devices.
19
20 Each bank is called a node and the concept is represented under Linux by a
21 ``struct pglist_data`` even if the architecture is UMA. This structure is
22 always referenced by its typedef ``pg_data_t``. A ``pg_data_t`` structure
23 for a particular node can be referenced by ``NODE_DATA(nid)`` macro where
24 ``nid`` is the ID of that node.
25
26 For NUMA architectures, the node structures are allocated by the architecture
27 specific code early during boot. Usually, these structures are allocated
28 locally on the memory bank they represent. For UMA architectures, only one
29 static ``pg_data_t`` structure called ``contig_page_data`` is used. Nodes will
30 be discussed further in Section :ref:`Nodes <nodes>`
31
32 The entire physical address space is partitioned into one or more blocks
33 called zones which represent ranges within memory. These ranges are usually
34 determined by architectural constraints for accessing the physical memory.
35 The memory range within a node that corresponds to a particular zone is
36 described by a ``struct zone``. Each zone has
37 one of the types described below.
38
39 * ``ZONE_DMA`` and ``ZONE_DMA32`` historically represented memory suitable for
40 DMA by peripheral devices that cannot access all of the addressable
41 memory. For many years there are better more and robust interfaces to get
42 memory with DMA specific requirements (Documentation/core-api/dma-api.rst),
43 but ``ZONE_DMA`` and ``ZONE_DMA32`` still represent memory ranges that have
44 restrictions on how they can be accessed.
45 Depending on the architecture, either of these zone types or even they both
46 can be disabled at build time using ``CONFIG_ZONE_DMA`` and
47 ``CONFIG_ZONE_DMA32`` configuration options. Some 64-bit platforms may need
48 both zones as they support peripherals with different DMA addressing
49 limitations.
50
51 * ``ZONE_NORMAL`` is for normal memory that can be accessed by the kernel all
52 the time. DMA operations can be performed on pages in this zone if the DMA
53 devices support transfers to all addressable memory. ``ZONE_NORMAL`` is
54 always enabled.
55
56 * ``ZONE_HIGHMEM`` is the part of the physical memory that is not covered by a
57 permanent mapping in the kernel page tables. The memory in this zone is only
58 accessible to the kernel using temporary mappings. This zone is available
59 only on some 32-bit architectures and is enabled with ``CONFIG_HIGHMEM``.
60
61 * ``ZONE_MOVABLE`` is for normal accessible memory, just like ``ZONE_NORMAL``.
62 The difference is that the contents of most pages in ``ZONE_MOVABLE`` is
63 movable. That means that while virtual addresses of these pages do not
64 change, their content may move between different physical pages. Often
65 ``ZONE_MOVABLE`` is populated during memory hotplug, but it may be
66 also populated on boot using one of ``kernelcore``, ``movablecore`` and
67 ``movable_node`` kernel command line parameters. See
68 Documentation/mm/page_migration.rst and
69 Documentation/admin-guide/mm/memory-hotplug.rst for additional details.
70
71 * ``ZONE_DEVICE`` represents memory residing on devices such as PMEM and GPU.
72 It has different characteristics than RAM zone types and it exists to provide
73 :ref:`struct page <Pages>` and memory map services for device driver
74 identified physical address ranges. ``ZONE_DEVICE`` is enabled with
75 configuration option ``CONFIG_ZONE_DEVICE``.
76
77 It is important to note that many kernel operations can only take place using
78 ``ZONE_NORMAL`` so it is the most performance critical zone. Zones are
79 discussed further in Section :ref:`Zones <zones>`.
80
81 The relation between node and zone extents is determined by the physical memory
82 map reported by the firmware, architectural constraints for memory addressing
83 and certain parameters in the kernel command line.
84
85 For example, with 32-bit kernel on an x86 UMA machine with 2 Gbytes of RAM the
86 entire memory will be on node 0 and there will be three zones: ``ZONE_DMA``,
87 ``ZONE_NORMAL`` and ``ZONE_HIGHMEM``::
88
89 0 2G
90 +-------------------------------------------------------------+
91 | node 0 |
92 +-------------------------------------------------------------+
93
94 0 16M 896M 2G
95 +----------+-----------------------+--------------------------+
96 | ZONE_DMA | ZONE_NORMAL | ZONE_HIGHMEM |
97 +----------+-----------------------+--------------------------+
98
99
100 With a kernel built with ``ZONE_DMA`` disabled and ``ZONE_DMA32`` enabled and
101 booted with ``movablecore=80%`` parameter on an arm64 machine with 16 Gbytes of
102 RAM equally split between two nodes, there will be ``ZONE_DMA32``,
103 ``ZONE_NORMAL`` and ``ZONE_MOVABLE`` on node 0, and ``ZONE_NORMAL`` and
104 ``ZONE_MOVABLE`` on node 1::
105
106
107 1G 9G 17G
108 +--------------------------------+ +--------------------------+
109 | node 0 | | node 1 |
110 +--------------------------------+ +--------------------------+
111
112 1G 4G 4200M 9G 9320M 17G
113 +---------+----------+-----------+ +------------+-------------+
114 | DMA32 | NORMAL | MOVABLE | | NORMAL | MOVABLE |
115 +---------+----------+-----------+ +------------+-------------+
116
117
118 Memory banks may belong to interleaving nodes. In the example below an x86
119 machine has 16 Gbytes of RAM in 4 memory banks, even banks belong to node 0
120 and odd banks belong to node 1::
121
122
123 0 4G 8G 12G 16G
124 +-------------+ +-------------+ +-------------+ +-------------+
125 | node 0 | | node 1 | | node 0 | | node 1 |
126 +-------------+ +-------------+ +-------------+ +-------------+
127
128 0 16M 4G
129 +-----+-------+ +-------------+ +-------------+ +-------------+
130 | DMA | DMA32 | | NORMAL | | NORMAL | | NORMAL |
131 +-----+-------+ +-------------+ +-------------+ +-------------+
132
133 In this case node 0 will span from 0 to 12 Gbytes and node 1 will span from
134 4 to 16 Gbytes.
135
136 .. _nodes:
137
138 Nodes
139 =====
140
141 As we have mentioned, each node in memory is described by a ``pg_data_t`` which
142 is a typedef for a ``struct pglist_data``. When allocating a page, by default
143 Linux uses a node-local allocation policy to allocate memory from the node
144 closest to the running CPU. As processes tend to run on the same CPU, it is
145 likely the memory from the current node will be used. The allocation policy can
146 be controlled by users as described in
147 Documentation/admin-guide/mm/numa_memory_policy.rst.
148
149 Most NUMA architectures maintain an array of pointers to the node
150 structures. The actual structures are allocated early during boot when
151 architecture specific code parses the physical memory map reported by the
152 firmware. The bulk of the node initialization happens slightly later in the
153 boot process by free_area_init() function, described later in Section
154 :ref:`Initialization <initialization>`.
155
156
157 Along with the node structures, kernel maintains an array of ``nodemask_t``
158 bitmasks called ``node_states``. Each bitmask in this array represents a set of
159 nodes with particular properties as defined by ``enum node_states``:
160
161 ``N_POSSIBLE``
162 The node could become online at some point.
163 ``N_ONLINE``
164 The node is online.
165 ``N_NORMAL_MEMORY``
166 The node has regular memory.
167 ``N_HIGH_MEMORY``
168 The node has regular or high memory. When ``CONFIG_HIGHMEM`` is disabled
169 aliased to ``N_NORMAL_MEMORY``.
170 ``N_MEMORY``
171 The node has memory(regular, high, movable)
172 ``N_CPU``
173 The node has one or more CPUs
174 ``N_GENERIC_INITIATOR``
175 The node has one or more Generic Initiators
176
177 For each node that has a property described above, the bit corresponding to the
178 node ID in the ``node_states[<property>]`` bitmask is set.
179
180 For example, for node 2 with normal memory and CPUs, bit 2 will be set in ::
181
182 node_states[N_POSSIBLE]
183 node_states[N_ONLINE]
184 node_states[N_NORMAL_MEMORY]
185 node_states[N_HIGH_MEMORY]
186 node_states[N_MEMORY]
187 node_states[N_CPU]
188
189 For various operations possible with nodemasks please refer to
190 ``include/linux/nodemask.h``.
191
192 Among other things, nodemasks are used to provide macros for node traversal,
193 namely ``for_each_node()`` and ``for_each_online_node()``.
194
195 For instance, to call a function foo() for each online node::
196
197 for_each_online_node(nid) {
198 pg_data_t *pgdat = NODE_DATA(nid);
199
200 foo(pgdat);
201 }
202
203 Node structure
204 --------------
205
206 The nodes structure ``struct pglist_data`` is declared in
207 ``include/linux/mmzone.h``. Here we briefly describe fields of this
208 structure:
209
210 General
211 ~~~~~~~
212
213 ``node_zones``
214 The zones for this node. Not all of the zones may be populated, but it is
215 the full list. It is referenced by this node's node_zonelists as well as
216 other node's node_zonelists.
217
218 ``node_zonelists``
219 The list of all zones in all nodes. This list defines the order of zones
220 that allocations are preferred from. The ``node_zonelists`` is set up by
221 ``build_zonelists()`` in ``mm/page_alloc.c`` during the initialization of
222 core memory management structures.
223
224 ``nr_zones``
225 Number of populated zones in this node.
226
227 ``node_mem_map``
228 For UMA systems that use FLATMEM memory model the 0's node
229 ``node_mem_map`` is array of struct pages representing each physical frame.
230
231 ``node_page_ext``
232 For UMA systems that use FLATMEM memory model the 0's node
233 ``node_page_ext`` is array of extensions of struct pages. Available only
234 in the kernels built with ``CONFIG_PAGE_EXTENSION`` enabled.
235
236 ``node_start_pfn``
237 The page frame number of the starting page frame in this node.
238
239 ``node_present_pages``
240 Total number of physical pages present in this node.
241
242 ``node_spanned_pages``
243 Total size of physical page range, including holes.
244
245 ``node_size_lock``
246 A lock that protects the fields defining the node extents. Only defined when
247 at least one of ``CONFIG_MEMORY_HOTPLUG`` or
248 ``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` configuration options are enabled.
249 ``pgdat_resize_lock()`` and ``pgdat_resize_unlock()`` are provided to
250 manipulate ``node_size_lock`` without checking for ``CONFIG_MEMORY_HOTPLUG``
251 or ``CONFIG_DEFERRED_STRUCT_PAGE_INIT``.
252
253 ``node_id``
254 The Node ID (NID) of the node, starts at 0.
255
256 ``totalreserve_pages``
257 This is a per-node reserve of pages that are not available to userspace
258 allocations.
259
260 ``first_deferred_pfn``
261 If memory initialization on large machines is deferred then this is the first
262 PFN that needs to be initialized. Defined only when
263 ``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` is enabled
264
265 ``deferred_split_queue``
266 Per-node queue of huge pages that their split was deferred. Defined only when ``CONFIG_TRANSPARENT_HUGEPAGE`` is enabled.
267
268 ``__lruvec``
269 Per-node lruvec holding LRU lists and related parameters. Used only when
270 memory cgroups are disabled. It should not be accessed directly, use
271 ``mem_cgroup_lruvec()`` to look up lruvecs instead.
272
273 Reclaim control
274 ~~~~~~~~~~~~~~~
275
276 See also Documentation/mm/page_reclaim.rst.
277
278 ``kswapd``
279 Per-node instance of kswapd kernel thread.
280
281 ``kswapd_wait``, ``pfmemalloc_wait``, ``reclaim_wait``
282 Workqueues used to synchronize memory reclaim tasks
283
284 ``nr_writeback_throttled``
285 Number of tasks that are throttled waiting on dirty pages to clean.
286
287 ``nr_reclaim_start``
288 Number of pages written while reclaim is throttled waiting for writeback.
289
290 ``kswapd_order``
291 Controls the order kswapd tries to reclaim
292
293 ``kswapd_highest_zoneidx``
294 The highest zone index to be reclaimed by kswapd
295
296 ``kswapd_failures``
297 Number of runs kswapd was unable to reclaim any pages
298
299 ``min_unmapped_pages``
300 Minimal number of unmapped file backed pages that cannot be reclaimed.
301 Determined by ``vm.min_unmapped_ratio`` sysctl. Only defined when
302 ``CONFIG_NUMA`` is enabled.
303
304 ``min_slab_pages``
305 Minimal number of SLAB pages that cannot be reclaimed. Determined by
306 ``vm.min_slab_ratio sysctl``. Only defined when ``CONFIG_NUMA`` is enabled
307
308 ``flags``
309 Flags controlling reclaim behavior.
310
311 Compaction control
312 ~~~~~~~~~~~~~~~~~~
313
314 ``kcompactd_max_order``
315 Page order that kcompactd should try to achieve.
316
317 ``kcompactd_highest_zoneidx``
318 The highest zone index to be compacted by kcompactd.
319
320 ``kcompactd_wait``
321 Workqueue used to synchronize memory compaction tasks.
322
323 ``kcompactd``
324 Per-node instance of kcompactd kernel thread.
325
326 ``proactive_compact_trigger``
327 Determines if proactive compaction is enabled. Controlled by
328 ``vm.compaction_proactiveness`` sysctl.
329
330 Statistics
331 ~~~~~~~~~~
332
333 ``per_cpu_nodestats``
334 Per-CPU VM statistics for the node
335
336 ``vm_stat``
337 VM statistics for the node.
338
339 .. _zones:
340
341 Zones
342 =====
343 As we have mentioned, each zone in memory is described by a ``struct zone``
344 which is an element of the ``node_zones`` array of the node it belongs to.
345 ``struct zone`` is the core data structure of the page allocator. A zone
346 represents a range of physical memory and may have holes.
347
348 The page allocator uses the GFP flags, see :ref:`mm-api-gfp-flags`, specified by
349 a memory allocation to determine the highest zone in a node from which the
350 memory allocation can allocate memory. The page allocator first allocates memory
351 from that zone, if the page allocator can't allocate the requested amount of
352 memory from the zone, it will allocate memory from the next lower zone in the
353 node, the process continues up to and including the lowest zone. For example, if
354 a node contains ``ZONE_DMA32``, ``ZONE_NORMAL`` and ``ZONE_MOVABLE`` and the
355 highest zone of a memory allocation is ``ZONE_MOVABLE``, the order of the zones
356 from which the page allocator allocates memory is ``ZONE_MOVABLE`` >
357 ``ZONE_NORMAL`` > ``ZONE_DMA32``.
358
359 At runtime, free pages in a zone are in the Per-CPU Pagesets (PCP) or free areas
360 of the zone. The Per-CPU Pagesets are a vital mechanism in the kernel's memory
361 management system. By handling most frequent allocations and frees locally on
362 each CPU, the Per-CPU Pagesets improve performance and scalability, especially
363 on systems with many cores. The page allocator in the kernel employs a two-step
364 strategy for memory allocation, starting with the Per-CPU Pagesets before
365 falling back to the buddy allocator. Pages are transferred between the Per-CPU
366 Pagesets and the global free areas (managed by the buddy allocator) in batches.
367 This minimizes the overhead of frequent interactions with the global buddy
368 allocator.
369
370 Architecture specific code calls free_area_init() to initializes zones.
371
372 Zone structure
373 --------------
374 The zones structure ``struct zone`` is defined in ``include/linux/mmzone.h``.
375 Here we briefly describe fields of this structure:
376
377 General
378 ~~~~~~~
379
380 ``_watermark``
381 The watermarks for this zone. When the amount of free pages in a zone is below
382 the min watermark, boosting is ignored, an allocation may trigger direct
383 reclaim and direct compaction, it is also used to throttle direct reclaim.
384 When the amount of free pages in a zone is below the low watermark, kswapd is
385 woken up. When the amount of free pages in a zone is above the high watermark,
386 kswapd stops reclaiming (a zone is balanced) when the
387 ``NUMA_BALANCING_MEMORY_TIERING`` bit of ``sysctl_numa_balancing_mode`` is not
388 set. The promo watermark is used for memory tiering and NUMA balancing. When
389 the amount of free pages in a zone is above the promo watermark, kswapd stops
390 reclaiming when the ``NUMA_BALANCING_MEMORY_TIERING`` bit of
391 ``sysctl_numa_balancing_mode`` is set. The watermarks are set by
392 ``__setup_per_zone_wmarks()``. The min watermark is calculated according to
393 ``vm.min_free_kbytes`` sysctl. The other three watermarks are set according
394 to the distance between two watermarks. The distance itself is calculated
395 taking ``vm.watermark_scale_factor`` sysctl into account.
396
397 ``watermark_boost``
398 The number of pages which are used to boost watermarks to increase reclaim
399 pressure to reduce the likelihood of future fallbacks and wake kswapd now
400 as the node may be balanced overall and kswapd will not wake naturally.
401
402 ``nr_reserved_highatomic``
403 The number of pages which are reserved for high-order atomic allocations.
404
405 ``nr_free_highatomic``
406 The number of free pages in reserved highatomic pageblocks
407
408 ``lowmem_reserve``
409 The array of the amounts of the memory reserved in this zone for memory
410 allocations. For example, if the highest zone a memory allocation can
411 allocate memory from is ``ZONE_MOVABLE``, the amount of memory reserved in
412 this zone for this allocation is ``lowmem_reserve[ZONE_MOVABLE]`` when
413 attempting to allocate memory from this zone. This is a mechanism the page
414 allocator uses to prevent allocations which could use ``highmem`` from using
415 too much ``lowmem``. For some specialised workloads on ``highmem`` machines,
416 it is dangerous for the kernel to allow process memory to be allocated from
417 the ``lowmem`` zone. This is because that memory could then be pinned via the
418 ``mlock()`` system call, or by unavailability of swapspace.
419 ``vm.lowmem_reserve_ratio`` sysctl determines how aggressive the kernel is in
420 defending these lower zones. This array is recalculated by
421 ``setup_per_zone_lowmem_reserve()`` at runtime if ``vm.lowmem_reserve_ratio``
422 sysctl changes.
423
424 ``node``
425 The index of the node this zone belongs to. Available only when
426 ``CONFIG_NUMA`` is enabled because there is only one zone in a UMA system.
427
428 ``zone_pgdat``
429 Pointer to the ``struct pglist_data`` of the node this zone belongs to.
430
431 ``per_cpu_pageset``
432 Pointer to the Per-CPU Pagesets (PCP) allocated and initialized by
433 ``setup_zone_pageset()``. By handling most frequent allocations and frees
434 locally on each CPU, PCP improves performance and scalability on systems with
435 many cores.
436
437 ``pageset_high_min``
438 Copied to the ``high_min`` of the Per-CPU Pagesets for faster access.
439
440 ``pageset_high_max``
441 Copied to the ``high_max`` of the Per-CPU Pagesets for faster access.
442
443 ``pageset_batch``
444 Copied to the ``batch`` of the Per-CPU Pagesets for faster access. The
445 ``batch``, ``high_min`` and ``high_max`` of the Per-CPU Pagesets are used to
446 calculate the number of elements the Per-CPU Pagesets obtain from the buddy
447 allocator under a single hold of the lock for efficiency. They are also used
448 to decide if the Per-CPU Pagesets return pages to the buddy allocator in page
449 free process.
450
451 ``pageblock_flags``
452 The pointer to the flags for the pageblocks in the zone (see
453 ``include/linux/pageblock-flags.h`` for flags list). The memory is allocated
454 in ``setup_usemap()``. Each pageblock occupies ``NR_PAGEBLOCK_BITS`` bits.
455 Defined only when ``CONFIG_FLATMEM`` is enabled. The flags is stored in
456 ``mem_section`` when ``CONFIG_SPARSEMEM`` is enabled.
457
458 ``zone_start_pfn``
459 The start pfn of the zone. It is initialized by
460 ``calculate_node_totalpages()``.
461
462 ``managed_pages``
463 The present pages managed by the buddy system, which is calculated as:
464 ``managed_pages`` = ``present_pages`` - ``reserved_pages``, ``reserved_pages``
465 includes pages allocated by the memblock allocator. It should be used by page
466 allocator and vm scanner to calculate all kinds of watermarks and thresholds.
467 It is accessed using ``atomic_long_xxx()`` functions. It is initialized in
468 ``free_area_init_core()`` and then is reinitialized when memblock allocator
469 frees pages into buddy system.
470
471 ``spanned_pages``
472 The total pages spanned by the zone, including holes, which is calculated as:
473 ``spanned_pages`` = ``zone_end_pfn`` - ``zone_start_pfn``. It is initialized
474 by ``calculate_node_totalpages()``.
475
476 ``present_pages``
477 The physical pages existing within the zone, which is calculated as:
478 ``present_pages`` = ``spanned_pages`` - ``absent_pages`` (pages in holes). It
479 may be used by memory hotplug or memory power management logic to figure out
480 unmanaged pages by checking (``present_pages`` - ``managed_pages``). Write
481 access to ``present_pages`` at runtime should be protected by
482 ``mem_hotplug_begin/done()``. Any reader who can't tolerant drift of
483 ``present_pages`` should use ``get_online_mems()`` to get a stable value. It
484 is initialized by ``calculate_node_totalpages()``.
485
486 ``present_early_pages``
487 The present pages existing within the zone located on memory available since
488 early boot, excluding hotplugged memory. Defined only when
489 ``CONFIG_MEMORY_HOTPLUG`` is enabled and initialized by
490 ``calculate_node_totalpages()``.
491
492 ``cma_pages``
493 The pages reserved for CMA use. These pages behave like ``ZONE_MOVABLE`` when
494 they are not used for CMA. Defined only when ``CONFIG_CMA`` is enabled.
495
496 ``name``
497 The name of the zone. It is a pointer to the corresponding element of
498 the ``zone_names`` array.
499
500 ``nr_isolate_pageblock``
501 Number of isolated pageblocks. It is used to solve incorrect freepage counting
502 problem due to racy retrieving migratetype of pageblock. Protected by
503 ``zone->lock``. Defined only when ``CONFIG_MEMORY_ISOLATION`` is enabled.
504
505 ``span_seqlock``
506 The seqlock to protect ``zone_start_pfn`` and ``spanned_pages``. It is a
507 seqlock because it has to be read outside of ``zone->lock``, and it is done in
508 the main allocator path. However, the seqlock is written quite infrequently.
509 Defined only when ``CONFIG_MEMORY_HOTPLUG`` is enabled.
510
511 ``initialized``
512 The flag indicating if the zone is initialized. Set by
513 ``init_currently_empty_zone()`` during boot.
514
515 ``free_area``
516 The array of free areas, where each element corresponds to a specific order
517 which is a power of two. The buddy allocator uses this structure to manage
518 free memory efficiently. When allocating, it tries to find the smallest
519 sufficient block, if the smallest sufficient block is larger than the
520 requested size, it will be recursively split into the next smaller blocks
521 until the required size is reached. When a page is freed, it may be merged
522 with its buddy to form a larger block. It is initialized by
523 ``zone_init_free_lists()``.
524
525 ``unaccepted_pages``
526 The list of pages to be accepted. All pages on the list are ``MAX_PAGE_ORDER``.
527 Defined only when ``CONFIG_UNACCEPTED_MEMORY`` is enabled.
528
529 ``flags``
530 The zone flags. The least three bits are used and defined by
531 ``enum zone_flags``. ``ZONE_BOOSTED_WATERMARK`` (bit 0): zone recently boosted
532 watermarks. Cleared when kswapd is woken. ``ZONE_RECLAIM_ACTIVE`` (bit 1):
533 kswapd may be scanning the zone. ``ZONE_BELOW_HIGH`` (bit 2): zone is below
534 high watermark.
535
536 ``lock``
537 The main lock that protects the internal data structures of the page allocator
538 specific to the zone, especially protects ``free_area``.
539
540 ``percpu_drift_mark``
541 When free pages are below this point, additional steps are taken when reading
542 the number of free pages to avoid per-cpu counter drift allowing watermarks
543 to be breached. It is updated in ``refresh_zone_stat_thresholds()``.
544
545 Compaction control
546 ~~~~~~~~~~~~~~~~~~
547
548 ``compact_cached_free_pfn``
549 The PFN where compaction free scanner should start in the next scan.
550
551 ``compact_cached_migrate_pfn``
552 The PFNs where compaction migration scanner should start in the next scan.
553 This array has two elements: the first one is used in ``MIGRATE_ASYNC`` mode,
554 and the other one is used in ``MIGRATE_SYNC`` mode.
555
556 ``compact_init_migrate_pfn``
557 The initial migration PFN which is initialized to 0 at boot time, and to the
558 first pageblock with migratable pages in the zone after a full compaction
559 finishes. It is used to check if a scan is a whole zone scan or not.
560
561 ``compact_init_free_pfn``
562 The initial free PFN which is initialized to 0 at boot time and to the last
563 pageblock with free ``MIGRATE_MOVABLE`` pages in the zone. It is used to check
564 if it is the start of a scan.
565
566 ``compact_considered``
567 The number of compactions attempted since last failure. It is reset in
568 ``defer_compaction()`` when a compaction fails to result in a page allocation
569 success. It is increased by 1 in ``compaction_deferred()`` when a compaction
570 should be skipped. ``compaction_deferred()`` is called before
571 ``compact_zone()`` is called, ``compaction_defer_reset()`` is called when
572 ``compact_zone()`` returns ``COMPACT_SUCCESS``, ``defer_compaction()`` is
573 called when ``compact_zone()`` returns ``COMPACT_PARTIAL_SKIPPED`` or
574 ``COMPACT_COMPLETE``.
575
576 ``compact_defer_shift``
577 The number of compactions skipped before trying again is
578 ``1<<compact_defer_shift``. It is increased by 1 in ``defer_compaction()``.
579 It is reset in ``compaction_defer_reset()`` when a direct compaction results
580 in a page allocation success. Its maximum value is ``COMPACT_MAX_DEFER_SHIFT``.
581
582 ``compact_order_failed``
583 The minimum compaction failed order. It is set in ``compaction_defer_reset()``
584 when a compaction succeeds and in ``defer_compaction()`` when a compaction
585 fails to result in a page allocation success.
586
587 ``compact_blockskip_flush``
588 Set to true when compaction migration scanner and free scanner meet, which
589 means the ``PB_compact_skip`` bits should be cleared.
590
591 ``contiguous``
592 Set to true when the zone is contiguous (in other words, no hole).
593
594 Statistics
595 ~~~~~~~~~~
596
597 ``vm_stat``
598 VM statistics for the zone. The items tracked are defined by
599 ``enum zone_stat_item``.
600
601 ``vm_numa_event``
602 VM NUMA event statistics for the zone. The items tracked are defined by
603 ``enum numa_stat_item``.
604
605 ``per_cpu_zonestats``
606 Per-CPU VM statistics for the zone. It records VM statistics and VM NUMA event
607 statistics on a per-CPU basis. It reduces updates to the global ``vm_stat``
608 and ``vm_numa_event`` fields of the zone to improve performance.
609
610 .. _pages:
611
612 Pages
613 =====
614
615 .. admonition:: Stub
616
617 This section is incomplete. Please list and describe the appropriate fields.
618
619 .. _folios:
620
621 Folios
622 ======
623
624 .. admonition:: Stub
625
626 This section is incomplete. Please list and describe the appropriate fields.
627
628 .. _initialization:
629
630 Initialization
631 ==============
632
633 .. admonition:: Stub
634
635 This section is incomplete. Please list and describe the appropriate fields.
636

3. 한국어 전문 번역

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

Physical-memory abstraction과 NUMA node

1-30

Linux는 매우 다양한 architecture에서 동작하므로 physical memory를 표현하는 architecture-independent abstraction이 필요합니다. 이 장은 실행 중인 system에서 physical memory를 관리하는 자료 구조를 설명합니다.

Memory management의 첫 핵심 개념은 `Non-Uniform Memory Access (NUMA)`입니다. Multi-core·multi-socket machine에서는 processor와의 `distance`에 따라 접근 비용이 다른 여러 bank로 memory를 구성할 수 있습니다. CPU마다 memory bank가 있거나 peripheral device 가까이에 DMA에 매우 적합한 bank가 있을 수 있습니다.

각 bank를 node라고 하며, architecture가 UMA이더라도 Linux에서는 `struct pglist_data`로 표현합니다. 이 구조는 항상 typedef인 `pg_data_t`로 참조합니다. 특정 node의 `pg_data_t`는 node ID `nid`를 받는 `NODE_DATA(nid)` macro로 참조할 수 있습니다.

NUMA architecture에서는 boot 초기 architecture-specific code가 node structure를 할당합니다. 보통 각 structure는 자신이 나타내는 memory bank에 local하게 할당됩니다. UMA architecture는 `contig_page_data`라는 static `pg_data_t` 하나만 사용합니다. Node에 관한 자세한 내용은 뒤의 `Nodes` section에서 설명합니다.

.. SPDX-License-Identifier: GPL-2.0

===============
Physical Memory
===============

Linux is available for a wide range of architectures so there is a need for an
architecture-independent abstraction to represent the physical memory. This
chapter describes the structures used to manage physical memory in a running
system.

The first principal concept prevalent in the memory management is
`Non-Uniform Memory Access (NUMA)
<https://en.wikipedia.org/wiki/Non-uniform_memory_access>`_.
With multi-core and multi-socket machines, memory may be arranged into banks
that incur a different cost to access depending on the “distance” from the
processor. For example, there might be a bank of memory assigned to each CPU or
a bank of memory very suitable for DMA near peripheral devices.

Each bank is called a node and the concept is represented under Linux by a
``struct pglist_data`` even if the architecture is UMA. This structure is
always referenced by its typedef ``pg_data_t``. A ``pg_data_t`` structure
for a particular node can be referenced by ``NODE_DATA(nid)`` macro where
``nid`` is the ID of that node.

For NUMA architectures, the node structures are allocated by the architecture
specific code early during boot. Usually, these structures are allocated
locally on the memory bank they represent. For UMA architectures, only one
static ``pg_data_t`` structure called ``contig_page_data`` is used. Nodes will
be discussed further in Section :ref:`Nodes <nodes>`

Physical address space와 zone 유형

31-80

전체 physical-address space는 memory 안의 range를 나타내는 zone 하나 이상으로 나뉩니다. Range는 보통 physical memory 접근에 관한 architecture 제약으로 결정됩니다. Node 안에서 특정 zone에 해당하는 memory range는 `struct zone`이 설명합니다.

  • `ZONE_DMA`와 `ZONE_DMA32`: 주소 지정 가능한 memory 전체에 접근하지 못하는 peripheral device의 DMA에 알맞은 memory를 역사적으로 나타냈습니다. 현재는 DMA 요구에 맞는 memory를 얻는 더 견고한 interface가 있으며 `Documentation/core-api/dma-api.rst`에 설명되어 있습니다. 그래도 두 zone은 접근 방식에 제약이 있는 memory range를 계속 나타냅니다. Architecture에 따라 `CONFIG_ZONE_DMA`, `CONFIG_ZONE_DMA32`로 둘 중 하나 또는 둘 다 build 때 disable할 수 있습니다. DMA address 한계가 다른 peripheral을 지원하는 일부 64bit platform은 두 zone이 모두 필요할 수 있습니다.
  • `ZONE_NORMAL`: Kernel이 항상 접근할 수 있는 일반 memory입니다. DMA device가 주소 지정 가능한 memory 전체로 transfer할 수 있다면 이 zone page에도 DMA operation을 수행할 수 있습니다. 항상 enable됩니다.
  • `ZONE_HIGHMEM`: Kernel page table에 permanent mapping이 없는 physical memory 부분입니다. Kernel은 temporary mapping을 통해서만 이 zone에 접근합니다. 일부 32bit architecture에서만 사용할 수 있고 `CONFIG_HIGHMEM`으로 enable합니다.
  • `ZONE_MOVABLE`: `ZONE_NORMAL`처럼 정상적으로 접근할 수 있는 memory입니다. 차이는 page 대부분의 content를 이동할 수 있다는 점입니다. Virtual address는 바뀌지 않지만 content가 다른 physical page로 이동할 수 있습니다. Memory hotplug 때 채우는 경우가 많고, boot 때 `kernelcore`, `movablecore`, `movable_node` kernel command-line parameter로 채울 수도 있습니다. `Documentation/mm/page_migration.rst`와 `Documentation/admin-guide/mm/memory-hotplug.rst`를 참조하십시오.
  • `ZONE_DEVICE`: PMEM이나 GPU 같은 device에 있는 memory를 나타냅니다. RAM zone과 특성이 다르며, device driver가 지정한 physical-address range에 `struct page`와 memory-map service를 제공하려고 존재합니다. `CONFIG_ZONE_DEVICE`로 enable합니다.

많은 kernel operation은 `ZONE_NORMAL`에서만 수행할 수 있으므로 가장 성능에 민감한 zone입니다. Node와 zone extent의 관계는 firmware가 보고한 physical-memory map, memory addressing architecture 제약, 특정 kernel command-line parameter로 결정됩니다.


The entire physical address space is partitioned into one or more blocks
called zones which represent ranges within memory. These ranges are usually
determined by architectural constraints for accessing the physical memory.
The memory range within a node that corresponds to a particular zone is
described by a ``struct zone``. Each zone has
one of the types described below.

* ``ZONE_DMA`` and ``ZONE_DMA32`` historically represented memory suitable for
  DMA by peripheral devices that cannot access all of the addressable
  memory. For many years there are better more and robust interfaces to get
  memory with DMA specific requirements (Documentation/core-api/dma-api.rst),
  but ``ZONE_DMA`` and ``ZONE_DMA32`` still represent memory ranges that have
  restrictions on how they can be accessed.
  Depending on the architecture, either of these zone types or even they both
  can be disabled at build time using ``CONFIG_ZONE_DMA`` and
  ``CONFIG_ZONE_DMA32`` configuration options. Some 64-bit platforms may need
  both zones as they support peripherals with different DMA addressing
  limitations.

* ``ZONE_NORMAL`` is for normal memory that can be accessed by the kernel all
  the time. DMA operations can be performed on pages in this zone if the DMA
  devices support transfers to all addressable memory. ``ZONE_NORMAL`` is
  always enabled.

* ``ZONE_HIGHMEM`` is the part of the physical memory that is not covered by a
  permanent mapping in the kernel page tables. The memory in this zone is only
  accessible to the kernel using temporary mappings. This zone is available
  only on some 32-bit architectures and is enabled with ``CONFIG_HIGHMEM``.

* ``ZONE_MOVABLE`` is for normal accessible memory, just like ``ZONE_NORMAL``.
  The difference is that the contents of most pages in ``ZONE_MOVABLE`` is
  movable. That means that while virtual addresses of these pages do not
  change, their content may move between different physical pages. Often
  ``ZONE_MOVABLE`` is populated during memory hotplug, but it may be
  also populated on boot using one of ``kernelcore``, ``movablecore`` and
  ``movable_node`` kernel command line parameters. See
  Documentation/mm/page_migration.rst and
  Documentation/admin-guide/mm/memory-hotplug.rst for additional details.

* ``ZONE_DEVICE`` represents memory residing on devices such as PMEM and GPU.
  It has different characteristics than RAM zone types and it exists to provide
  :ref:`struct page <Pages>` and memory map services for device driver
  identified physical address ranges. ``ZONE_DEVICE`` is enabled with
  configuration option ``CONFIG_ZONE_DEVICE``.

It is important to note that many kernel operations can only take place using
``ZONE_NORMAL`` so it is the most performance critical zone. Zones are
discussed further in Section :ref:`Zones <zones>`.

Node와 zone extent 예제

81-135

첫 예제는 RAM 2GB인 x86 UMA machine의 32bit kernel입니다. Memory 전체가 node 0에 있으며 `ZONE_DMA`, `ZONE_NORMAL`, `ZONE_HIGHMEM` 세 zone으로 나뉩니다. 주소 0~16MB는 DMA, 16~896MB는 NORMAL, 896MB~2GB는 HIGHMEM입니다.

두 번째 예제는 RAM 16GB가 node 두 개에 똑같이 나뉜 arm64 machine입니다. Kernel은 `ZONE_DMA` 없이 `ZONE_DMA32`를 enable했고 `movablecore=80%`로 boot했습니다. Node 0에는 `ZONE_DMA32`, `ZONE_NORMAL`, `ZONE_MOVABLE`이 있고 node 1에는 `ZONE_NORMAL`, `ZONE_MOVABLE`이 있습니다. 원문 주소 표기는 1GB에서 17GB 범위입니다.

세 번째 예제처럼 memory bank가 interleaving node에 속할 수도 있습니다. RAM 16GB를 4GB bank 네 개로 나눈 x86 machine에서 짝수 bank는 node 0, 홀수 bank는 node 1에 속합니다. 이 경우 node 0의 span은 0~12GB이고 node 1의 span은 4~16GB입니다. Span에는 중간 hole 또는 다른 node 소유 range가 포함될 수 있습니다.

The relation between node and zone extents is determined by the physical memory
map reported by the firmware, architectural constraints for memory addressing
and certain parameters in the kernel command line.

For example, with 32-bit kernel on an x86 UMA machine with 2 Gbytes of RAM the
entire memory will be on node 0 and there will be three zones: ``ZONE_DMA``,
``ZONE_NORMAL`` and ``ZONE_HIGHMEM``::

  0                                                            2G
  +-------------------------------------------------------------+
  |                            node 0                           |
  +-------------------------------------------------------------+

  0         16M                    896M                        2G
  +----------+-----------------------+--------------------------+
  | ZONE_DMA |      ZONE_NORMAL      |       ZONE_HIGHMEM       |
  +----------+-----------------------+--------------------------+


With a kernel built with ``ZONE_DMA`` disabled and ``ZONE_DMA32`` enabled and
booted with ``movablecore=80%`` parameter on an arm64 machine with 16 Gbytes of
RAM equally split between two nodes, there will be ``ZONE_DMA32``,
``ZONE_NORMAL`` and ``ZONE_MOVABLE`` on node 0, and ``ZONE_NORMAL`` and
``ZONE_MOVABLE`` on node 1::


  1G                                9G                         17G
  +--------------------------------+ +--------------------------+
  |              node 0            | |          node 1          |
  +--------------------------------+ +--------------------------+

  1G       4G        4200M          9G          9320M          17G
  +---------+----------+-----------+ +------------+-------------+
  |  DMA32  |  NORMAL  |  MOVABLE  | |   NORMAL   |   MOVABLE   |
  +---------+----------+-----------+ +------------+-------------+


Memory banks may belong to interleaving nodes. In the example below an x86
machine has 16 Gbytes of RAM in 4 memory banks, even banks belong to node 0
and odd banks belong to node 1::


  0              4G              8G             12G            16G
  +-------------+ +-------------+ +-------------+ +-------------+
  |    node 0   | |    node 1   | |    node 0   | |    node 1   |
  +-------------+ +-------------+ +-------------+ +-------------+

  0   16M      4G
  +-----+-------+ +-------------+ +-------------+ +-------------+
  | DMA | DMA32 | |    NORMAL   | |    NORMAL   | |    NORMAL   |
  +-----+-------+ +-------------+ +-------------+ +-------------+

In this case node 0 will span from 0 to 12 Gbytes and node 1 will span from
4 to 16 Gbytes.

Node allocation policy와 node_states

136-202

각 memory node는 `struct pglist_data`의 typedef인 `pg_data_t`로 설명합니다. Page를 할당할 때 Linux는 기본적으로 실행 CPU와 가장 가까운 node에서 memory를 얻는 node-local policy를 사용합니다. Process는 같은 CPU에서 계속 실행되는 경향이 있어 current node memory를 사용할 가능성이 큽니다. User는 `Documentation/admin-guide/mm/numa_memory_policy.rst`의 방법으로 allocation policy를 제어할 수 있습니다.

대부분의 NUMA architecture는 node-structure pointer array를 유지합니다. Architecture-specific code가 firmware physical-memory map을 parse하는 boot 초기에 실제 structure를 할당합니다. Node initialization 대부분은 조금 뒤 `free_area_init()`에서 수행하며 뒤의 `Initialization` section에서 언급합니다.

Kernel은 node structure와 함께 `node_states`라는 `nodemask_t` bitmask array를 유지합니다. 각 bitmask는 `enum node_states`가 정의한 특정 속성을 가진 node set입니다.

  • `N_POSSIBLE`: 언젠가 online이 될 수 있는 node입니다.
  • `N_ONLINE`: 현재 online인 node입니다.
  • `N_NORMAL_MEMORY`: regular memory가 있는 node입니다.
  • `N_HIGH_MEMORY`: regular 또는 high memory가 있는 node입니다. `CONFIG_HIGHMEM`이 disable되면 `N_NORMAL_MEMORY`의 alias입니다.
  • `N_MEMORY`: regular, high, movable 중 어떤 형태로든 memory가 있는 node입니다.
  • `N_CPU`: CPU가 하나 이상 있는 node입니다.
  • `N_GENERIC_INITIATOR`: Generic Initiator가 하나 이상 있는 node입니다.

위 속성을 가진 node마다 `node_states[<property>]` bitmask에서 node ID에 해당하는 bit를 set합니다. 예를 들어 normal memory와 CPU가 있는 node 2는 `N_POSSIBLE`, `N_ONLINE`, `N_NORMAL_MEMORY`, `N_HIGH_MEMORY`, `N_MEMORY`, `N_CPU` mask의 bit 2가 set됩니다.

Nodemask operation은 `include/linux/nodemask.h`를 참조하십시오. Nodemask는 `for_each_node()`와 `for_each_online_node()` 같은 node traversal macro를 제공하는 데도 사용합니다.

for_each_online_node(nid) {
        pg_data_t *pgdat = NODE_DATA(nid);

        foo(pgdat);
}
.. _nodes:

Nodes
=====

As we have mentioned, each node in memory is described by a ``pg_data_t`` which
is a typedef for a ``struct pglist_data``. When allocating a page, by default
Linux uses a node-local allocation policy to allocate memory from the node
closest to the running CPU. As processes tend to run on the same CPU, it is
likely the memory from the current node will be used. The allocation policy can
be controlled by users as described in
Documentation/admin-guide/mm/numa_memory_policy.rst.

Most NUMA architectures maintain an array of pointers to the node
structures. The actual structures are allocated early during boot when
architecture specific code parses the physical memory map reported by the
firmware. The bulk of the node initialization happens slightly later in the
boot process by free_area_init() function, described later in Section
:ref:`Initialization <initialization>`.


Along with the node structures, kernel maintains an array of ``nodemask_t``
bitmasks called ``node_states``. Each bitmask in this array represents a set of
nodes with particular properties as defined by ``enum node_states``:

``N_POSSIBLE``
  The node could become online at some point.
``N_ONLINE``
  The node is online.
``N_NORMAL_MEMORY``
  The node has regular memory.
``N_HIGH_MEMORY``
  The node has regular or high memory. When ``CONFIG_HIGHMEM`` is disabled
  aliased to ``N_NORMAL_MEMORY``.
``N_MEMORY``
  The node has memory(regular, high, movable)
``N_CPU``
  The node has one or more CPUs
``N_GENERIC_INITIATOR``
  The node has one or more Generic Initiators

For each node that has a property described above, the bit corresponding to the
node ID in the ``node_states[<property>]`` bitmask is set.

For example, for node 2 with normal memory and CPUs, bit 2 will be set in ::

  node_states[N_POSSIBLE]
  node_states[N_ONLINE]
  node_states[N_NORMAL_MEMORY]
  node_states[N_HIGH_MEMORY]
  node_states[N_MEMORY]
  node_states[N_CPU]

For various operations possible with nodemasks please refer to
``include/linux/nodemask.h``.

Among other things, nodemasks are used to provide macros for node traversal,
namely ``for_each_node()`` and ``for_each_online_node()``.

For instance, to call a function foo() for each online node::

        for_each_online_node(nid) {
                pg_data_t *pgdat = NODE_DATA(nid);

                foo(pgdat);
        }

struct pglist_data의 일반 field

203-272

Node structure `struct pglist_data`는 `include/linux/mmzone.h`에 선언되어 있습니다. 일반 field는 다음과 같습니다.

  • `node_zones`: 이 node의 zone 전체 목록입니다. 모든 zone이 populated되지는 않을 수 있습니다. 이 node와 다른 node의 `node_zonelists`가 참조합니다.
  • `node_zonelists`: 모든 node의 모든 zone 목록입니다. Allocation이 선호할 zone 순서를 정합니다. Core memory-management structure 초기화 때 `mm/page_alloc.c`의 `build_zonelists()`가 설정합니다.
  • `nr_zones`: 이 node에서 populated된 zone 수입니다.
  • `node_mem_map`: FLATMEM memory model을 쓰는 UMA system에서 node 0의 physical frame 각각을 나타내는 `struct page` array입니다.
  • `node_page_ext`: FLATMEM UMA system에서 node 0의 `struct page` extension array입니다. `CONFIG_PAGE_EXTENSION`을 enable한 kernel에서만 사용할 수 있습니다.
  • `node_start_pfn`: 이 node 첫 page frame의 PFN입니다.
  • `node_present_pages`: 이 node에 실제 존재하는 physical page 총수입니다.
  • `node_spanned_pages`: hole을 포함한 physical-page range 전체 크기입니다.
  • `node_size_lock`: node extent를 정의하는 field를 보호합니다. `CONFIG_MEMORY_HOTPLUG` 또는 `CONFIG_DEFERRED_STRUCT_PAGE_INIT` 중 하나 이상을 enable했을 때만 정의됩니다. 두 config를 직접 검사하지 않고 lock을 다루도록 `pgdat_resize_lock()`과 `pgdat_resize_unlock()`을 제공합니다.
  • `node_id`: 0부터 시작하는 node ID, 즉 NID입니다.
  • `totalreserve_pages`: userspace allocation이 사용할 수 없는 node별 reserve page 수입니다.
  • `first_deferred_pfn`: 큰 machine에서 memory initialization을 미룰 때 앞으로 초기화해야 하는 첫 PFN입니다. `CONFIG_DEFERRED_STRUCT_PAGE_INIT`에서만 정의됩니다.
  • `deferred_split_queue`: split이 연기된 huge page의 node별 queue입니다. `CONFIG_TRANSPARENT_HUGEPAGE`에서만 정의됩니다.
  • `__lruvec`: LRU list와 관련 parameter를 담는 node별 lruvec입니다. Memory cgroup이 disable됐을 때만 사용합니다. 직접 접근하지 말고 `mem_cgroup_lruvec()`로 lruvec을 찾아야 합니다.
Node structure
--------------

The nodes structure ``struct pglist_data`` is declared in
``include/linux/mmzone.h``. Here we briefly describe fields of this
structure:

General
~~~~~~~

``node_zones``
  The zones for this node.  Not all of the zones may be populated, but it is
  the full list. It is referenced by this node's node_zonelists as well as
  other node's node_zonelists.

``node_zonelists``
  The list of all zones in all nodes. This list defines the order of zones
  that allocations are preferred from. The ``node_zonelists`` is set up by
  ``build_zonelists()`` in ``mm/page_alloc.c`` during the initialization of
  core memory management structures.

``nr_zones``
  Number of populated zones in this node.

``node_mem_map``
  For UMA systems that use FLATMEM memory model the 0's node
  ``node_mem_map`` is array of struct pages representing each physical frame.

``node_page_ext``
  For UMA systems that use FLATMEM memory model the 0's node
  ``node_page_ext`` is array of extensions of struct pages. Available only
  in the kernels built with ``CONFIG_PAGE_EXTENSION`` enabled.

``node_start_pfn``
  The page frame number of the starting page frame in this node.

``node_present_pages``
  Total number of physical pages present in this node.

``node_spanned_pages``
  Total size of physical page range, including holes.

``node_size_lock``
  A lock that protects the fields defining the node extents. Only defined when
  at least one of ``CONFIG_MEMORY_HOTPLUG`` or
  ``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` configuration options are enabled.
  ``pgdat_resize_lock()`` and ``pgdat_resize_unlock()`` are provided to
  manipulate ``node_size_lock`` without checking for ``CONFIG_MEMORY_HOTPLUG``
  or ``CONFIG_DEFERRED_STRUCT_PAGE_INIT``.

``node_id``
  The Node ID (NID) of the node, starts at 0.

``totalreserve_pages``
  This is a per-node reserve of pages that are not available to userspace
  allocations.

``first_deferred_pfn``
  If memory initialization on large machines is deferred then this is the first
  PFN that needs to be initialized. Defined only when
  ``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` is enabled

``deferred_split_queue``
  Per-node queue of huge pages that their split was deferred. Defined only when ``CONFIG_TRANSPARENT_HUGEPAGE`` is enabled.

``__lruvec``
  Per-node lruvec holding LRU lists and related parameters. Used only when
  memory cgroups are disabled. It should not be accessed directly, use
  ``mem_cgroup_lruvec()`` to look up lruvecs instead.

Node reclaim·compaction·통계 field

273-329

Reclaim control은 `Documentation/mm/page_reclaim.rst`도 참조하십시오.

  • `kswapd`: node별 kswapd kernel-thread instance입니다.
  • `kswapd_wait`, `pfmemalloc_wait`, `reclaim_wait`: memory-reclaim task를 동기화하는 workqueue입니다.
  • `nr_writeback_throttled`: dirty page가 clean되기를 기다리며 throttle된 task 수입니다.
  • `nr_reclaim_start`: reclaim이 writeback을 기다리며 throttle된 동안 write된 page 수입니다.
  • `kswapd_order`: kswapd가 reclaim하려는 order를 제어합니다.
  • `kswapd_highest_zoneidx`: kswapd가 reclaim할 가장 높은 zone index입니다.
  • `kswapd_failures`: kswapd가 page를 하나도 reclaim하지 못한 실행 횟수입니다.
  • `min_unmapped_pages`: reclaim할 수 없도록 남겨 둘 최소 unmapped file-backed page 수입니다. `vm.min_unmapped_ratio` sysctl이 정하며 `CONFIG_NUMA`에서만 정의됩니다.
  • `min_slab_pages`: reclaim할 수 없도록 남겨 둘 최소 SLAB page 수입니다. `vm.min_slab_ratio` sysctl이 정하며 `CONFIG_NUMA`에서만 정의됩니다.
  • `flags`: reclaim 동작을 제어하는 flag입니다.

Node compaction control field는 다음과 같습니다.

  • `kcompactd_max_order`: kcompactd가 달성하려 시도할 page order입니다.
  • `kcompactd_highest_zoneidx`: kcompactd가 compact할 가장 높은 zone index입니다.
  • `kcompactd_wait`: memory-compaction task를 동기화하는 workqueue입니다.
  • `kcompactd`: node별 kcompactd kernel-thread instance입니다.
  • `proactive_compact_trigger`: proactive compaction enable 여부를 정하며 `vm.compaction_proactiveness` sysctl로 제어합니다.
Reclaim control
~~~~~~~~~~~~~~~

See also Documentation/mm/page_reclaim.rst.

``kswapd``
  Per-node instance of kswapd kernel thread.

``kswapd_wait``, ``pfmemalloc_wait``, ``reclaim_wait``
  Workqueues used to synchronize memory reclaim tasks

``nr_writeback_throttled``
  Number of tasks that are throttled waiting on dirty pages to clean.

``nr_reclaim_start``
  Number of pages written while reclaim is throttled waiting for writeback.

``kswapd_order``
  Controls the order kswapd tries to reclaim

``kswapd_highest_zoneidx``
  The highest zone index to be reclaimed by kswapd

``kswapd_failures``
  Number of runs kswapd was unable to reclaim any pages

``min_unmapped_pages``
  Minimal number of unmapped file backed pages that cannot be reclaimed.
  Determined by ``vm.min_unmapped_ratio`` sysctl. Only defined when
  ``CONFIG_NUMA`` is enabled.

``min_slab_pages``
  Minimal number of SLAB pages that cannot be reclaimed. Determined by
  ``vm.min_slab_ratio sysctl``. Only defined when ``CONFIG_NUMA`` is enabled

``flags``
  Flags controlling reclaim behavior.

Compaction control
~~~~~~~~~~~~~~~~~~

``kcompactd_max_order``
  Page order that kcompactd should try to achieve.

``kcompactd_highest_zoneidx``
  The highest zone index to be compacted by kcompactd.

``kcompactd_wait``
  Workqueue used to synchronize memory compaction tasks.

``kcompactd``
  Per-node instance of kcompactd kernel thread.

``proactive_compact_trigger``
  Determines if proactive compaction is enabled. Controlled by
  ``vm.compaction_proactiveness`` sysctl.

Zone allocation 순서와 PCP

330-371

`per_cpu_nodestats`는 node의 CPU별 VM statistic이고 `vm_stat`은 node의 VM statistic입니다.

각 memory zone은 자신이 속한 node의 `node_zones` array element인 `struct zone`으로 설명합니다. `struct zone`은 page allocator의 core data structure입니다. Zone은 physical-memory range를 나타내며 hole을 포함할 수 있습니다.

Page allocator는 allocation에 지정된 GFP flag를 보고 해당 node에서 사용할 수 있는 가장 높은 zone을 결정합니다. 먼저 그 zone에서 할당하고, 요청량을 얻지 못하면 node의 다음 낮은 zone으로 내려가 최하위 zone까지 계속합니다. 예를 들어 `ZONE_DMA32`, `ZONE_NORMAL`, `ZONE_MOVABLE`이 있고 최고 zone이 `ZONE_MOVABLE`이면 순서는 `ZONE_MOVABLE > ZONE_NORMAL > ZONE_DMA32`입니다.

Runtime에 zone의 free page는 Per-CPU Pageset, 즉 PCP 또는 zone free area에 있습니다. PCP는 잦은 allocation과 free 대부분을 각 CPU에서 local하게 처리해, 특히 core가 많은 system에서 성능과 확장성을 높입니다.

Kernel page allocator는 먼저 PCP를 사용하고 실패하면 buddy allocator로 fallback하는 2단계 전략을 씁니다. PCP와 buddy allocator가 관리하는 global free area 사이에서 page를 batch 단위로 옮겨 global buddy allocator와 잦게 상호작용하는 overhead를 줄입니다.

Architecture-specific code는 `free_area_init()`을 호출해 zone을 초기화합니다.

Statistics
~~~~~~~~~~

``per_cpu_nodestats``
  Per-CPU VM statistics for the node

``vm_stat``
  VM statistics for the node.

.. _zones:

Zones
=====
As we have mentioned, each zone in memory is described by a ``struct zone``
which is an element of the ``node_zones`` array of the node it belongs to.
``struct zone`` is the core data structure of the page allocator. A zone
represents a range of physical memory and may have holes.

The page allocator uses the GFP flags, see :ref:`mm-api-gfp-flags`, specified by
a memory allocation to determine the highest zone in a node from which the
memory allocation can allocate memory. The page allocator first allocates memory
from that zone, if the page allocator can't allocate the requested amount of
memory from the zone, it will allocate memory from the next lower zone in the
node, the process continues up to and including the lowest zone. For example, if
a node contains ``ZONE_DMA32``, ``ZONE_NORMAL`` and ``ZONE_MOVABLE`` and the
highest zone of a memory allocation is ``ZONE_MOVABLE``, the order of the zones
from which the page allocator allocates memory is ``ZONE_MOVABLE`` >
``ZONE_NORMAL`` > ``ZONE_DMA32``.

At runtime, free pages in a zone are in the Per-CPU Pagesets (PCP) or free areas
of the zone. The Per-CPU Pagesets are a vital mechanism in the kernel's memory
management system. By handling most frequent allocations and frees locally on
each CPU, the Per-CPU Pagesets improve performance and scalability, especially
on systems with many cores. The page allocator in the kernel employs a two-step
strategy for memory allocation, starting with the Per-CPU Pagesets before
falling back to the buddy allocator. Pages are transferred between the Per-CPU
Pagesets and the global free areas (managed by the buddy allocator) in batches.
This minimizes the overhead of frequent interactions with the global buddy
allocator.

Architecture specific code calls free_area_init() to initializes zones.

struct zone 일반 field: watermark와 PCP

372-450

Zone structure `struct zone`은 `include/linux/mmzone.h`에 정의되어 있습니다.

  • `_watermark`: zone watermark입니다. Free page가 min 아래이면 boost를 무시하고 allocation이 direct reclaim과 direct compaction을 일으킬 수 있으며 direct reclaim throttle에도 사용합니다. Low 아래이면 kswapd를 깨웁니다. High 위이고 `sysctl_numa_balancing_mode`의 `NUMA_BALANCING_MEMORY_TIERING` bit가 set되지 않았으면 kswapd가 reclaim을 멈추고 zone이 balanced됩니다. Promo watermark는 memory tiering과 NUMA balancing에 사용하며 해당 bit가 set된 경우 free page가 promo 위이면 kswapd가 reclaim을 멈춥니다. `__setup_per_zone_wmarks()`가 설정합니다. Min은 `vm.min_free_kbytes`, 나머지 세 watermark의 간격은 `vm.watermark_scale_factor`를 고려해 계산합니다.
  • `watermark_boost`: 앞으로 fallback할 가능성을 낮추도록 reclaim pressure를 높이고, node 전체가 balanced라 자연스럽게 깨지 않을 kswapd를 지금 깨우기 위해 watermark에 더하는 page 수입니다.
  • `nr_reserved_highatomic`: high-order atomic allocation용으로 reserve한 page 수입니다.
  • `nr_free_highatomic`: reserved highatomic pageblock의 free page 수입니다.
  • `lowmem_reserve`: allocation별로 이 zone에 reserve한 memory 양의 array입니다. Allocation 최고 zone이 `ZONE_MOVABLE`이면 이 zone에서 시도할 때 reserve는 `lowmem_reserve[ZONE_MOVABLE]`입니다. Highmem을 쓸 수 있는 allocation이 lowmem을 너무 많이 소비하지 않게 합니다. Highmem machine의 특수 workload에서는 process memory를 lowmem zone에서 할당하면 `mlock()` 또는 swapspace 부재로 pin될 수 있어 위험합니다. `vm.lowmem_reserve_ratio`가 lower-zone 방어 강도를 정하고, sysctl 변경 시 `setup_per_zone_lowmem_reserve()`가 array를 다시 계산합니다.
  • `node`: zone이 속한 node index입니다. 원문 설명상 UMA system에는 node가 하나뿐이므로 `CONFIG_NUMA`일 때만 사용할 수 있습니다.
  • `zone_pgdat`: zone이 속한 node의 `struct pglist_data` pointer입니다.
  • `per_cpu_pageset`: `setup_zone_pageset()`이 할당하고 초기화한 PCP pointer입니다. 잦은 allocation과 free를 CPU local로 처리해 많은 core가 있는 system의 성능과 확장성을 높입니다.
  • `pageset_high_min`: 빠른 접근을 위해 PCP의 `high_min`으로 copy됩니다.
  • `pageset_high_max`: 빠른 접근을 위해 PCP의 `high_max`로 copy됩니다.
  • `pageset_batch`: 빠른 접근을 위해 PCP의 `batch`로 copy됩니다. `batch`, `high_min`, `high_max`는 lock 한 번으로 PCP가 buddy allocator에서 가져올 element 수를 계산하고, page free 과정에서 PCP가 buddy allocator에 page를 반환할지도 결정합니다.
Zone structure
--------------
The zones structure ``struct zone`` is defined in ``include/linux/mmzone.h``.
Here we briefly describe fields of this structure:

General
~~~~~~~

``_watermark``
  The watermarks for this zone. When the amount of free pages in a zone is below
  the min watermark, boosting is ignored, an allocation may trigger direct
  reclaim and direct compaction, it is also used to throttle direct reclaim.
  When the amount of free pages in a zone is below the low watermark, kswapd is
  woken up. When the amount of free pages in a zone is above the high watermark,
  kswapd stops reclaiming (a zone is balanced) when the
  ``NUMA_BALANCING_MEMORY_TIERING`` bit of ``sysctl_numa_balancing_mode`` is not
  set. The promo watermark is used for memory tiering and NUMA balancing. When
  the amount of free pages in a zone is above the promo watermark, kswapd stops
  reclaiming when the ``NUMA_BALANCING_MEMORY_TIERING`` bit of
  ``sysctl_numa_balancing_mode`` is set. The watermarks are set by
  ``__setup_per_zone_wmarks()``. The min watermark is calculated according to
  ``vm.min_free_kbytes`` sysctl. The other three watermarks are set according
  to the distance between two watermarks. The distance itself is calculated
  taking ``vm.watermark_scale_factor`` sysctl into account.

``watermark_boost``
  The number of pages which are used to boost watermarks to increase reclaim
  pressure to reduce the likelihood of future fallbacks and wake kswapd now
  as the node may be balanced overall and kswapd will not wake naturally.

``nr_reserved_highatomic``
  The number of pages which are reserved for high-order atomic allocations.

``nr_free_highatomic``
  The number of free pages in reserved highatomic pageblocks

``lowmem_reserve``
  The array of the amounts of the memory reserved in this zone for memory
  allocations. For example, if the highest zone a memory allocation can
  allocate memory from is ``ZONE_MOVABLE``, the amount of memory reserved in
  this zone for this allocation is ``lowmem_reserve[ZONE_MOVABLE]`` when
  attempting to allocate memory from this zone. This is a mechanism the page
  allocator uses to prevent allocations which could use ``highmem`` from using
  too much ``lowmem``. For some specialised workloads on ``highmem`` machines,
  it is dangerous for the kernel to allow process memory to be allocated from
  the ``lowmem`` zone. This is because that memory could then be pinned via the
  ``mlock()`` system call, or by unavailability of swapspace.
  ``vm.lowmem_reserve_ratio`` sysctl determines how aggressive the kernel is in
  defending these lower zones. This array is recalculated by
  ``setup_per_zone_lowmem_reserve()`` at runtime if ``vm.lowmem_reserve_ratio``
  sysctl changes.

``node``
  The index of the node this zone belongs to. Available only when
  ``CONFIG_NUMA`` is enabled because there is only one zone in a UMA system.

``zone_pgdat``
  Pointer to the ``struct pglist_data`` of the node this zone belongs to.

``per_cpu_pageset``
  Pointer to the Per-CPU Pagesets (PCP) allocated and initialized by
  ``setup_zone_pageset()``. By handling most frequent allocations and frees
  locally on each CPU, PCP improves performance and scalability on systems with
  many cores.

``pageset_high_min``
  Copied to the ``high_min`` of the Per-CPU Pagesets for faster access.

``pageset_high_max``
  Copied to the ``high_max`` of the Per-CPU Pagesets for faster access.

``pageset_batch``
  Copied to the ``batch`` of the Per-CPU Pagesets for faster access. The
  ``batch``, ``high_min`` and ``high_max`` of the Per-CPU Pagesets are used to
  calculate the number of elements the Per-CPU Pagesets obtain from the buddy
  allocator under a single hold of the lock for efficiency. They are also used
  to decide if the Per-CPU Pagesets return pages to the buddy allocator in page
  free process.

struct zone 일반 field: extent와 buddy state

451-544
  • `pageblock_flags`: zone pageblock의 flag pointer입니다. Flag 목록은 `include/linux/pageblock-flags.h`에 있고 `setup_usemap()`이 memory를 할당합니다. Pageblock마다 `NR_PAGEBLOCK_BITS` bit를 차지합니다. `CONFIG_FLATMEM`에서만 정의되며 `CONFIG_SPARSEMEM`에서는 flag를 `mem_section`에 저장합니다.
  • `zone_start_pfn`: zone 시작 PFN이며 `calculate_node_totalpages()`가 초기화합니다.
  • `managed_pages`: buddy system이 관리하는 present page 수입니다. `managed_pages = present_pages - reserved_pages`이며 `reserved_pages`에는 memblock allocator가 할당한 page가 포함됩니다. Page allocator와 VM scanner가 watermark와 threshold를 계산할 때 사용해야 합니다. `atomic_long_xxx()`로 접근합니다. `free_area_init_core()`에서 초기화하고 memblock allocator가 buddy system에 page를 free할 때 다시 초기화합니다.
  • `spanned_pages`: hole을 포함해 zone이 span하는 전체 page 수입니다. `spanned_pages = zone_end_pfn - zone_start_pfn`이며 `calculate_node_totalpages()`가 초기화합니다.
  • `present_pages`: zone에 실제 존재하는 physical page 수입니다. `present_pages = spanned_pages - absent_pages`, 여기서 absent page는 hole의 page입니다. Memory hotplug 또는 power-management logic이 `present_pages - managed_pages`로 unmanaged page를 파악할 수 있습니다. Runtime write는 `mem_hotplug_begin/done()`으로 보호해야 합니다. Drift를 허용할 수 없는 reader는 `get_online_mems()`로 안정된 값을 얻어야 합니다. `calculate_node_totalpages()`가 초기화합니다.
  • `present_early_pages`: early boot부터 사용 가능한 memory에 있는 present page 수이며 hotplug memory는 제외합니다. `CONFIG_MEMORY_HOTPLUG`에서만 정의되고 `calculate_node_totalpages()`가 초기화합니다.
  • `cma_pages`: CMA용 reserve page입니다. CMA가 사용하지 않을 때는 `ZONE_MOVABLE`처럼 동작합니다. `CONFIG_CMA`에서만 정의됩니다.
  • `name`: `zone_names` array의 대응 element를 가리키는 zone 이름 pointer입니다.
  • `nr_isolate_pageblock`: isolate된 pageblock 수입니다. Pageblock migratetype을 race 상태로 읽어 free-page count가 잘못되는 문제를 해결하는 데 사용합니다. `zone->lock`이 보호하며 `CONFIG_MEMORY_ISOLATION`에서만 정의됩니다.
  • `span_seqlock`: `zone_start_pfn`과 `spanned_pages`를 보호하는 seqlock입니다. Main allocator path에서 `zone->lock` 밖에서 읽어야 하지만 write는 매우 드물어 seqlock을 사용합니다. `CONFIG_MEMORY_HOTPLUG`에서만 정의됩니다.
  • `initialized`: zone 초기화 여부 flag이며 boot 때 `init_currently_empty_zone()`이 set합니다.
  • `free_area`: 2의 거듭제곱인 특정 order마다 element가 있는 free-area array입니다. Buddy allocator는 충분한 가장 작은 block을 찾고, 요청보다 크면 필요한 크기에 이를 때까지 다음 작은 block으로 재귀적으로 split합니다. Page를 free하면 buddy와 merge해 더 큰 block을 만들 수 있습니다. `zone_init_free_lists()`가 초기화합니다.
  • `unaccepted_pages`: accept해야 할 page 목록입니다. 목록의 모든 page는 `MAX_PAGE_ORDER`입니다. `CONFIG_UNACCEPTED_MEMORY`에서만 정의됩니다.
  • `flags`: `enum zone_flags`가 정의한 하위 3bit를 씁니다. Bit 0 `ZONE_BOOSTED_WATERMARK`는 최근 watermark가 boost됐음을 나타내고 kswapd를 깨울 때 clear합니다. Bit 1 `ZONE_RECLAIM_ACTIVE`는 kswapd가 zone을 scan 중일 수 있음을 뜻합니다. Bit 2 `ZONE_BELOW_HIGH`는 zone이 high watermark 아래임을 뜻합니다.
  • `lock`: zone별 page allocator 내부 자료 구조, 특히 `free_area`를 보호하는 main lock입니다.
  • `percpu_drift_mark`: free page가 이 지점보다 적으면 per-CPU counter drift 때문에 watermark를 침범하지 않도록 free-page 수를 읽을 때 추가 단계를 수행합니다. `refresh_zone_stat_thresholds()`가 갱신합니다.
``pageblock_flags``
  The pointer to the flags for the pageblocks in the zone (see
  ``include/linux/pageblock-flags.h`` for flags list). The memory is allocated
  in ``setup_usemap()``. Each pageblock occupies ``NR_PAGEBLOCK_BITS`` bits.
  Defined only when ``CONFIG_FLATMEM`` is enabled. The flags is stored in
  ``mem_section`` when ``CONFIG_SPARSEMEM`` is enabled.

``zone_start_pfn``
  The start pfn of the zone. It is initialized by
  ``calculate_node_totalpages()``.

``managed_pages``
  The present pages managed by the buddy system, which is calculated as:
  ``managed_pages`` = ``present_pages`` - ``reserved_pages``, ``reserved_pages``
  includes pages allocated by the memblock allocator. It should be used by page
  allocator and vm scanner to calculate all kinds of watermarks and thresholds.
  It is accessed using ``atomic_long_xxx()`` functions. It is initialized in
  ``free_area_init_core()`` and then is reinitialized when memblock allocator
  frees pages into buddy system.

``spanned_pages``
  The total pages spanned by the zone, including holes, which is calculated as:
  ``spanned_pages`` = ``zone_end_pfn`` - ``zone_start_pfn``. It is initialized
  by ``calculate_node_totalpages()``.

``present_pages``
  The physical pages existing within the zone, which is calculated as:
  ``present_pages`` = ``spanned_pages`` - ``absent_pages`` (pages in holes). It
  may be used by memory hotplug or memory power management logic to figure out
  unmanaged pages by checking (``present_pages`` - ``managed_pages``). Write
  access to ``present_pages`` at runtime should be protected by
  ``mem_hotplug_begin/done()``. Any reader who can't tolerant drift of
  ``present_pages`` should use ``get_online_mems()`` to get a stable value. It
  is initialized by ``calculate_node_totalpages()``.

``present_early_pages``
  The present pages existing within the zone located on memory available since
  early boot, excluding hotplugged memory. Defined only when
  ``CONFIG_MEMORY_HOTPLUG`` is enabled and initialized by
  ``calculate_node_totalpages()``.

``cma_pages``
  The pages reserved for CMA use. These pages behave like ``ZONE_MOVABLE`` when
  they are not used for CMA. Defined only when ``CONFIG_CMA`` is enabled.

``name``
  The name of the zone. It is a pointer to the corresponding element of
  the ``zone_names`` array.

``nr_isolate_pageblock``
  Number of isolated pageblocks. It is used to solve incorrect freepage counting
  problem due to racy retrieving migratetype of pageblock. Protected by
  ``zone->lock``. Defined only when ``CONFIG_MEMORY_ISOLATION`` is enabled.

``span_seqlock``
  The seqlock to protect ``zone_start_pfn`` and ``spanned_pages``. It is a
  seqlock because it has to be read outside of ``zone->lock``, and it is done in
  the main allocator path. However, the seqlock is written quite infrequently.
  Defined only when ``CONFIG_MEMORY_HOTPLUG`` is enabled.

``initialized``
  The flag indicating if the zone is initialized. Set by
  ``init_currently_empty_zone()`` during boot.

``free_area``
  The array of free areas, where each element corresponds to a specific order
  which is a power of two. The buddy allocator uses this structure to manage
  free memory efficiently. When allocating, it tries to find the smallest
  sufficient block, if the smallest sufficient block is larger than the
  requested size, it will be recursively split into the next smaller blocks
  until the required size is reached. When a page is freed, it may be merged
  with its buddy to form a larger block. It is initialized by
  ``zone_init_free_lists()``.

``unaccepted_pages``
  The list of pages to be accepted. All pages on the list are ``MAX_PAGE_ORDER``.
  Defined only when ``CONFIG_UNACCEPTED_MEMORY`` is enabled.

``flags``
  The zone flags. The least three bits are used and defined by
  ``enum zone_flags``. ``ZONE_BOOSTED_WATERMARK`` (bit 0): zone recently boosted
  watermarks. Cleared when kswapd is woken. ``ZONE_RECLAIM_ACTIVE`` (bit 1):
  kswapd may be scanning the zone. ``ZONE_BELOW_HIGH`` (bit 2): zone is below
  high watermark.

``lock``
  The main lock that protects the internal data structures of the page allocator
  specific to the zone, especially protects ``free_area``.

``percpu_drift_mark``
  When free pages are below this point, additional steps are taken when reading
  the number of free pages to avoid per-cpu counter drift allowing watermarks
  to be breached. It is updated in ``refresh_zone_stat_thresholds()``.

Zone compaction control과 통계

545-609
  • `compact_cached_free_pfn`: 다음 scan에서 compaction free scanner가 시작할 PFN입니다.
  • `compact_cached_migrate_pfn`: 다음 scan에서 compaction migration scanner가 시작할 PFN array입니다. 첫 element는 `MIGRATE_ASYNC`, 두 번째는 `MIGRATE_SYNC` mode에서 사용합니다.
  • `compact_init_migrate_pfn`: initial migration PFN입니다. Boot 때 0으로 초기화하고 full compaction이 끝난 뒤에는 zone에서 migratable page가 있는 첫 pageblock으로 설정합니다. Scan이 zone 전체 scan인지 확인하는 데 사용합니다.
  • `compact_init_free_pfn`: initial free PFN입니다. Boot 때 0으로, 이후에는 zone에서 free `MIGRATE_MOVABLE` page가 있는 마지막 pageblock으로 설정합니다. Scan 시작인지 확인하는 데 사용합니다.
  • `compact_considered`: 마지막 실패 뒤 compaction을 시도한 횟수입니다. Compaction이 page-allocation 성공으로 이어지지 않으면 `defer_compaction()`이 reset합니다. Compaction을 skip해야 할 때 `compaction_deferred()`가 1 증가시킵니다. `compaction_deferred()`는 `compact_zone()` 전에 호출하고, `compact_zone()`이 `COMPACT_SUCCESS`를 반환하면 `compaction_defer_reset()`을, `COMPACT_PARTIAL_SKIPPED` 또는 `COMPACT_COMPLETE`를 반환하면 `defer_compaction()`을 호출합니다.
  • `compact_defer_shift`: 다시 시도하기 전 skip할 compaction 수는 `1 << compact_defer_shift`입니다. `defer_compaction()`에서 1 증가하고 direct compaction이 page allocation에 성공하면 `compaction_defer_reset()`에서 reset합니다. 최댓값은 `COMPACT_MAX_DEFER_SHIFT`입니다.
  • `compact_order_failed`: compaction에 실패한 최소 order입니다. 성공 시 `compaction_defer_reset()`에서, page-allocation 성공으로 이어지지 않은 실패 시 `defer_compaction()`에서 설정합니다.
  • `compact_blockskip_flush`: compaction migration scanner와 free scanner가 만났을 때 true로 set하며, `PB_compact_skip` bit를 clear해야 한다는 뜻입니다.
  • `contiguous`: zone에 hole이 없어 contiguous하면 true입니다.

`vm_stat`은 `enum zone_stat_item`이 정의한 항목의 zone VM statistic입니다. `vm_numa_event`는 `enum numa_stat_item`이 정의한 zone VM NUMA-event statistic입니다.

`per_cpu_zonestats`는 zone의 CPU별 VM statistic입니다. VM statistic과 NUMA-event statistic을 CPU별로 기록해 global `vm_stat`과 `vm_numa_event` update를 줄이고 성능을 높입니다.

Compaction control
~~~~~~~~~~~~~~~~~~

``compact_cached_free_pfn``
  The PFN where compaction free scanner should start in the next scan.

``compact_cached_migrate_pfn``
  The PFNs where compaction migration scanner should start in the next scan.
  This array has two elements: the first one is used in ``MIGRATE_ASYNC`` mode,
  and the other one is used in ``MIGRATE_SYNC`` mode.

``compact_init_migrate_pfn``
  The initial migration PFN which is initialized to 0 at boot time, and to the
  first pageblock with migratable pages in the zone after a full compaction
  finishes. It is used to check if a scan is a whole zone scan or not.

``compact_init_free_pfn``
  The initial free PFN which is initialized to 0 at boot time and to the last
  pageblock with free ``MIGRATE_MOVABLE`` pages in the zone. It is used to check
  if it is the start of a scan.

``compact_considered``
  The number of compactions attempted since last failure. It is reset in
  ``defer_compaction()`` when a compaction fails to result in a page allocation
  success. It is increased by 1 in ``compaction_deferred()`` when a compaction
  should be skipped. ``compaction_deferred()`` is called before
  ``compact_zone()`` is called, ``compaction_defer_reset()`` is called when
  ``compact_zone()`` returns ``COMPACT_SUCCESS``, ``defer_compaction()`` is
  called when ``compact_zone()`` returns ``COMPACT_PARTIAL_SKIPPED`` or
  ``COMPACT_COMPLETE``.

``compact_defer_shift``
  The number of compactions skipped before trying again is
  ``1<<compact_defer_shift``. It is increased by 1 in ``defer_compaction()``.
  It is reset in ``compaction_defer_reset()`` when a direct compaction results
  in a page allocation success. Its maximum value is ``COMPACT_MAX_DEFER_SHIFT``.

``compact_order_failed``
  The minimum compaction failed order. It is set in ``compaction_defer_reset()``
  when a compaction succeeds and in ``defer_compaction()`` when a compaction
  fails to result in a page allocation success.

``compact_blockskip_flush``
  Set to true when compaction migration scanner and free scanner meet, which
  means the ``PB_compact_skip`` bits should be cleared.

``contiguous``
  Set to true when the zone is contiguous (in other words, no hole).

Statistics
~~~~~~~~~~

``vm_stat``
  VM statistics for the zone. The items tracked are defined by
  ``enum zone_stat_item``.

``vm_numa_event``
  VM NUMA event statistics for the zone. The items tracked are defined by
  ``enum numa_stat_item``.

``per_cpu_zonestats``
  Per-CPU VM statistics for the zone. It records VM statistics and VM NUMA event
  statistics on a per-CPU basis. It reduces updates to the global ``vm_stat``
  and ``vm_numa_event`` fields of the zone to improve performance.

Pages, Folios와 Initialization 자리표시자

610-635

`Pages` section은 incomplete stub입니다. 적절한 field를 나열하고 설명해 달라는 안내만 있습니다.

`Folios` section도 incomplete stub이며 적절한 field 목록과 설명이 아직 필요합니다.

`Initialization` section 역시 incomplete stub이며 적절한 field를 나열하고 설명하라는 안내만 있습니다. 원문에 없는 field 설명은 추가하지 않았습니다.

.. _pages:

Pages
=====

.. admonition:: Stub

   This section is incomplete. Please list and describe the appropriate fields.

.. _folios:

Folios
======

.. admonition:: Stub

   This section is incomplete. Please list and describe the appropriate fields.

.. _initialization:

Initialization
==============

.. admonition:: Stub

   This section is incomplete. Please list and describe the appropriate fields.