:Original: Documentation/mm/mmu_notifier.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> :æ ¡è¯‘: 什么时候需è¦é¡µè¡¨é”内通知? ========================== 当清除一个pte/pmd时,我们å¯ä»¥é€‰æ‹©é€šè¿‡åœ¨é¡µè¡¨é”下(通知版的\*_clear_flush调用 mmu_notifier_invalidate_range)通知事件。但这ç§é€šçŸ¥å¹¶ä¸æ˜¯åœ¨æ‰€æœ‰æƒ…况下都需è¦çš„。 对于二级TLB(éžCPU TLB),如IOMMU TLB或设备TLB(当设备使用类似ATS/PASID的东西让 IOMMUèµ°CPU页表æ¥è®¿é—®è¿›ç¨‹çš„虚拟地å€ç©ºé—´ï¼‰ã€‚åªæœ‰ä¸¤ç§æƒ…况需è¦åœ¨æ¸…除pte/pmd时在æŒæœ‰é¡µ 表é”çš„åŒæ—¶é€šçŸ¥è¿™äº›äºŒçº§TLB: A) 在mmu_notifier_invalidate_range_end()之å‰ï¼Œæ”¯æŒé¡µçš„地å€è¢«é‡Šæ”¾ã€‚ B) 一个页表项被更新以指å‘一个新的页é¢ï¼ˆCOW,零页上的写异常,__replace_page(),...)。 情况Aå¾ˆæ˜Žæ˜¾ï¼Œä½ ä¸æƒ³å†’风险让设备写到一个现在å¯èƒ½è¢«ä¸€äº›å®Œå…¨ä¸åŒçš„任务使用的页é¢ã€‚ 情况Bæ›´åŠ å¾®å¦™ã€‚ä¸ºäº†æ£ç¡®èµ·è§ï¼Œå®ƒéœ€è¦æŒ‰ç…§ä»¥ä¸‹åºåˆ—å‘生: - ä¸Šé¡µè¡¨é” - 清除页表项并通知 ([pmd/pte]p_huge_clear_flush_notify()) - 设置页表项以指å‘新页 如果在设置新的pte/pmd值之å‰ï¼Œæ¸…除页表项之åŽæ²¡æœ‰è¿›è¡Œé€šçŸ¥ï¼Œé‚£ä¹ˆä½ å°±ä¼šç ´å设备的C11或 C++11ç‰å†…å˜æ¨¡åž‹ã€‚ 考虑以下情况(设备使用类似于ATS/PASID的功能)。 两个地å€addrAå’ŒaddrBï¼Œè¿™æ ·|addrA - addrB| >= PAGE_SIZE,我们å‡è®¾å®ƒä»¬æ˜¯COWçš„ 写ä¿æŠ¤ï¼ˆB的其他情况也适用)。 :: [Time N] -------------------------------------------------------------------- CPU-thread-0 {å°è¯•å†™åˆ°addrA} CPU-thread-1 {å°è¯•å†™åˆ°addrB} CPU-thread-2 {} CPU-thread-3 {} DEV-thread-0 {读å–addrA并填充设备TLB} DEV-thread-2 {读å–addrB并填充设备TLB} [Time N+1] ------------------------------------------------------------------ CPU-thread-0 {COW_step0: {mmu_notifier_invalidate_range_start(addrA)}} CPU-thread-1 {COW_step0: {mmu_notifier_invalidate_range_start(addrB)}} CPU-thread-2 {} CPU-thread-3 {} DEV-thread-0 {} DEV-thread-2 {} [Time N+2] ------------------------------------------------------------------ CPU-thread-0 {COW_step1: {更新页表以指å‘addrA的新页}} CPU-thread-1 {COW_step1: {更新页表以指å‘addrB的新页}} CPU-thread-2 {} CPU-thread-3 {} DEV-thread-0 {} DEV-thread-2 {} [Time N+3] ------------------------------------------------------------------ CPU-thread-0 {preempted} CPU-thread-1 {preempted} CPU-thread-2 {写入addrA,这是对新页é¢çš„写入} CPU-thread-3 {} DEV-thread-0 {} DEV-thread-2 {} [Time N+3] ------------------------------------------------------------------ CPU-thread-0 {preempted} CPU-thread-1 {preempted} CPU-thread-2 {} CPU-thread-3 {写入addrB,这是一个写入新页的过程} DEV-thread-0 {} DEV-thread-2 {} [Time N+4] ------------------------------------------------------------------ CPU-thread-0 {preempted} CPU-thread-1 {COW_step3: {mmu_notifier_invalidate_range_end(addrB)}} CPU-thread-2 {} CPU-thread-3 {} DEV-thread-0 {} DEV-thread-2 {} [Time N+5] ------------------------------------------------------------------ CPU-thread-0 {preempted} CPU-thread-1 {} CPU-thread-2 {} CPU-thread-3 {} DEV-thread-0 {从旧页ä¸è¯»å–addrA} DEV-thread-2 {从新页é¢è¯»å–addrB} æ‰€ä»¥åœ¨è¿™é‡Œï¼Œå› ä¸ºåœ¨N+2的时候,清空页表项没有和通知一起作废二级TLB,设备在看到addrAçš„æ–°å€¼ä¹‹å‰ å°±çœ‹åˆ°äº†addrBçš„æ–°å€¼ã€‚è¿™å°±ç ´å了设备的总内å˜åºã€‚ 当改å˜ä¸€ä¸ªpte的写ä¿æŠ¤æˆ–指å‘一个新的具有相åŒå†…容的写ä¿æŠ¤é¡µï¼ˆKSM)时,将mmu_notifier_invalidate_range 调用延迟到页表é”外的mmu_notifier_invalidate_range_end()是å¯ä»¥çš„。å³ä½¿åšé¡µè¡¨æ›´æ–°çš„线程 在释放页表é”åŽä½†åœ¨è°ƒç”¨mmu_notifier_invalidate_range_end()å‰è¢«æŠ¢å ,也是如æ¤ã€‚