.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/mm/highmem.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> :æ ¡è¯‘: ========== 高内å˜å¤„ç† ========== 作者: Peter Zijlstra <a.p.zijlstra@chello.nl> .. contents:: :local: é«˜å†…å˜æ˜¯ä»€ä¹ˆï¼Ÿ ============== 当物ç†å†…å˜çš„å¤§å°æŽ¥è¿‘æˆ–è¶…è¿‡è™šæ‹Ÿå†…å˜çš„æœ€å¤§å¤§å°æ—¶ï¼Œå°±ä¼šä½¿ç”¨é«˜å†…å˜ï¼ˆhighmem)。在这一点上,内 æ ¸ä¸å¯èƒ½åœ¨ä»»ä½•æ—¶å€™éƒ½ä¿æŒæ‰€æœ‰å¯ç”¨çš„物ç†å†…å˜çš„æ˜ 射。这æ„味ç€å†…æ ¸éœ€è¦å¼€å§‹ä½¿ç”¨å®ƒæƒ³è®¿é—®çš„物ç†å†… å˜çš„ä¸´æ—¶æ˜ å°„ã€‚ æ²¡æœ‰è¢«æ°¸ä¹…æ˜ å°„è¦†ç›–çš„é‚£éƒ¨åˆ†ï¼ˆç‰©ç†ï¼‰å†…å˜å°±æ˜¯æˆ‘们所说的 "高内å˜"。对于这个边界的确切ä½ç½®ï¼Œæœ‰ å„ç§æž¶æž„上的é™åˆ¶ã€‚ 例如,在i386æž¶æž„ä¸ï¼Œæˆ‘ä»¬é€‰æ‹©å°†å†…æ ¸æ˜ å°„åˆ°æ¯ä¸ªè¿›ç¨‹çš„è™šæ‹Ÿç©ºé—´ï¼Œè¿™æ ·æˆ‘ä»¬å°±ä¸å¿…ä¸ºå†…æ ¸çš„è¿›å…¥/退 出付出全部的TLB作废代价。这æ„味ç€å¯ç”¨çš„虚拟内å˜ç©ºé—´ï¼ˆi386上为4GiBï¼‰å¿…é¡»åœ¨ç”¨æˆ·å’Œå†…æ ¸ç©ºé—´ä¹‹ 间进行划分。 ä½¿ç”¨è¿™ç§æ–¹æ³•çš„æž¶æž„çš„ä¼ ç»Ÿåˆ†é…æ–¹å¼æ˜¯3:1,3GiB用于用户空间,顶部的1GiBç”¨äºŽå†…æ ¸ç©ºé—´ã€‚:: +--------+ 0xffffffff | Kernel | +--------+ 0xc0000000 | | | User | | | +--------+ 0x00000000 è¿™æ„味ç€å†…æ ¸åœ¨ä»»ä½•æ—¶å€™æœ€å¤šå¯ä»¥æ˜ å°„1GiB的物ç†å†…å˜ï¼Œä½†æ˜¯ç”±äºŽæˆ‘们需è¦è™šæ‹Ÿåœ°å€ç©ºé—´æ¥åšå…¶ä»–事 情--包括访问其余物ç†å†…å˜çš„ä¸´æ—¶æ˜ å°„--å®žé™…çš„ç›´æŽ¥æ˜ å°„é€šå¸¸ä¼šæ›´å°‘ï¼ˆé€šå¸¸åœ¨~896MiBå·¦å³ï¼‰ã€‚ 其他有mmä¸Šä¸‹æ–‡æ ‡ç¾çš„TLB的架构å¯ä»¥æœ‰ç‹¬ç«‹çš„å†…æ ¸å’Œç”¨æˆ·æ˜ å°„ã€‚ç„¶è€Œï¼Œä¸€äº›ç¡¬ä»¶ï¼ˆå¦‚ä¸€äº›ARM)在使 用mmä¸Šä¸‹æ–‡æ ‡ç¾æ—¶ï¼Œå…¶è™šæ‹Ÿç©ºé—´æœ‰é™ã€‚ ä¸´æ—¶è™šæ‹Ÿæ˜ å°„ ============ å†…æ ¸åŒ…å«å‡ ç§åˆ›å»ºä¸´æ—¶æ˜ 射的方法。下é¢çš„åˆ—è¡¨æŒ‰ç…§ä½¿ç”¨çš„ä¼˜å…ˆé¡ºåºæ˜¾ç¤ºäº†å®ƒä»¬ã€‚ * kmap_local_page()。这个函数是用æ¥è¦æ±‚çŸæœŸæ˜ 射的。它å¯ä»¥ä»Žä»»ä½•ä¸Šä¸‹æ–‡ï¼ˆåŒ…æ‹¬ä¸æ–)ä¸è°ƒç”¨ï¼Œ ä½†æ˜¯æ˜ å°„åªèƒ½åœ¨èŽ·å–它们的上下文ä¸ä½¿ç”¨ã€‚ 在å¯è¡Œçš„æƒ…况下,这个函数应该比其他所有的函数优先使用。 è¿™äº›æ˜ å°„æ˜¯çº¿ç¨‹æœ¬åœ°å’ŒCPU本地的,这æ„å‘³ç€æ˜ å°„åªèƒ½ä»Žè¿™ä¸ªçº¿ç¨‹ä¸è®¿é—®ï¼Œå¹¶ä¸”å½“æ˜ å°„å¤„äºŽæ´»è·ƒçŠ¶ æ€æ—¶ï¼Œçº¿ç¨‹è¢«ç»‘定到CPUä¸Šã€‚å°½ç®¡è¿™ä¸ªå‡½æ•°ä»Žæ¥æ²¡æœ‰ç¦ç”¨è¿‡æŠ¢å ï¼Œä½†åœ¨æ˜ å°„è¢«å¤„ç†ä¹‹å‰ï¼ŒCPUä¸èƒ½ 通过CPU-hotplugä»Žç³»ç»Ÿä¸æ‹”出。 在本地的kmap区域ä¸é‡‡å–pagefaults是有效的,除éžèŽ·å–æœ¬åœ°æ˜ å°„çš„ä¸Šä¸‹æ–‡ç”±äºŽå…¶ä»–åŽŸå› ä¸å…许 è¿™æ ·åšã€‚ 如剿‰€è¿°ï¼Œç¼ºé¡µå¼‚常和抢å 从未被ç¦ç”¨ã€‚没有必è¦ç¦ç”¨æŠ¢å ï¼Œå› ä¸ºå½“ä¸Šä¸‹æ–‡åˆ‡æ¢åˆ°ä¸€ä¸ªä¸åŒçš„任务 æ—¶ï¼Œç¦»å¼€çš„ä»»åŠ¡çš„æ˜ å°„è¢«ä¿å˜ï¼Œè€Œè¿›å…¥çš„ä»»åŠ¡çš„æ˜ å°„è¢«æ¢å¤ã€‚ kmap_local_page()总是返回一个有效的虚拟地å€ï¼Œå¹¶ä¸”å‡å®škunmap_local()ä¸ä¼šå¤±è´¥ã€‚ 在CONFIG_HIGHMEM=nçš„å†…æ ¸ä¸ï¼Œå¯¹äºŽä½Žå†…å˜é¡µï¼Œå®ƒè¿”å›žç›´æŽ¥æ˜ å°„çš„è™šæ‹Ÿåœ°å€ã€‚åªæœ‰çœŸæ£çš„高内 å˜é¡µé¢æ‰ä¼šè¢«ä¸´æ—¶æ˜ å°„ã€‚å› æ¤ï¼Œç”¨æˆ·å¯ä»¥ä¸ºé‚£äº›å·²çŸ¥ä¸æ˜¯æ¥è‡ªZONE_HIGHMEM的页é¢è°ƒç”¨æ™®é€šçš„ page_address()。然而,使用kmap_local_page() / kunmap_local()总是安全的。 虽然它比kmap()快得多,但在高内å˜çš„æƒ…况下,它对指针的有效性有é™åˆ¶ã€‚与kmap()æ˜ å°„ç›¸å, æœ¬åœ°æ˜ å°„åªåœ¨è°ƒç”¨è€…çš„ä¸Šä¸‹æ–‡ä¸æœ‰æ•ˆï¼Œä¸èƒ½ä¼ 递给其他上下文。这æ„味ç€ç”¨æˆ·å¿…é¡»ç»å¯¹ä¿è¯è¿”回 地å€çš„使用åªé™äºŽæ˜ 射它的线程。 大多数代ç å¯ä»¥è¢«è®¾è®¡æˆä½¿ç”¨çº¿ç¨‹æœ¬åœ°æ˜ å°„ã€‚å› æ¤ï¼Œç”¨æˆ·åœ¨è®¾è®¡ä»–ä»¬çš„ä»£ç æ—¶ï¼Œåº”该尽é‡é¿å…使用 kmap()ï¼Œå°†é¡µé¢æ˜ 射到将被使用的åŒä¸€çº¿ç¨‹ä¸ï¼Œå¹¶ä¼˜å…ˆä½¿ç”¨kmap_local_page()。 嵌套kmap_local_page()å’Œkmap_atomic()æ˜ å°„åœ¨ä¸€å®šç¨‹åº¦ä¸Šæ˜¯å…许的(最多到KMAP_TYPE_NR), ä½†æ˜¯å®ƒä»¬çš„è°ƒç”¨å¿…é¡»ä¸¥æ ¼æŽ’åºï¼Œå› ä¸ºæ˜ å°„çš„å®žçŽ°æ˜¯åŸºäºŽå †æ ˆçš„ã€‚å…³äºŽå¦‚ä½•ç®¡ç†åµŒå¥—æ˜ å°„çš„ç»†èŠ‚ï¼Œ 请å‚è§kmap_local_page() kdocs(包å«åœ¨ "函数 "部分)。 * kmap_atomic(). è¿™å…许对å•个页é¢è¿›è¡Œéžå¸¸çŸçš„æ—¶é—´æ˜ å°„ã€‚ç”±äºŽæ˜ å°„è¢«é™åˆ¶åœ¨å‘布它的CPU上, 它表现得很好,但å‘å¸ƒçš„ä»»åŠ¡å› æ¤è¢«è¦æ±‚留在该CPU上直到它完æˆï¼Œä»¥å…其他任务å–ä»£å®ƒçš„æ˜ å°„ã€‚ kmap_atomic()也å¯ä»¥è¢«ä¸æ–ä¸Šä¸‹æ–‡ä½¿ç”¨ï¼Œå› ä¸ºå®ƒä¸ç¡çœ ,调用者也å¯èƒ½åœ¨è°ƒç”¨kunmap_atomic() åŽæ‰ç¡çœ 。 å†…æ ¸ä¸å¯¹kmap_atomic()çš„æ¯æ¬¡è°ƒç”¨éƒ½ä¼šåˆ›å»ºä¸€ä¸ªä¸å¯æŠ¢å 的段,并ç¦ç”¨ç¼ºé¡µå¼‚常。这å¯èƒ½æ˜¯ æœªé¢„æœŸå»¶è¿Ÿçš„æ¥æºä¹‹ä¸€ã€‚å› æ¤ç”¨æˆ·åº”该选择kmap_local_page()è€Œä¸æ˜¯kmap_atomic()。 å‡è®¾k[un]map_atomic()ä¸ä¼šå¤±è´¥ã€‚ * kmap()。这应该被用æ¥å¯¹å•个页é¢è¿›è¡ŒçŸæ—¶é—´çš„æ˜ å°„ï¼Œå¯¹æŠ¢å æˆ–è¿ç§»æ²¡æœ‰é™åˆ¶ã€‚它会带æ¥å¼€é”€ï¼Œ å› ä¸ºæ˜ å°„ç©ºé—´æ˜¯å—é™åˆ¶çš„,并且å—到全局é”çš„ä¿æŠ¤ï¼Œä»¥å®žçŽ°åŒæ¥ã€‚当ä¸å†éœ€è¦æ˜ 射时,必须用 kunmap()é‡Šæ”¾è¯¥é¡µè¢«æ˜ å°„çš„åœ°å€ã€‚ æ˜ å°„å˜åŒ–必须广æ’到所有CPUï¼ˆæ ¸ï¼‰ä¸Šï¼Œkmap()还需è¦åœ¨kmapçš„æ± è¢«å›žç»•ï¼ˆTLB项用光了,需è¦ä»Žç¬¬ 一项å¤ç”¨ï¼‰æ—¶è¿›è¡Œå…¨å±€TLBæ— æ•ˆåŒ–ï¼Œå½“æ˜ å°„ç©ºé—´è¢«å®Œå…¨åˆ©ç”¨æ—¶ï¼Œå®ƒå¯èƒ½ä¼šé˜»å¡žï¼Œç›´åˆ°æœ‰ä¸€ä¸ªå¯ç”¨çš„ æ§½å‡ºçŽ°ã€‚å› æ¤ï¼Œkmap()åªèƒ½ä»Žå¯æŠ¢å 的上下文ä¸è°ƒç”¨ã€‚ å¦‚æžœä¸€ä¸ªæ˜ å°„å¿…é¡»æŒç»ç›¸å¯¹è¾ƒé•¿çš„æ—¶é—´ï¼Œä¸Šè¿°æ‰€æœ‰çš„工作都是必è¦çš„ï¼Œä½†æ˜¯å†…æ ¸ä¸å¤§éƒ¨åˆ†çš„ é«˜å†…å˜æ˜ å°„éƒ½æ˜¯çŸæš‚的,而且åªåœ¨ä¸€ä¸ªåœ°æ–¹ä½¿ç”¨ã€‚è¿™æ„味ç€åœ¨è¿™ç§æƒ…况下,kmap()çš„æˆæœ¬å¤§ 多被浪费了。kmap()并䏿˜¯ä¸ºé•¿æœŸæ˜ å°„è€Œè®¾è®¡çš„ï¼Œä½†æ˜¯å®ƒå·²ç»æœç€è¿™ä¸ªæ–¹å‘å‘展了,在较新 的代ç ä¸å¼ºçƒˆä¸é¼“励使用它,å‰é¢çš„函数集应该是首选。 在64ä½ç³»ç»Ÿä¸ï¼Œè°ƒç”¨kmap_local_page()ã€kmap_atomic()å’Œkmap()æ²¡æœ‰å®žé™…ä½œç”¨ï¼Œå› ä¸º64ä½ åœ°å€ç©ºé—´è¶³ä»¥æ°¸ä¹…æ˜ å°„æ‰€æœ‰ç‰©ç†å†…å˜é¡µé¢ã€‚ * vmap()。这å¯ä»¥ç”¨æ¥å°†å¤šä¸ªç‰©ç†é¡µé•¿æœŸæ˜ 射到一个连ç»çš„虚拟空间。它需è¦å…¨å±€åŒæ¥æ¥è§£é™¤ æ˜ å°„ã€‚ ä¸´æ—¶æ˜ å°„çš„æˆæœ¬ ============== åˆ›å»ºä¸´æ—¶æ˜ å°„çš„ä»£ä»·å¯èƒ½ç›¸å½“高。体系架构必须æ“ä½œå†…æ ¸çš„é¡µè¡¨ã€æ•°æ®TLBå’Œ/或MMU的寄å˜å™¨ã€‚ 如果CONFIG_HIGHMEMæ²¡æœ‰è¢«è®¾ç½®ï¼Œé‚£ä¹ˆå†…æ ¸ä¼šå°è¯•用一点计算æ¥åˆ›å»ºæ˜ 射,将页é¢ç»“构地å€è½¬æ¢æˆ 指å‘页é¢å†…å®¹çš„æŒ‡é’ˆï¼Œè€Œä¸æ˜¯åŽ»æ£é¼“æ˜ å°„ã€‚åœ¨è¿™ç§æƒ…å†µä¸‹ï¼Œè§£æ˜ å°„æ“作å¯èƒ½æ˜¯ä¸€ä¸ªç©ºæ“作。 如果CONFIG_MMU没有被设置,那么就ä¸å¯èƒ½æœ‰ä¸´æ—¶æ˜ 射和高内å˜ã€‚åœ¨è¿™ç§æƒ…况下,也将使用计算方法。 i386 PAE ======== 在æŸäº›æƒ…况下,i386 架构将å…è®¸ä½ åœ¨ 32 使œºå™¨ä¸Šå®‰è£…多达 64GiB 的内å˜ã€‚ä½†è¿™æœ‰ä¸€äº›åŽæžœ: * Linux需è¦ä¸ºç³»ç»Ÿä¸çš„æ¯ä¸ªé¡µé¢å»ºç«‹ä¸€ä¸ªé¡µå¸§ç»“构,而且页帧需è¦é©»åœ¨æ°¸ä¹…æ˜ å°„ä¸ï¼Œè¿™æ„味ç€ï¼š * ä½ æœ€å¤šå¯ä»¥æœ‰896M/sizeof(struct page)页帧;由于页结构体是32å—节的,所以最终会有 112Gçš„é¡µï¼›ç„¶è€Œï¼Œå†…æ ¸éœ€è¦åœ¨å†…å˜ä¸å˜å‚¨æ›´å¤šçš„页帧...... * PAEä½¿ä½ çš„é¡µè¡¨å˜å¤§--è¿™ä½¿ç³»ç»Ÿå˜æ…¢ï¼Œå› 为更多的数æ®éœ€è¦åœ¨TLBå¡«å……ç‰æ–¹é¢è¢«è®¿é—®ã€‚一个好处 是,PAE有更多的PTEä½ï¼Œå¯ä»¥æä¾›åƒNXå’ŒPATè¿™æ ·çš„é«˜çº§åŠŸèƒ½ã€‚ ä¸€èˆ¬çš„å»ºè®®æ˜¯ï¼Œä½ ä¸è¦åœ¨32使œºå™¨ä¸Šä½¿ç”¨è¶…过8GiB的空间--尽管更多的空间å¯èƒ½å¯¹ä½ å’Œä½ çš„å·¥ä½œ 釿œ‰ç”¨ï¼Œä½†ä½ å‡ ä¹Žæ˜¯é ä½ è‡ªå·±--ä¸è¦æŒ‡æœ›å†…æ ¸å¼€å‘者真的会很关心事情的进展情况。 函数 ==== 该APIåœ¨ä»¥ä¸‹å†…æ ¸ä»£ç ä¸: include/linux/highmem.h include/linux/highmem-internal.h