€•™^Œ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/split_page_table_lock”Œ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/split_page_table_lock”Œ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/split_page_table_lock”Œ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/split_page_table_lock”Œ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/split_page_table_lock”Œ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/split_page_table_lock”Œ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/split_page_table_lock”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)�”}”(hhh]”(hŒtitle”“”)�”}”(hŒSplit page table lock”h]”hŒSplit page table lock”…”�”}”(hh¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhh·h²hh³ŒF/var/lib/git/docbuild/linux/Documentation/mm/split_page_table_lock.rst”h´KubhŒ paragraph”“”)�”}”(hX Originally, mm->page_table_lock spinlock protected all page tables of the mm_struct. But this approach leads to poor page fault scalability of multi-threaded applications due to high contention on the lock. To improve scalability, split page table lock was introduced.”h]”hX Originally, mm->page_table_lock spinlock protected all page tables of the mm_struct. But this approach leads to poor page fault scalability of multi-threaded applications due to high contention on the lock. To improve scalability, split page table lock was introduced.”…”�”}”(hhÍh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khh·h²hubhÌ)�”}”(hŒÔWith split page table lock we have separate per-table lock to serialize access to the table. At the moment we use split lock for PTE and PMD tables. Access to higher level tables protected by mm->page_table_lock.”h]”hŒÔWith split page table lock we have separate per-table lock to serialize access to the table. At the moment we use split lock for PTE and PMD tables. Access to higher level tables protected by mm->page_table_lock.”…”�”}”(hhÛh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K hh·h²hubhÌ)�”}”(hŒFThere are helpers to lock/unlock a table and other accessor functions:”h]”hŒFThere are helpers to lock/unlock a table and other accessor functions:”…”�”}”(hhéh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khh·h²hubhŒ block_quote”“”)�”}”(hXô- pte_offset_map_lock() maps PTE and takes PTE table lock, returns pointer to PTE with pointer to its PTE table lock, or returns NULL if no PTE table; - pte_offset_map_ro_nolock() maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken), or returns NULL if no PTE table; - pte_offset_map_rw_nolock() maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken) and the value of its pmd entry, or returns NULL if no PTE table; - pte_offset_map() maps PTE, returns pointer to PTE, or returns NULL if no PTE table; - pte_unmap() unmaps PTE table; - pte_unmap_unlock() unlocks and unmaps PTE table; - pte_alloc_map_lock() allocates PTE table if needed and takes its lock, returns pointer to PTE with pointer to its lock, or returns NULL if allocation failed; - pmd_lock() takes PMD table lock, returns pointer to taken lock; - pmd_lockptr() returns pointer to PMD table lock; ”h]”hŒ bullet_list”“”)�”}”(hhh]”(hŒ list_item”“”)�”}”(hŒžpte_offset_map_lock() maps PTE and takes PTE table lock, returns pointer to PTE with pointer to its PTE table lock, or returns NULL if no PTE table;”h]”hŒdefinition_list”“”)�”}”(hhh]”hŒdefinition_list_item”“”)�”}”(hŒ”pte_offset_map_lock() maps PTE and takes PTE table lock, returns pointer to PTE with pointer to its PTE table lock, or returns NULL if no PTE table;”h]”(hŒterm”“”)�”}”(hŒpte_offset_map_lock()”h]”hŒpte_offset_map_lock()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´KhjubhŒ definition”“”)�”}”(hhh]”hÌ)�”}”(hŒ~maps PTE and takes PTE table lock, returns pointer to PTE with pointer to its PTE table lock, or returns NULL if no PTE table;”h]”hŒ~maps PTE and takes PTE table lock, returns pointer to PTE with pointer to its PTE table lock, or returns NULL if no PTE table;”…”�”}”(hj(h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khj%ubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´Khj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubj)�”}”(hŒ–pte_offset_map_ro_nolock() maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken), or returns NULL if no PTE table;”h]”j )�”}”(hhh]”j)�”}”(hŒŒpte_offset_map_ro_nolock() maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken), or returns NULL if no PTE table;”h]”(j)�”}”(hŒpte_offset_map_ro_nolock()”h]”hŒpte_offset_map_ro_nolock()”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´KhjUubj$)�”}”(hhh]”hÌ)�”}”(hŒqmaps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken), or returns NULL if no PTE table;”h]”hŒqmaps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken), or returns NULL if no PTE table;”…”�”}”(hjjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khjgubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjUubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´KhjRubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjNubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubj)�”}”(hŒºpte_offset_map_rw_nolock() maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken) and the value of its pmd entry, or returns NULL if no PTE table;”h]”j )�”}”(hhh]”j)�”}”(hŒ«pte_offset_map_rw_nolock() maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken) and the value of its pmd entry, or returns NULL if no PTE table;”h]”(j)�”}”(hŒpte_offset_map_rw_nolock()”h]”hŒpte_offset_map_rw_nolock()”…”�”}”(hj›h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´Khj—ubj$)�”}”(hhh]”hÌ)�”}”(hŒ�maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken) and the value of its pmd entry, or returns NULL if no PTE table;”h]”hŒ�maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken) and the value of its pmd entry, or returns NULL if no PTE table;”…”�”}”(hj¬h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khj©ubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hj—ubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´Khj”ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj�ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubj)�”}”(hŒXpte_offset_map() maps PTE, returns pointer to PTE, or returns NULL if no PTE table;”h]”j )�”}”(hhh]”j)�”}”(hŒSpte_offset_map() maps PTE, returns pointer to PTE, or returns NULL if no PTE table;”h]”(j)�”}”(hŒpte_offset_map()”h]”hŒpte_offset_map()”…”�”}”(hjÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´KhjÙubj$)�”}”(hhh]”hÌ)�”}”(hŒBmaps PTE, returns pointer to PTE, or returns NULL if no PTE table;”h]”hŒBmaps PTE, returns pointer to PTE, or returns NULL if no PTE table;”…”�”}”(hjîh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khjëubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjÙubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´KhjÖubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÒubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubj)�”}”(hŒ"pte_unmap() unmaps PTE table;”h]”j )�”}”(hhh]”j)�”}”(hŒpte_unmap() unmaps PTE table;”h]”(j)�”}”(hŒ pte_unmap()”h]”hŒ pte_unmap()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´Khjubj$)�”}”(hhh]”hÌ)�”}”(hŒunmaps PTE table;”h]”hŒunmaps PTE table;”…”�”}”(hj0h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khj-ubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´Khjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubj)�”}”(hŒ5pte_unmap_unlock() unlocks and unmaps PTE table;”h]”j )�”}”(hhh]”j)�”}”(hŒ0pte_unmap_unlock() unlocks and unmaps PTE table;”h]”(j)�”}”(hŒpte_unmap_unlock()”h]”hŒpte_unmap_unlock()”…”�”}”(hjah²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´Khj]ubj$)�”}”(hhh]”hÌ)�”}”(hŒunlocks and unmaps PTE table;”h]”hŒunlocks and unmaps PTE table;”…”�”}”(hjrh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khjoubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hj]ubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´KhjZubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjVubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubj)�”}”(hŒ§pte_alloc_map_lock() allocates PTE table if needed and takes its lock, returns pointer to PTE with pointer to its lock, or returns NULL if allocation failed;”h]”j )�”}”(hhh]”j)�”}”(hŒ�pte_alloc_map_lock() allocates PTE table if needed and takes its lock, returns pointer to PTE with pointer to its lock, or returns NULL if allocation failed;”h]”(j)�”}”(hŒpte_alloc_map_lock()”h]”hŒpte_alloc_map_lock()”…”�”}”(hj£h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´K!hjŸubj$)�”}”(hhh]”hÌ)�”}”(hŒˆallocates PTE table if needed and takes its lock, returns pointer to PTE with pointer to its lock, or returns NULL if allocation failed;”h]”hŒˆallocates PTE table if needed and takes its lock, returns pointer to PTE with pointer to its lock, or returns NULL if allocation failed;”…”�”}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K!hj±ubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjŸubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´K!hjœubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj˜ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubj)�”}”(hŒDpmd_lock() takes PMD table lock, returns pointer to taken lock;”h]”j )�”}”(hhh]”j)�”}”(hŒ?pmd_lock() takes PMD table lock, returns pointer to taken lock;”h]”(j)�”}”(hŒ pmd_lock()”h]”hŒ pmd_lock()”…”�”}”(hjåh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´K#hjáubj$)�”}”(hhh]”hÌ)�”}”(hŒ4takes PMD table lock, returns pointer to taken lock;”h]”hŒ4takes PMD table lock, returns pointer to taken lock;”…”�”}”(hjöh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K$hjóubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjáubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´K#hjÞubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÚubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubj)�”}”(hŒ6pmd_lockptr() returns pointer to PMD table lock; ”h]”j )�”}”(hhh]”j)�”}”(hŒ1pmd_lockptr() returns pointer to PMD table lock; ”h]”(j)�”}”(hŒ pmd_lockptr()”h]”hŒ pmd_lockptr()”…”�”}”(hj'h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´K&hj#ubj$)�”}”(hhh]”hÌ)�”}”(hŒ"returns pointer to PMD table lock;”h]”hŒ"returns pointer to PMD table lock;”…”�”}”(hj8h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K&hj5ubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hj#ubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´K&hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ-”uh1hýh³hÊh´Khhùubah}”(h]”h ]”h"]”h$]”h&]”uh1h÷h³hÊh´Khh·h²hubhÌ)�”}”(hŒËSplit page table lock for PTE tables is enabled compile-time if CONFIG_SPLIT_PTLOCK_CPUS (usually 4) is less or equal to NR_CPUS. If split lock is disabled, all tables are guarded by mm->page_table_lock.”h]”hŒËSplit page table lock for PTE tables is enabled compile-time if CONFIG_SPLIT_PTLOCK_CPUS (usually 4) is less or equal to NR_CPUS. If split lock is disabled, all tables are guarded by mm->page_table_lock.”…”�”}”(hjlh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K(hh·h²hubhÌ)�”}”(hŒ}Split page table lock for PMD tables is enabled, if it's enabled for PTE tables and the architecture supports it (see below).”h]”hŒSplit page table lock for PMD tables is enabled, if it’s enabled for PTE tables and the architecture supports it (see below).”…”�”}”(hjzh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K,hh·h²hubh¶)�”}”(hhh]”(h»)�”}”(hŒ!Hugetlb and split page table lock”h]”hŒ!Hugetlb and split page table lock”…”�”}”(hj‹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjˆh²hh³hÊh´K0ubhÌ)�”}”(hŒ^Hugetlb can support several page sizes. We use split lock only for PMD level, but not for PUD.”h]”hŒ^Hugetlb can support several page sizes. We use split lock only for PMD level, but not for PUD.”…”�”}”(hj™h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K2hjˆh²hubhÌ)�”}”(hŒHugetlb-specific helpers:”h]”hŒHugetlb-specific helpers:”…”�”}”(hj§h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K5hjˆh²hubhø)�”}”(hŒ¢- huge_pte_lock() takes pmd split lock for PMD_SIZE page, mm->page_table_lock otherwise; - huge_pte_lockptr() returns pointer to table lock; ”h]”hþ)�”}”(hhh]”(j)�”}”(hŒ`huge_pte_lock() takes pmd split lock for PMD_SIZE page, mm->page_table_lock otherwise;”h]”j )�”}”(hhh]”j)�”}”(hŒVhuge_pte_lock() takes pmd split lock for PMD_SIZE page, mm->page_table_lock otherwise;”h]”(j)�”}”(hŒhuge_pte_lock()”h]”hŒhuge_pte_lock()”…”�”}”(hjÇh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´K8hjÃubj$)�”}”(hhh]”hÌ)�”}”(hŒFtakes pmd split lock for PMD_SIZE page, mm->page_table_lock otherwise;”h]”hŒFtakes pmd split lock for PMD_SIZE page, mm->page_table_lock otherwise;”…”�”}”(hjØh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K8hjÕubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjÃubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´K8hjÀubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¼ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¹ubj)�”}”(hŒ7huge_pte_lockptr() returns pointer to table lock; ”h]”j )�”}”(hhh]”j)�”}”(hŒ2huge_pte_lockptr() returns pointer to table lock; ”h]”(j)�”}”(hŒhuge_pte_lockptr()”h]”hŒhuge_pte_lockptr()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jh³hÊh´K;hjubj$)�”}”(hhh]”hÌ)�”}”(hŒreturns pointer to table lock;”h]”hŒreturns pointer to table lock;”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K;hjubah}”(h]”h ]”h"]”h$]”h&]”uh1j#hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÊh´K;hjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjþubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¹ubeh}”(h]”h ]”h"]”h$]”h&]”jdjeuh1hýh³hÊh´K7hjµubah}”(h]”h ]”h"]”h$]”h&]”uh1h÷h³hÊh´K7hjˆh²hubeh}”(h]”Œ!hugetlb-and-split-page-table-lock”ah ]”h"]”Œ!hugetlb and split page table lock”ah$]”h&]”uh1hµhh·h²hh³hÊh´K0ubh¶)�”}”(hhh]”(h»)�”}”(hŒ3Support of split page table lock by an architecture”h]”hŒ3Support of split page table lock by an architecture”…”�”}”(hjWh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjTh²hh³hÊh´K>ubhÌ)�”}”(hŒÃThere's no need in special enabling of PTE split page table lock: everything required is done by pagetable_pte_ctor() and pagetable_dtor(), which must be called on PTE table allocation / freeing.”h]”hŒÅThere’s no need in special enabling of PTE split page table lock: everything required is done by pagetable_pte_ctor() and pagetable_dtor(), which must be called on PTE table allocation / freeing.”…”�”}”(hjeh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K@hjTh²hubhÌ)�”}”(hŒ¤Make sure the architecture doesn't use slab allocator for page table allocation: slab uses page->slab_cache for its pages. This field shares storage with page->ptl.”h]”hŒ¦Make sure the architecture doesn’t use slab allocator for page table allocation: slab uses page->slab_cache for its pages. This field shares storage with page->ptl.”…”�”}”(hjsh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KDhjTh²hubhÌ)�”}”(hŒLPMD split lock only makes sense if you have more than two page table levels.”h]”hŒLPMD split lock only makes sense if you have more than two page table levels.”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KHhjTh²hubhÌ)�”}”(hŒsPMD split lock enabling requires pagetable_pmd_ctor() call on PMD table allocation and pagetable_dtor() on freeing.”h]”hŒsPMD split lock enabling requires pagetable_pmd_ctor() call on PMD table allocation and pagetable_dtor() on freeing.”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KKhjTh²hubhÌ)�”}”(hŒËAllocation usually happens in pmd_alloc_one(), freeing in pmd_free() and pmd_free_tlb(), but make sure you cover all PMD table allocation / freeing paths: i.e X86_PAE preallocate few PMDs on pgd_alloc().”h]”hŒËAllocation usually happens in pmd_alloc_one(), freeing in pmd_free() and pmd_free_tlb(), but make sure you cover all PMD table allocation / freeing paths: i.e X86_PAE preallocate few PMDs on pgd_alloc().”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KNhjTh²hubhÌ)�”}”(hŒIWith everything in place you can set CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK.”h]”hŒIWith everything in place you can set CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK.”…”�”}”(hj«h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KRhjTh²hubhÌ)�”}”(hŒ\NOTE: pagetable_pte_ctor() and pagetable_pmd_ctor() can fail -- it must be handled properly.”h]”hŒ\NOTE: pagetable_pte_ctor() and pagetable_pmd_ctor() can fail -- it must be handled properly.”…”�”}”(hj¹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KThjTh²hubeh}”(h]”Œ3support-of-split-page-table-lock-by-an-architecture”ah ]”h"]”Œ3support of split page table lock by an architecture”ah$]”h&]”uh1hµhh·h²hh³hÊh´K>ubh¶)�”}”(hhh]”(h»)�”}”(hŒ page->ptl”h]”hŒ page->ptl”…”�”}”(hjÒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjÏh²hh³hÊh´KXubhÌ)�”}”(hŒ²page->ptl is used to access split page table lock, where 'page' is struct page of page containing the table. It shares storage with page->private (and few other fields in union).”h]”hŒ¶page->ptl is used to access split page table lock, where ‘page’ is struct page of page containing the table. It shares storage with page->private (and few other fields in union).”…”�”}”(hjàh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KZhjÏh²hubhÌ)�”}”(hŒRTo avoid increasing size of struct page and have best performance, we use a trick:”h]”hŒRTo avoid increasing size of struct page and have best performance, we use a trick:”…”�”}”(hjîh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K^hjÏh²hubhø)�”}”(hX{- if spinlock_t fits into long, we use page->ptr as spinlock, so we can avoid indirect access and save a cache line. - if size of spinlock_t is bigger then size of long, we use page->ptl as pointer to spinlock_t and allocate it dynamically. This allows to use split lock with enabled DEBUG_SPINLOCK or DEBUG_LOCK_ALLOC, but costs one more cache line for indirect access; ”h]”hþ)�”}”(hhh]”(j)�”}”(hŒrif spinlock_t fits into long, we use page->ptr as spinlock, so we can avoid indirect access and save a cache line.”h]”hÌ)�”}”(hŒrif spinlock_t fits into long, we use page->ptr as spinlock, so we can avoid indirect access and save a cache line.”h]”hŒrif spinlock_t fits into long, we use page->ptr as spinlock, so we can avoid indirect access and save a cache line.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kahjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)�”}”(hŒüif size of spinlock_t is bigger then size of long, we use page->ptl as pointer to spinlock_t and allocate it dynamically. This allows to use split lock with enabled DEBUG_SPINLOCK or DEBUG_LOCK_ALLOC, but costs one more cache line for indirect access; ”h]”hÌ)�”}”(hŒûif size of spinlock_t is bigger then size of long, we use page->ptl as pointer to spinlock_t and allocate it dynamically. This allows to use split lock with enabled DEBUG_SPINLOCK or DEBUG_LOCK_ALLOC, but costs one more cache line for indirect access;”h]”hŒûif size of spinlock_t is bigger then size of long, we use page->ptl as pointer to spinlock_t and allocate it dynamically. This allows to use split lock with enabled DEBUG_SPINLOCK or DEBUG_LOCK_ALLOC, but costs one more cache line for indirect access;”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kchjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubeh}”(h]”h ]”h"]”h$]”h&]”jdjeuh1hýh³hÊh´Kahjüubah}”(h]”h ]”h"]”h$]”h&]”uh1h÷h³hÊh´KahjÏh²hubhÌ)�”}”(hŒiThe spinlock_t allocated in pagetable_pte_ctor() for PTE table and in pagetable_pmd_ctor() for PMD table.”h]”hŒiThe spinlock_t allocated in pagetable_pte_ctor() for PTE table and in pagetable_pmd_ctor() for PMD table.”…”�”}”(hj?h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KhhjÏh²hubhÌ)�”}”(hŒBPlease, never access page->ptl directly -- use appropriate helper.”h]”hŒBPlease, never access page->ptl directly -- use appropriate helper.”…”�”}”(hjMh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KkhjÏh²hubeh}”(h]”Œpage-ptl”ah ]”h"]”Œ page->ptl”ah$]”h&]”uh1hµhh·h²hh³hÊh´KXubeh}”(h]”Œsplit-page-table-lock”ah ]”h"]”Œsplit page table lock”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”}”(jhjejQjNjÌjÉj`j]uŒ nametypes”}”(jh‰jQ‰j̉j`‰uh}”(jeh·jNjˆjÉjTj]jÏuŒ 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.