c++ mmap写入速度_内存管理(24)mmap和缺页中断
相關(guān)文件:
mm/mlock.c
mm/util.c
mm/mmap.c
include/linux/slab.h
mmap系統(tǒng)調(diào)用陷入內(nèi)核中會(huì)調(diào)用vm_mmap_pgoff=>do_mmap_pgoff函數(shù)來(lái)真正完成mmap操作
1.1.do_mmap_pgoff函數(shù)(關(guān)鍵部分代碼)
do_mmap_pgoff
- 16行:對(duì)需要映射的內(nèi)存長(zhǎng)度頁(yè)對(duì)齊
- 20行:get_unmapped_area返回需要映射的地址空間
- 25行:建立映射關(guān)系,如果定義了VM_LOCKED還要立即申請(qǐng)物理內(nèi)存,該函數(shù)的實(shí)現(xiàn)細(xì)節(jié)請(qǐng)看1.2小節(jié)
1.2.mmap_region函數(shù)(關(guān)鍵部分代碼)
mmap_region
- 40行:查找符合條件的vma
- 46行:合并相鄰的vma
- 49行:如果沒(méi)找到合適的vma則調(diào)用kmem_cache_zalloc申請(qǐng)一個(gè)vma結(jié)構(gòu),這個(gè)函數(shù)前面也說(shuō)過(guò)
- 51行:把初始化好的vma插入mm下的內(nèi)存管理樹(shù)結(jié)構(gòu)
- 55行:配置vma的訪問(wèn)權(quán)限
2.缺頁(yè)中斷(armv7架構(gòu))
相關(guān)文件:
mm/memory.c
arch/arm/mm/fault.c
缺頁(yè)中斷與具體的處理器架構(gòu)密切相關(guān)。以ARM為例,頁(yè)面轉(zhuǎn)換失效和頁(yè)面訪問(wèn)權(quán)限失效對(duì)應(yīng)的核心處理函數(shù)為do_page_fault。
缺頁(yè)中斷基本流程
2.1.do_page_fault函數(shù)(關(guān)鍵部分)
do_page_fault函數(shù)-1
- 69行:處于中斷上下文或者禁止搶占時(shí)跳轉(zhuǎn)到no_context標(biāo)簽
- 71行:用戶(hù)空間添加FAULT_FLAG_USER標(biāo)志
- 73行:具備FSR_WRITE權(quán)限則添加FAULT_FLAG_WRITE標(biāo)志
- 76行:真正處理缺頁(yè)中斷的函數(shù),詳情看小節(jié)2.2
do_page_fault函數(shù)-2
- 85行:不屬于以上異常就說(shuō)明缺頁(yè)中斷正常處理完成
- 88行:缺頁(yè)中斷處理有異常發(fā)生,如果是內(nèi)核空間跳轉(zhuǎn)到no_context標(biāo)簽執(zhí)行__do_kernel_fault函數(shù)
- 90行:VM_FAULT_OOM則調(diào)用pagefault_out_of_memory發(fā)送OOM信號(hào)
- 95行:用戶(hù)空間則向進(jìn)程發(fā)送SIGSEGV信號(hào),進(jìn)程中斷
- 99行:__do_kernel_fault函數(shù)發(fā)送Oops錯(cuò)誤
2.2.__do_page_fault函數(shù)(關(guān)鍵部分)
__do_page_fault函數(shù)
- 112行:查找vma
- 115行:vma訪問(wèn)權(quán)限
- 120行:缺頁(yè)中斷處理,詳見(jiàn)2.3
2.3.__handle_mm_fault函數(shù)(關(guān)鍵部分)
__handle_mm_fault函數(shù)
- 141~148行:獲取到addr所對(duì)應(yīng)的PGD、PUD、PMD、PTE
- 150行:handle_pte_fault處理缺頁(yè)中斷,詳見(jiàn)2.4
2.4.handle_pte_fault函數(shù)(關(guān)鍵部分)
handle_pte_fault函數(shù)-1
176行:如果頁(yè)面不在內(nèi)存中(還未映射真正的頁(yè)),調(diào)用pte_none177行:頁(yè)面為空。對(duì)于文件映射通常會(huì)調(diào)用do_fault(詳見(jiàn)2.6);否則表示匿名映射則會(huì)調(diào)用do_anonymous_page(詳見(jiàn)2.5)186行:頁(yè)面不為空,表示正處于交換內(nèi)存中,調(diào)用do_swap_page函數(shù),詳見(jiàn)2.7189行:寫(xiě)異常190行:如果pte為只讀權(quán)限,調(diào)用do_swap_page函數(shù)193行:如果具備寫(xiě)屬性,L_PTE_DIRTY置位handle_pte_fault函數(shù)-2
- 189行:設(shè)置L_PTE_YONG位
- 190行:如果pte頁(yè)面項(xiàng)有變化就要寫(xiě)入物理頁(yè)面項(xiàng),并更新TLB cache
2.5.do_anonymous_page函數(shù)
do_anonymous_page函數(shù)-1
- 225行:判斷當(dāng)前VMA是否需要增加一個(gè)guard page作為安全墊
- 229~236行:對(duì)于只讀的VMA,系統(tǒng)使用0號(hào)頁(yè)面生成新的PTE entry,0號(hào)頁(yè)面是在paging_init中初始化的,前面提過(guò)。使用pte_offset_map_lock能得到頁(yè)表項(xiàng)。如果表項(xiàng)不為空則跳轉(zhuǎn)到setpte處更新到硬件表中。
do_anonymous_page函數(shù)-2
241行:分配一個(gè)可寫(xiě)的匿名頁(yè)面,最終調(diào)用伙伴系統(tǒng)的alloc_pages,優(yōu)先選擇高端內(nèi)存254~256行:通過(guò)mk_xxx生成一個(gè)新的pte entry262行:inc_mm_counter_fast增加系統(tǒng)中匿名頁(yè)面的引用計(jì)數(shù)263行增加到RMAP反向映射系統(tǒng)中265行:把匿名頁(yè)添加到LRU鏈表中,kswap中會(huì)用到267行:設(shè)置pte entry到硬件頁(yè)表中do_anonymous_page函數(shù)-3
- 270行:刷新TLB和cache
2.6.do_fault函數(shù)
do_fault函數(shù)
- 300行:只讀缺頁(yè)異常,詳見(jiàn)2.8小節(jié)
- 303行:私有映射且發(fā)生寫(xiě)時(shí)拷貝缺頁(yè)異常,詳見(jiàn)2.9小節(jié)
- 305行:公有映射寫(xiě)缺頁(yè)異常,詳見(jiàn)2.10小節(jié)
2.7.do_swap_page函數(shù)
與2.8和2.9類(lèi)似
2.8.do_read_fault函數(shù)
static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,unsigned long address, pmd_t *pmd,pgoff_t pgoff, unsigned int flags, pte_t orig_pte){struct page *fault_page;if (vma->vm_ops->map_pages && fault_around_bytes >> PAGE_SHIFT > 1) {//拿到缺頁(yè)異常地址addr所對(duì)應(yīng)的ptepte = pte_offset_map_lock(mm, pmd, address, &ptl);/*以缺頁(yè)異常地址為中心,從start_addr開(kāi)始檢查相應(yīng)的pte是否為空,若為*空則從這個(gè)pte開(kāi)始到max_pgoff為止使用map_pages()來(lái)映射PTE。這么做為*了提前建立缺頁(yè)地址(進(jìn)程地址空間)與(現(xiàn)存)page cache的映射關(guān)系,*減少缺頁(yè)中斷的次數(shù)從而提高效率。*/do_fault_around(vma, address, pte, pgoff, flags);//頁(yè)面內(nèi)容在剛剛被系統(tǒng)修改了,跳轉(zhuǎn)到unlock_out標(biāo)簽if (!pte_same(*pte, orig_pte))goto unlock_out;pte_unmap_unlock(pte, ptl);}//為缺頁(yè)異常地址分配page cache ret = __do_fault(vma, address, pgoff, flags, NULL, &fault_page);if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))return ret;//拿到映射好的缺頁(yè)地址的PTEpte = pte_offset_map_lock(mm, pmd, address, &ptl);if (unlikely(!pte_same(*pte, orig_pte))) {pte_unmap_unlock(pte, ptl);unlock_page(fault_page);page_cache_release(fault_page);return ret;}//為PTE創(chuàng)建條目,并加入反向映射機(jī)制do_set_pte(vma, address, fault_page, pte, false, false);unlock_page(fault_page);unlock_out://放棄映射pte_unmap_unlock(pte, ptl);return ret;}2.9.do_cow_fault函數(shù)
//省略部分錯(cuò)誤判斷static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,unsigned long address, pmd_t *pmd,pgoff_t pgoff, unsigned int flags, pte_t orig_pte){pte_t *pte;int ret;if (unlikely(anon_vma_prepare(vma)))return VM_FAULT_OOM;//以GFP_HIGHUSER_MOVABLE分配掩碼分配一個(gè)物理頁(yè)面new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);if (mem_cgroup_try_charge(new_page, mm, GFP_KERNEL, &memcg)) {page_cache_release(new_page);return VM_FAULT_OOM;}//讀取文件內(nèi)容到fault_pageret = __do_fault(vma, address, pgoff, flags, new_page, &fault_page);if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))goto uncharge_out;if (fault_page)//拷貝內(nèi)容到物理頁(yè)面copy_user_highpage(new_page, fault_page, address, vma);__SetPageUptodate(new_page);//取得對(duì)應(yīng)的PTEpte = pte_offset_map_lock(mm, pmd, address, &ptl);//為對(duì)應(yīng)PTE創(chuàng)建條目再添加到反向映射機(jī)制do_set_pte(vma, address, new_page, pte, true, true);mem_cgroup_commit_charge(new_page, memcg, false);//物理頁(yè)面加入LRU隊(duì)列進(jìn)行管理,內(nèi)存回收會(huì)用到lru_cache_add_active_or_unevictable(new_page, vma);pte_unmap_unlock(pte, ptl);if (fault_page) {unlock_page(fault_page);page_cache_release(fault_page);} else {i_mmap_unlock_read(vma->vm_file->f_mapping);}return ret;uncharge_out:mem_cgroup_cancel_charge(new_page, memcg);page_cache_release(new_page);return ret;}2.10.do_shared_fault函數(shù)
與2.8和2.9類(lèi)似
2.11.do_fault_around函數(shù)
static void do_fault_around(struct vm_area_struct *vma, unsigned long address,pte_t *pte, pgoff_t pgoff, unsigned int flags){unsigned long start_addr, nr_pages, mask;pgoff_t max_pgoff;struct vm_fault vmf;int off;/*fault_around_bytes是一個(gè)全局變量,等于16個(gè)page的大小,所以此處nr_pages=16*/nr_pages = ACCESS_ONCE(fault_around_bytes) >> PAGE_SHIFT;//以16頁(yè)對(duì)齊為步長(zhǎng)計(jì)算掩碼mask = ~(nr_pages * PAGE_SIZE - 1) & PAGE_MASK;//以16頁(yè)對(duì)齊,取缺頁(yè)地址和vm_start較大的那個(gè)為掃描PTE的起始地址start_addr = max(address & mask, vma->vm_start);/*PTRS_PER_PTE 表示每個(gè)PTE項(xiàng)所對(duì)應(yīng)的條目數(shù),此處為512也就是1個(gè)PTE對(duì)應(yīng)512頁(yè)*這一步相當(dāng)于取缺頁(yè)地址和start_addr的偏離(頁(yè)數(shù)單位)的絕對(duì)值*/off = ((address - start_addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);//查找PTE的起始位置pte -= off;pgoff -= off;/* * max_pgoff is either end of page table or end of vma * or fault_around_pages() from pgoff, depending what is nearest. */max_pgoff = pgoff - ((start_addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +PTRS_PER_PTE - 1;max_pgoff = min3(max_pgoff, vma_pages(vma) + vma->vm_pgoff - 1,pgoff + nr_pages - 1);/* Check if it makes any sense to call ->map_pages */while (!pte_none(*pte)) {if (++pgoff > max_pgoff)return;start_addr += PAGE_SIZE;if (start_addr >= vma->vm_end)return;pte++;}//找到為空的PTE,則從此處開(kāi)始到max_pgoff映射PTEvmf.virtual_address = (void __user *) start_addr;vmf.pte = pte;vmf.pgoff = pgoff;vmf.max_pgoff = max_pgoff;vmf.flags = flags;vma->vm_ops->map_pages(vma, &vmf);} 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的c++ mmap写入速度_内存管理(24)mmap和缺页中断的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 电子科大沙河校区有计算机专业,电子科大沙
- 下一篇: 怀旧服开新服务器消息,怀旧服B测已经开启