类似淘宝网站模板网站开发获取报价
2026/4/6 7:26:32 网站建设 项目流程
类似淘宝网站模板,网站开发获取报价,北京建设企业网站,购物网站设计的目的文章目录 1. 前言2. 匿名内存映射的典型场景2.1 只读内存匿名映射过程2.2 只写内存匿名映射过程2.3 COW 匿名映射过程2.3.1 先读后写内存匿名映射过程2.3.2 父子进程写 COW 匿名映射过程 1. 前言 限于作者能力水平#xff0c;本文可能存在谬误#xff0c;因此而给读者带来的…文章目录1. 前言2. 匿名内存映射的典型场景2.1 只读内存匿名映射过程2.2 只写内存匿名映射过程2.3 COW 匿名映射过程2.3.1 先读后写内存匿名映射过程2.3.2 父子进程写 COW 匿名映射过程1. 前言限于作者能力水平本文可能存在谬误因此而给读者带来的损失作者不做任何承诺。2. 匿名内存映射的典型场景本文以ARMv7 Linux 4.14.x为上下文分析匿名内存映射的典型场景下代码实现的概要细节。2.1 只读内存匿名映射过程用户空间分配内存而后进行读操作映射为zero pagesize_tsize1*1024*1024;char*ptrmmap(NULL,size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,0,0);charcptr[0];// 读操作触发 page faultmunmap(ptr,size);语句char c ptr[0];会触发硬件page fault从而进入读操作匿名内存页的映射过程。ARMv7架构的处理流程如下do_DataAbort()...do_page_fault()__do_page_fault()handle_mm_fault()__handle_mm_fault()handle_pte_fault()staticinthandle_pte_fault(structvm_fault*vmf){...if(unlikely(pmd_none(*vmf-pmd))){/* * Leave __pte_alloc() until later: because vm_ops-fault may * want to allocate huge page, and if we expose page table * for an instant, it will be difficult to retract from * concurrent faults and from rmap lookups. */vmf-pteNULL;}else{...}if(!vmf-pte){/* PTE 页表 还未建立 */if(vma_is_anonymous(vmf-vma))returndo_anonymous_page(vmf);/* 匿名映射 */elsereturndo_fault(vmf);}...}staticintdo_anonymous_page(structvm_fault*vmf){.../* Use the zero-page for reads */if(!(vmf-flagsFAULT_FLAG_WRITE)!mm_forbids_zeropage(vma-vm_mm)){entrypte_mkspecial(pfn_pte(my_zero_pfn(vmf-address),vma-vm_page_prot));...gotosetpte;}...setpte:set_pte_at(vma-vm_mm,vmf-address,vmf-pte,entry);...}上面的代码中my_zero_pfn()选择将读地址映射到zero page。从硬件 MMU 可以得知当前的page fault是由读还是写引起的从而去决定是否设置FAULT_FLAG_WRITE标志位。如ARMv7架构下发生page fault时从寄存器DFSR(Data Fault Status Register)获知是读还是写2.2 只写内存匿名映射过程用户空间分配内存而后进行写操作新分配物理内存并映射size_tsize1*1024*1024;char*ptrmmap(NULL,size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,0,0);ptr[0]0xAA;// 写操作触发 page faultmunmap(ptr,size);语句ptr[0] 0xAA;会触发硬件page fault从而进入写操作匿名内存页的映射过程。ARMv7架构的处理流程如下do_DataAbort()...do_page_fault()staticint__kprobesdo_page_fault(unsignedlongaddr,unsignedintfsr,structpt_regs*regs){...unsignedintflagsFAULT_FLAG_ALLOW_RETRY|FAULT_FLAG_KILLABLE;.../* 从 DFSR 寄存器得知是写操作引发的 page fault则设置 FAULT_FLAG_WRITE 标志位 */if(fsrFSR_WRITE)flags|FAULT_FLAG_WRITE;...fault__do_page_fault(mm,addr,fsr,flags,tsk);...}__do_page_fault()handle_mm_fault()__handle_mm_fault()handle_pte_fault()do_anonymous_page()staticintdo_anonymous_page(structvm_fault*vmf){...structpage*page;....../* 分配新内存页面 */pagealloc_zeroed_user_highpage_movable(vma,vmf-address);if(!page)gotooom;...__SetPageUptodate(page);entrymk_pte(page,vma-vm_page_prot);/* 构建 pte */if(vma-vm_flagsVM_WRITE)entrypte_mkwrite(pte_mkdirty(entry));/* 设置页面可写 */...setpte:set_pte_at(vma-vm_mm,vmf-address,vmf-pte,entry);/* 填充 PTE 页表项 */...}2.3 COW 匿名映射过程2.3.1 先读后写内存匿名映射过程用户空间分配内存先读而后进行写操作将引发写时拷贝(COW)size_tsize1*1024*1024;char*ptrmmap(NULL,size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,0,0);charcptr[0];// 读操作触发 page fault过程见 2.1 只读内存匿名映射过程ptr[0]0xAA;// 对只读内存进行写操作触发 COWmunmap(ptr,size);语句char c ptr[0];触发page fault将虚拟地址映射到只读的zero page过程见2.1 只读内存匿名映射过程这里不再赘述。语句ptr[0] 0xAA;写只读内存将触发写时拷贝(COW)do_DataAbort()...do_page_fault()__do_page_fault()handle_mm_fault()__handle_mm_fault()handle_pte_fault()staticinthandle_pte_fault(structvm_fault*vmf){pte_tentry;if(unlikely(pmd_none(*vmf-pmd))){...}else{...vmf-ptepte_offset_map(vmf-pmd,vmf-address);vmf-orig_pte*vmf-pte;...}...vmf-ptlpte_lockptr(vmf-vma-vm_mm,vmf-pmd);spin_lock(vmf-ptl);entryvmf-orig_pte;if(unlikely(!pte_same(*vmf-pte,entry)))gotounlock;if(vmf-flagsFAULT_FLAG_WRITE){/* 请求发起写操作 */if(!pte_write(entry))/* 但页面不允许写 */returndo_wp_page(vmf);/* 做写时拷贝(COW: Copy-On-Write) */entrypte_mkdirty(entry);}entrypte_mkyoung(entry);...unlock:pte_unmap_unlock(vmf-pte,vmf-ptl);return0;}staticintdo_wp_page(structvm_fault*vmf)__releases(vmf-ptl){...returnwp_page_copy(vmf);}2.3.2 父子进程写 COW 匿名映射过程size_tsize1*1024*1024;char*ptrmmap(NULL,size,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,0,0);// (1) 写操作触发 page fault分配内存页面ptr[0]A;fork();// (2.1) 父进程写触发 page fault// (2.2)ptr[0]B;父进程写触发 COW假定父进程先执行ptr[0] B;在写入过程中会触发 page fault 并进行 COWstaticintdo_wp_page(structvm_fault*vmf)__releases(vmf-ptl){structvm_area_struct*vmavmf-vma;vmf-pagevm_normal_page(vma,vmf-address,vmf-orig_pte);.../* * Ok, we need to copy. Oh, well.. */get_page(vmf-page);pte_unmap_unlock(vmf-pte,vmf-ptl);returnwp_page_copy(vmf);}staticintwp_page_copy(structvm_fault*vmf){...if(is_zero_pfn(pte_pfn(vmf-orig_pte))){/* 旧页面 是 zero page, 直接分配清 0 的新页面即可, 无需拷贝 */...}else{/* 旧页面 非 zero page, 分配新页面, 并拷贝旧页面内容 *//* 为父进程分配新页面 */new_pagealloc_page_vma(GFP_HIGHUSER_MOVABLE,vma,vmf-address);if(!new_page)gotooom;/* 拷贝 父进程 旧页面内容 到 新分配的页面 */cow_user_page(new_page,old_page,vmf-address,vma);}.../* * Re-check the pte - we dropped the lock */vmf-ptepte_offset_map_lock(mm,vmf-pmd,vmf-address,vmf-ptl);if(likely(pte_same(*vmf-pte,vmf-orig_pte))){...flush_cache_page(vma,vmf-address,pte_pfn(vmf-orig_pte));/* 为父进程构建新的 PTE 页表项内容 */entrymk_pte(new_page,vma-vm_page_prot);entrymaybe_mkwrite(pte_mkdirty(entry),vma);.../* 用新构建的 PTE 填充 PTE 页表项 */set_pte_at_notify(mm,vmf-address,vmf-pte,entry).../* Free the old page.. */new_pageold_page;page_copied1;}else{...}...returnpage_copied?VM_FAULT_WRITE:0;...}从上面的分析看到为父进程创建了新的页面假定父进程先执行ptr[0] B;然后拷贝旧页面内容并填充了 PTE 页表项。子进程写触发 COW假定子进程后执行ptr[0] B;在写入过程中会触发 page fault 并进行 COWstaticintdo_wp_page(structvm_fault*vmf)__releases(vmf-ptl){structvm_area_struct*vmavmf-vma;vmf-pagevm_normal_page(vma,vmf-address,vmf-orig_pte);.../* * Take out anonymous pages first, anonymous shared vmas are * not dirty accountable. */if(PageAnon(vmf-page)!PageKsm(vmf-page)){...if(!trylock_page(vmf-page)){...}if(reuse_swap_page(vmf-page,total_map_swapcount)){.../* 子进程 重用 fork 时 父进程 的 旧页面 */wp_page_reuse(vmf);returnVM_FAULT_WRITE;}}elseif(unlikely((vma-vm_flags(VM_WRITE|VM_SHARED))(VM_WRITE|VM_SHARED))){...}}staticinlinevoidwp_page_reuse(structvm_fault*vmf)__releases(vmf-ptl){structvm_area_struct*vmavmf-vma;structpage*pagevmf-page;pte_tentry;/* * Clear the pages cpupid information as the existing * information potentially belongs to a now completely * unrelated process. */if(page)page_cpupid_xchg_last(page,(1LAST_CPUPID_SHIFT)-1);flush_cache_page(vma,vmf-address,pte_pfn(vmf-orig_pte));entrypte_mkyoung(vmf-orig_pte);entrymaybe_mkwrite(pte_mkdirty(entry),vma);if(ptep_set_access_flags(vma,vmf-address,vmf-pte,entry,1))update_mmu_cache(vma,vmf-address,vmf-pte);pte_unmap_unlock(vmf-pte,vmf-ptl);}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询