€• Œsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ#/translations/zh_CN/mm/memory-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ#/translations/zh_TW/mm/memory-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ#/translations/it_IT/mm/memory-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ#/translations/ja_JP/mm/memory-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ#/translations/ko_KR/mm/memory-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ#/translations/pt_BR/mm/memory-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ#/translations/sp_SP/mm/memory-model”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)”}”(hŒ SPDX-License-Identifier: GPL-2.0”h]”hŒ SPDX-License-Identifier: GPL-2.0”…””}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³Œ=/var/lib/git/docbuild/linux/Documentation/mm/memory-model.rst”h´KubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒPhysical Memory Model”h]”hŒPhysical Memory Model”…””}”(hhÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhhÊh²hh³hÇh´KubhŒ paragraph”“”)”}”(hXÄPhysical memory in a system may be addressed in different ways. The simplest case is when the physical memory starts at address 0 and spans a contiguous range up to the maximal address. It could be, however, that this range contains small holes that are not accessible for the CPU. Then there could be several contiguous ranges at completely distinct addresses. And, don't forget about NUMA, where different memory banks are attached to different CPUs.”h]”hXÆPhysical memory in a system may be addressed in different ways. The simplest case is when the physical memory starts at address 0 and spans a contiguous range up to the maximal address. It could be, however, that this range contains small holes that are not accessible for the CPU. Then there could be several contiguous ranges at completely distinct addresses. And, don’t forget about NUMA, where different memory banks are attached to different CPUs.”…””}”(hhßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÞ)”}”(hŒòLinux abstracts this diversity using one of the two memory models: FLATMEM and SPARSEMEM. Each architecture defines what memory models it supports, what the default memory model is and whether it is possible to manually override that default.”h]”hŒòLinux abstracts this diversity using one of the two memory models: FLATMEM and SPARSEMEM. Each architecture defines what memory models it supports, what the default memory model is and whether it is possible to manually override that default.”…””}”(hhíh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÞ)”}”(hŒpAll the memory models track the status of physical page frames using struct page arranged in one or more arrays.”h]”hŒpAll the memory models track the status of physical page frames using struct page arranged in one or more arrays.”…””}”(hhûh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÞ)”}”(hŒšRegardless of the selected memory model, there exists one-to-one mapping between the physical page frame number (PFN) and the corresponding `struct page`.”h]”(hŒŒRegardless of the selected memory model, there exists one-to-one mapping between the physical page frame number (PFN) and the corresponding ”…””}”(hj h²hh³Nh´NubhŒtitle_reference”“”)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj ubhŒ.”…””}”(hj h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÞ)”}”(hŒ•Each memory model defines :c:func:`pfn_to_page` and :c:func:`page_to_pfn` helpers that allow the conversion from PFN to `struct page` and vice versa.”h]”(hŒEach memory model defines ”…””}”(hj+h²hh³Nh´Nubh)”}”(hŒ:c:func:`pfn_to_page`”h]”hŒliteral”“”)”}”(hj5h]”hŒ pfn_to_page()”…””}”(hj9h²hh³Nh´Nubah}”(h]”h ]”(Œxref”Œc”Œc-func”eh"]”h$]”h&]”uh1j7hj3ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”Œmm/memory-model”Œ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰Œ reftarget”Œ pfn_to_page”uh1hh³hÇh´Khj+ubhŒ and ”…””}”(hj+h²hh³Nh´Nubh)”}”(hŒ:c:func:`page_to_pfn`”h]”j8)”}”(hj^h]”hŒ page_to_pfn()”…””}”(hj`h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hj\ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒ page_to_pfn”uh1hh³hÇh´Khj+ubhŒ/ helpers that allow the conversion from PFN to ”…””}”(hj+h²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj+ubhŒ and vice versa.”…””}”(hj+h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KhhÊh²hubhÉ)”}”(hhh]”(hÎ)”}”(hŒFLATMEM”h]”hŒFLATMEM”…””}”(hjšh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj—h²hh³hÇh´K ubhÞ)”}”(hŒ‰The simplest memory model is FLATMEM. This model is suitable for non-NUMA systems with contiguous, or mostly contiguous, physical memory.”h]”hŒ‰The simplest memory model is FLATMEM. This model is suitable for non-NUMA systems with contiguous, or mostly contiguous, physical memory.”…””}”(hj¨h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K"hj—h²hubhÞ)”}”(hŒýIn the FLATMEM memory model, there is a global `mem_map` array that maps the entire physical memory. For most architectures, the holes have entries in the `mem_map` array. The `struct page` objects corresponding to the holes are never fully initialized.”h]”(hŒ/In the FLATMEM memory model, there is a global ”…””}”(hj¶h²hh³Nh´Nubj)”}”(hŒ `mem_map`”h]”hŒmem_map”…””}”(hj¾h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¶ubhŒc array that maps the entire physical memory. For most architectures, the holes have entries in the ”…””}”(hj¶h²hh³Nh´Nubj)”}”(hŒ `mem_map`”h]”hŒmem_map”…””}”(hjÐh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¶ubhŒ array. The ”…””}”(hj¶h²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hjâh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¶ubhŒ@ objects corresponding to the holes are never fully initialized.”…””}”(hj¶h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K&hj—h²hubhÞ)”}”(hŒõTo allocate the `mem_map` array, architecture specific setup code should call :c:func:`free_area_init` function. Yet, the mappings array is not usable until the call to :c:func:`memblock_free_all` that hands all the memory to the page allocator.”h]”(hŒTo allocate the ”…””}”(hjúh²hh³Nh´Nubj)”}”(hŒ `mem_map`”h]”hŒmem_map”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjúubhŒ5 array, architecture specific setup code should call ”…””}”(hjúh²hh³Nh´Nubh)”}”(hŒ:c:func:`free_area_init`”h]”j8)”}”(hjh]”hŒfree_area_init()”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒfree_area_init”uh1hh³hÇh´K+hjúubhŒC function. Yet, the mappings array is not usable until the call to ”…””}”(hjúh²hh³Nh´Nubh)”}”(hŒ:c:func:`memblock_free_all`”h]”j8)”}”(hj9h]”hŒmemblock_free_all()”…””}”(hj;h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hj7ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒmemblock_free_all”uh1hh³hÇh´K+hjúubhŒ1 that hands all the memory to the page allocator.”…””}”(hjúh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K+hj—h²hubhÞ)”}”(hŒâAn architecture may free parts of the `mem_map` array that do not cover the actual physical pages. In such case, the architecture specific :c:func:`pfn_valid` implementation should take the holes in the `mem_map` into account.”h]”(hŒ&An architecture may free parts of the ”…””}”(hj`h²hh³Nh´Nubj)”}”(hŒ `mem_map`”h]”hŒmem_map”…””}”(hjhh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj`ubhŒ\ array that do not cover the actual physical pages. In such case, the architecture specific ”…””}”(hj`h²hh³Nh´Nubh)”}”(hŒ:c:func:`pfn_valid`”h]”j8)”}”(hj|h]”hŒ pfn_valid()”…””}”(hj~h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hjzubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒ pfn_valid”uh1hh³hÇh´K0hj`ubhŒ- implementation should take the holes in the ”…””}”(hj`h²hh³Nh´Nubj)”}”(hŒ `mem_map`”h]”hŒmem_map”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj`ubhŒ into account.”…””}”(hj`h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K0hj—h²hubhÞ)”}”(hŒWith FLATMEM, the conversion between a PFN and the `struct page` is straightforward: `PFN - ARCH_PFN_OFFSET` is an index to the `mem_map` array.”h]”(hŒ3With FLATMEM, the conversion between a PFN and the ”…””}”(hjµh²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hj½h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjµubhŒ is straightforward: ”…””}”(hjµh²hh³Nh´Nubj)”}”(hŒ`PFN - ARCH_PFN_OFFSET`”h]”hŒPFN - ARCH_PFN_OFFSET”…””}”(hjÏh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjµubhŒ is an index to the ”…””}”(hjµh²hh³Nh´Nubj)”}”(hŒ `mem_map`”h]”hŒmem_map”…””}”(hjáh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjµubhŒ array.”…””}”(hjµh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K5hj—h²hubhÞ)”}”(hŒ€The `ARCH_PFN_OFFSET` defines the first page frame number for systems with physical memory starting at address different from 0.”h]”(hŒThe ”…””}”(hjùh²hh³Nh´Nubj)”}”(hŒ`ARCH_PFN_OFFSET`”h]”hŒARCH_PFN_OFFSET”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjùubhŒk defines the first page frame number for systems with physical memory starting at address different from 0.”…””}”(hjùh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K9hj—h²hubeh}”(h]”Œflatmem”ah ]”h"]”Œflatmem”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ SPARSEMEM”h]”hŒ SPARSEMEM”…””}”(hj$h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj!h²hh³hÇh´K=ubhÞ)”}”(hX9SPARSEMEM is the most versatile memory model available in Linux and it is the only memory model that supports several advanced features such as hot-plug and hot-remove of the physical memory, alternative memory maps for non-volatile memory devices and deferred initialization of the memory map for larger systems.”h]”hX9SPARSEMEM is the most versatile memory model available in Linux and it is the only memory model that supports several advanced features such as hot-plug and hot-remove of the physical memory, alternative memory maps for non-volatile memory devices and deferred initialization of the memory map for larger systems.”…””}”(hj2h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K?hj!h²hubhÞ)”}”(hXeThe SPARSEMEM model presents the physical memory as a collection of sections. A section is represented with struct mem_section that contains `section_mem_map` that is, logically, a pointer to an array of struct pages. However, it is stored with some other magic that aids the sections management. The section size and maximal number of section is specified using `SECTION_SIZE_BITS` and `MAX_PHYSMEM_BITS` constants defined by each architecture that supports SPARSEMEM. While `MAX_PHYSMEM_BITS` is an actual width of a physical address that an architecture supports, the `SECTION_SIZE_BITS` is an arbitrary value.”h]”(hŒThe SPARSEMEM model presents the physical memory as a collection of sections. A section is represented with struct mem_section that contains ”…””}”(hj@h²hh³Nh´Nubj)”}”(hŒ`section_mem_map`”h]”hŒsection_mem_map”…””}”(hjHh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj@ubhŒÍ that is, logically, a pointer to an array of struct pages. However, it is stored with some other magic that aids the sections management. The section size and maximal number of section is specified using ”…””}”(hj@h²hh³Nh´Nubj)”}”(hŒ`SECTION_SIZE_BITS`”h]”hŒSECTION_SIZE_BITS”…””}”(hjZh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj@ubhŒ and ”…””}”(hj@h²hh³Nh´Nubj)”}”(hŒ`MAX_PHYSMEM_BITS`”h]”hŒMAX_PHYSMEM_BITS”…””}”(hjlh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj@ubhŒG constants defined by each architecture that supports SPARSEMEM. While ”…””}”(hj@h²hh³Nh´Nubj)”}”(hŒ`MAX_PHYSMEM_BITS`”h]”hŒMAX_PHYSMEM_BITS”…””}”(hj~h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj@ubhŒM is an actual width of a physical address that an architecture supports, the ”…””}”(hj@h²hh³Nh´Nubj)”}”(hŒ`SECTION_SIZE_BITS`”h]”hŒSECTION_SIZE_BITS”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj@ubhŒ is an arbitrary value.”…””}”(hj@h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KEhj!h²hubhÞ)”}”(hŒJThe maximal number of sections is denoted `NR_MEM_SECTIONS` and defined as”h]”(hŒ*The maximal number of sections is denoted ”…””}”(hj¨h²hh³Nh´Nubj)”}”(hŒ`NR_MEM_SECTIONS`”h]”hŒNR_MEM_SECTIONS”…””}”(hj°h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¨ubhŒ and defined as”…””}”(hj¨h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KPhj!h²hubhŒ math_block”“”)”}”(hŒDNR\_MEM\_SECTIONS = 2 ^ {(MAX\_PHYSMEM\_BITS - SECTION\_SIZE\_BITS)}”h]”hŒDNR\_MEM\_SECTIONS = 2 ^ {(MAX\_PHYSMEM\_BITS - SECTION\_SIZE\_BITS)}”…””}”hjÊsbah}”(h]”h ]”h"]”h$]”h&]”Œdocname”jPŒnumber”NŒlabel”NŒnowrap”‰hÅhÆuh1jÈh³hÇh´KShj!h²hubhÞ)”}”(hŒÏThe `mem_section` objects are arranged in a two-dimensional array called `mem_sections`. The size and placement of this array depend on `CONFIG_SPARSEMEM_EXTREME` and the maximal possible number of sections:”h]”(hŒThe ”…””}”(hjÜh²hh³Nh´Nubj)”}”(hŒ `mem_section`”h]”hŒ mem_section”…””}”(hjäh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÜubhŒ8 objects are arranged in a two-dimensional array called ”…””}”(hjÜh²hh³Nh´Nubj)”}”(hŒ`mem_sections`”h]”hŒ mem_sections”…””}”(hjöh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÜubhŒ1. The size and placement of this array depend on ”…””}”(hjÜh²hh³Nh´Nubj)”}”(hŒ`CONFIG_SPARSEMEM_EXTREME`”h]”hŒCONFIG_SPARSEMEM_EXTREME”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÜubhŒ- and the maximal possible number of sections:”…””}”(hjÜh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´KWhj!h²hubhŒ bullet_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hŒWhen `CONFIG_SPARSEMEM_EXTREME` is disabled, the `mem_sections` array is static and has `NR_MEM_SECTIONS` rows. Each row holds a single `mem_section` object.”h]”hÞ)”}”(hŒWhen `CONFIG_SPARSEMEM_EXTREME` is disabled, the `mem_sections` array is static and has `NR_MEM_SECTIONS` rows. Each row holds a single `mem_section` object.”h]”(hŒWhen ”…””}”(hj+h²hh³Nh´Nubj)”}”(hŒ`CONFIG_SPARSEMEM_EXTREME`”h]”hŒCONFIG_SPARSEMEM_EXTREME”…””}”(hj3h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj+ubhŒ is disabled, the ”…””}”(hj+h²hh³Nh´Nubj)”}”(hŒ`mem_sections`”h]”hŒ mem_sections”…””}”(hjEh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj+ubhŒ array is static and has ”…””}”(hj+h²hh³Nh´Nubj)”}”(hŒ`NR_MEM_SECTIONS`”h]”hŒNR_MEM_SECTIONS”…””}”(hjWh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj+ubhŒ rows. Each row holds a single ”…””}”(hj+h²hh³Nh´Nubj)”}”(hŒ `mem_section`”h]”hŒ mem_section”…””}”(hjih²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj+ubhŒ object.”…””}”(hj+h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K\hj'ubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj"h²hh³hÇh´Nubj&)”}”(hŒßWhen `CONFIG_SPARSEMEM_EXTREME` is enabled, the `mem_sections` array is dynamically allocated. Each row contains PAGE_SIZE worth of `mem_section` objects and the number of rows is calculated to fit all the memory sections. ”h]”hÞ)”}”(hŒÞWhen `CONFIG_SPARSEMEM_EXTREME` is enabled, the `mem_sections` array is dynamically allocated. Each row contains PAGE_SIZE worth of `mem_section` objects and the number of rows is calculated to fit all the memory sections.”h]”(hŒWhen ”…””}”(hj‹h²hh³Nh´Nubj)”}”(hŒ`CONFIG_SPARSEMEM_EXTREME`”h]”hŒCONFIG_SPARSEMEM_EXTREME”…””}”(hj“h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj‹ubhŒ is enabled, the ”…””}”(hj‹h²hh³Nh´Nubj)”}”(hŒ`mem_sections`”h]”hŒ mem_sections”…””}”(hj¥h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj‹ubhŒF array is dynamically allocated. Each row contains PAGE_SIZE worth of ”…””}”(hj‹h²hh³Nh´Nubj)”}”(hŒ `mem_section`”h]”hŒ mem_section”…””}”(hj·h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj‹ubhŒM objects and the number of rows is calculated to fit all the memory sections.”…””}”(hj‹h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K_hj‡ubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hj"h²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ*”uh1j h³hÇh´K\hj!h²hubhÞ)”}”(hŒîWith SPARSEMEM there are two possible ways to convert a PFN to the corresponding `struct page` - a "classic sparse" and "sparse vmemmap". The selection is made at build time and it is determined by the value of `CONFIG_SPARSEMEM_VMEMMAP`.”h]”(hŒQWith SPARSEMEM there are two possible ways to convert a PFN to the corresponding ”…””}”(hjÝh²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hjåh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÝubhŒ} - a “classic sparse†and “sparse vmemmapâ€. The selection is made at build time and it is determined by the value of ”…””}”(hjÝh²hh³Nh´Nubj)”}”(hŒ`CONFIG_SPARSEMEM_VMEMMAP`”h]”hŒCONFIG_SPARSEMEM_VMEMMAP”…””}”(hj÷h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÝubhŒ.”…””}”(hjÝh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kdhj!h²hubhÞ)”}”(hŒÑThe classic sparse encodes the section number of a page in page->flags and uses high bits of a PFN to access the section that maps that page frame. Inside a section, the PFN is the index to the array of pages.”h]”hŒÑThe classic sparse encodes the section number of a page in page->flags and uses high bits of a PFN to access the section that maps that page frame. Inside a section, the PFN is the index to the array of pages.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kihj!h²hubhÞ)”}”(hXLThe sparse vmemmap uses a virtually mapped memory map to optimize pfn_to_page and page_to_pfn operations. There is a global `struct page *vmemmap` pointer that points to a virtually contiguous array of `struct page` objects. A PFN is an index to that array and the offset of the `struct page` from `vmemmap` is the PFN of that page.”h]”(hŒ|The sparse vmemmap uses a virtually mapped memory map to optimize pfn_to_page and page_to_pfn operations. There is a global ”…””}”(hjh²hh³Nh´Nubj)”}”(hŒ`struct page *vmemmap`”h]”hŒstruct page *vmemmap”…””}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubhŒ8 pointer that points to a virtually contiguous array of ”…””}”(hjh²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hj7h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubhŒ@ objects. A PFN is an index to that array and the offset of the ”…””}”(hjh²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hjIh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubhŒ from ”…””}”(hjh²hh³Nh´Nubj)”}”(hŒ `vmemmap`”h]”hŒvmemmap”…””}”(hj[h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubhŒ is the PFN of that page.”…””}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kmhj!h²hubhÞ)”}”(hXTo use vmemmap, an architecture has to reserve a range of virtual addresses that will map the physical pages containing the memory map and make sure that `vmemmap` points to that range. In addition, the architecture should implement :c:func:`vmemmap_populate` method that will allocate the physical memory and create page tables for the virtual memory map. If an architecture does not have any special requirements for the vmemmap mappings, it can use default :c:func:`vmemmap_populate_basepages` provided by the generic memory management.”h]”(hŒšTo use vmemmap, an architecture has to reserve a range of virtual addresses that will map the physical pages containing the memory map and make sure that ”…””}”(hjsh²hh³Nh´Nubj)”}”(hŒ `vmemmap`”h]”hŒvmemmap”…””}”(hj{h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjsubhŒF points to that range. In addition, the architecture should implement ”…””}”(hjsh²hh³Nh´Nubh)”}”(hŒ:c:func:`vmemmap_populate`”h]”j8)”}”(hjh]”hŒvmemmap_populate()”…””}”(hj‘h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒvmemmap_populate”uh1hh³hÇh´KthjsubhŒÉ method that will allocate the physical memory and create page tables for the virtual memory map. If an architecture does not have any special requirements for the vmemmap mappings, it can use default ”…””}”(hjsh²hh³Nh´Nubh)”}”(hŒ$:c:func:`vmemmap_populate_basepages`”h]”j8)”}”(hj²h]”hŒvmemmap_populate_basepages()”…””}”(hj´h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hj°ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒvmemmap_populate_basepages”uh1hh³hÇh´KthjsubhŒ+ provided by the generic memory management.”…””}”(hjsh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kthj!h²hubhÞ)”}”(hXÅThe virtually mapped memory map allows storing `struct page` objects for persistent memory devices in pre-allocated storage on those devices. This storage is represented with struct vmem_altmap that is eventually passed to vmemmap_populate() through a long chain of function calls. The vmemmap_populate() implementation may use the `vmem_altmap` along with :c:func:`vmemmap_alloc_block_buf` helper to allocate memory map on the persistent memory device.”h]”(hŒ/The virtually mapped memory map allows storing ”…””}”(hjÙh²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hjáh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÙubhX objects for persistent memory devices in pre-allocated storage on those devices. This storage is represented with struct vmem_altmap that is eventually passed to vmemmap_populate() through a long chain of function calls. The vmemmap_populate() implementation may use the ”…””}”(hjÙh²hh³Nh´Nubj)”}”(hŒ `vmem_altmap`”h]”hŒ vmem_altmap”…””}”(hjóh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÙubhŒ along with ”…””}”(hjÙh²hh³Nh´Nubh)”}”(hŒ!:c:func:`vmemmap_alloc_block_buf`”h]”j8)”}”(hjh]”hŒvmemmap_alloc_block_buf()”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒvmemmap_alloc_block_buf”uh1hh³hÇh´K~hjÙubhŒ? helper to allocate memory map on the persistent memory device.”…””}”(hjÙh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K~hj!h²hubeh}”(h]”Œ sparsemem”ah ]”h"]”Œ sparsemem”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K=ubhÉ)”}”(hhh]”(hÎ)”}”(hŒ ZONE_DEVICE”h]”hŒ ZONE_DEVICE”…””}”(hj9h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÍhj6h²hh³hÇh´K‡ubhÞ)”}”(hX>The `ZONE_DEVICE` facility builds upon `SPARSEMEM_VMEMMAP` to offer `struct page` `mem_map` services for device driver identified physical address ranges. The "device" aspect of `ZONE_DEVICE` relates to the fact that the page objects for these address ranges are never marked online, and that a reference must be taken against the device, not just the page to keep the memory pinned for active use. `ZONE_DEVICE`, via :c:func:`devm_memremap_pages`, performs just enough memory hotplug to turn on :c:func:`pfn_to_page`, :c:func:`page_to_pfn`, and :c:func:`get_user_pages` service for the given range of pfns. Since the page reference count never drops below 1 the page is never tracked as free memory and the page's `struct list_head lru` space is repurposed for back referencing to the host device / driver that mapped the memory.”h]”(hŒThe ”…””}”(hjGh²hh³Nh´Nubj)”}”(hŒ `ZONE_DEVICE`”h]”hŒ ZONE_DEVICE”…””}”(hjOh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjGubhŒ facility builds upon ”…””}”(hjGh²hh³Nh´Nubj)”}”(hŒ`SPARSEMEM_VMEMMAP`”h]”hŒSPARSEMEM_VMEMMAP”…””}”(hjah²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjGubhŒ to offer ”…””}”(hjGh²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hjsh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjGubhŒ ”…””}”(hjGh²hh³Nh´Nubj)”}”(hŒ `mem_map`”h]”hŒmem_map”…””}”(hj…h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjGubhŒ[ services for device driver identified physical address ranges. The “device†aspect of ”…””}”(hjGh²hh³Nh´Nubj)”}”(hŒ `ZONE_DEVICE`”h]”hŒ ZONE_DEVICE”…””}”(hj—h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjGubhŒÐ relates to the fact that the page objects for these address ranges are never marked online, and that a reference must be taken against the device, not just the page to keep the memory pinned for active use. ”…””}”(hjGh²hh³Nh´Nubj)”}”(hŒ `ZONE_DEVICE`”h]”hŒ ZONE_DEVICE”…””}”(hj©h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjGubhŒ, via ”…””}”(hjGh²hh³Nh´Nubh)”}”(hŒ:c:func:`devm_memremap_pages`”h]”j8)”}”(hj½h]”hŒdevm_memremap_pages()”…””}”(hj¿h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hj»ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒdevm_memremap_pages”uh1hh³hÇh´KˆhjGubhŒ1, performs just enough memory hotplug to turn on ”…””}”(hjGh²hh³Nh´Nubh)”}”(hŒ:c:func:`pfn_to_page`”h]”j8)”}”(hjàh]”hŒ pfn_to_page()”…””}”(hjâh²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hjÞubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒ pfn_to_page”uh1hh³hÇh´KˆhjGubhŒ, ”…””}”(hjGh²hh³Nh´Nubh)”}”(hŒ:c:func:`page_to_pfn`”h]”j8)”}”(hjh]”hŒ page_to_pfn()”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hjubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒ page_to_pfn”uh1hh³hÇh´KˆhjGubhŒ, and ”…””}”(hjGh²hh³Nh´Nubh)”}”(hŒ:c:func:`get_user_pages`”h]”j8)”}”(hj&h]”hŒget_user_pages()”…””}”(hj(h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hj$ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒget_user_pages”uh1hh³hÇh´KˆhjGubhŒ“ service for the given range of pfns. Since the page reference count never drops below 1 the page is never tracked as free memory and the page’s ”…””}”(hjGh²hh³Nh´Nubj)”}”(hŒ`struct list_head lru`”h]”hŒstruct list_head lru”…””}”(hjGh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjGubhŒ] space is repurposed for back referencing to the host device / driver that mapped the memory.”…””}”(hjGh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kˆhj6h²hubhÞ)”}”(hX¢While `SPARSEMEM` presents memory as a collection of sections, optionally collected into memory blocks, `ZONE_DEVICE` users have a need for smaller granularity of populating the `mem_map`. Given that `ZONE_DEVICE` memory is never marked online it is subsequently never subject to its memory ranges being exposed through the sysfs memory hotplug api on memory block boundaries. The implementation relies on this lack of user-api constraint to allow sub-section sized memory ranges to be specified to :c:func:`arch_add_memory`, the top-half of memory hotplug. Sub-section support allows for 2MB as the cross-arch common alignment granularity for :c:func:`devm_memremap_pages`.”h]”(hŒWhile ”…””}”(hj_h²hh³Nh´Nubj)”}”(hŒ `SPARSEMEM`”h]”hŒ SPARSEMEM”…””}”(hjgh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj_ubhŒW presents memory as a collection of sections, optionally collected into memory blocks, ”…””}”(hj_h²hh³Nh´Nubj)”}”(hŒ `ZONE_DEVICE`”h]”hŒ ZONE_DEVICE”…””}”(hjyh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj_ubhŒ= users have a need for smaller granularity of populating the ”…””}”(hj_h²hh³Nh´Nubj)”}”(hŒ `mem_map`”h]”hŒmem_map”…””}”(hj‹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj_ubhŒ . Given that ”…””}”(hj_h²hh³Nh´Nubj)”}”(hŒ `ZONE_DEVICE`”h]”hŒ ZONE_DEVICE”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj_ubhX memory is never marked online it is subsequently never subject to its memory ranges being exposed through the sysfs memory hotplug api on memory block boundaries. The implementation relies on this lack of user-api constraint to allow sub-section sized memory ranges to be specified to ”…””}”(hj_h²hh³Nh´Nubh)”}”(hŒ:c:func:`arch_add_memory`”h]”j8)”}”(hj±h]”hŒarch_add_memory()”…””}”(hj³h²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hj¯ubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒarch_add_memory”uh1hh³hÇh´K•hj_ubhŒx, the top-half of memory hotplug. Sub-section support allows for 2MB as the cross-arch common alignment granularity for ”…””}”(hj_h²hh³Nh´Nubh)”}”(hŒ:c:func:`devm_memremap_pages`”h]”j8)”}”(hjÔh]”hŒdevm_memremap_pages()”…””}”(hjÖh²hh³Nh´Nubah}”(h]”h ]”(jCjDŒc-func”eh"]”h$]”h&]”uh1j7hjÒubah}”(h]”h ]”h"]”h$]”h&]”Œrefdoc”jPŒ refdomain”jDŒreftype”Œfunc”Œ refexplicit”‰Œrefwarn”‰jVŒdevm_memremap_pages”uh1hh³hÇh´K•hj_ubhŒ.”…””}”(hj_h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K•hj6h²hubhÞ)”}”(hŒThe users of `ZONE_DEVICE` are:”h]”(hŒ The users of ”…””}”(hjûh²hh³Nh´Nubj)”}”(hŒ `ZONE_DEVICE`”h]”hŒ ZONE_DEVICE”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjûubhŒ are:”…””}”(hjûh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K hj6h²hubj!)”}”(hhh]”(j&)”}”(hŒYpmem: Map platform persistent memory to be used as a direct-I/O target via DAX mappings. ”h]”hÞ)”}”(hŒXpmem: Map platform persistent memory to be used as a direct-I/O target via DAX mappings.”h]”hŒXpmem: Map platform persistent memory to be used as a direct-I/O target via DAX mappings.”…””}”(hj"h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K¢hjubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjh²hh³hÇh´Nubj&)”}”(hŒãhmm: Extend `ZONE_DEVICE` with `->page_fault()` and `->folio_free()` event callbacks to allow a device-driver to coordinate memory management events related to device-memory, typically GPU memory. See Documentation/mm/hmm.rst. ”h]”hÞ)”}”(hŒâhmm: Extend `ZONE_DEVICE` with `->page_fault()` and `->folio_free()` event callbacks to allow a device-driver to coordinate memory management events related to device-memory, typically GPU memory. See Documentation/mm/hmm.rst.”h]”(hŒ hmm: Extend ”…””}”(hj:h²hh³Nh´Nubj)”}”(hŒ `ZONE_DEVICE`”h]”hŒ ZONE_DEVICE”…””}”(hjBh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj:ubhŒ with ”…””}”(hj:h²hh³Nh´Nubj)”}”(hŒ`->page_fault()`”h]”hŒ->page_fault()”…””}”(hjTh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj:ubhŒ and ”…””}”(hj:h²hh³Nh´Nubj)”}”(hŒ`->folio_free()`”h]”hŒ->folio_free()”…””}”(hjfh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj:ubhŒž event callbacks to allow a device-driver to coordinate memory management events related to device-memory, typically GPU memory. See Documentation/mm/hmm.rst.”…””}”(hj:h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´K¥hj6ubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjh²hh³hÇh´Nubj&)”}”(hŒ p2pdma: Create `struct page` objects to allow peer devices in a PCI/-E topology to coordinate direct-DMA operations between themselves, i.e. bypass host memory.”h]”hÞ)”}”(hŒ p2pdma: Create `struct page` objects to allow peer devices in a PCI/-E topology to coordinate direct-DMA operations between themselves, i.e. bypass host memory.”h]”(hŒp2pdma: Create ”…””}”(hjˆh²hh³Nh´Nubj)”}”(hŒ `struct page`”h]”hŒ struct page”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjˆubhŒ„ objects to allow peer devices in a PCI/-E topology to coordinate direct-DMA operations between themselves, i.e. bypass host memory.”…””}”(hjˆh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÝh³hÇh´Kªhj„ubah}”(h]”h ]”h"]”h$]”h&]”uh1j%hjh²hh³hÇh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jÛjÜuh1j h³hÇh´K¢hj6h²hubeh}”(h]”Œ zone-device”ah ]”h"]”Œ zone_device”ah$]”h&]”uh1hÈhhÊh²hh³hÇh´K‡ubeh}”(h]”Œphysical-memory-model”ah ]”h"]”Œphysical memory model”ah$]”h&]”uh1hÈhhh²hh³hÇh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÇuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(hÍNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jçŒerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÇŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(jÁj¾jjj3j0j¹j¶uŒ nametypes”}”(jÁ‰j‰j3‰j¹‰uh}”(j¾hÊjj—j0j!j¶j6uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.