.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/mm/hugetlbfs_reserv.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> :æ ¡è¯‘: ============== Hugetlbfs 预留 ============== 概述 ==== :ref:`hugetlbpage` ä¸æ述的巨页通常是预先分é…给应用程åºä½¿ç”¨çš„。如果VMA指 示è¦ä½¿ç”¨å·¨é¡µï¼Œè¿™äº›å·¨é¡µä¼šåœ¨ç¼ºé¡µå¼‚常时被实例化到任务的地å€ç©ºé—´ã€‚如果在缺页异常 时没有巨页å˜åœ¨ï¼Œä»»åŠ¡å°±ä¼šè¢«å‘é€ä¸€ä¸ªSIGBUS,并ç»å¸¸ä¸é«˜å…´åœ°æ»åŽ»ã€‚åœ¨åŠ å…¥å·¨é¡µæ”¯ æŒåŽä¸ä¹…,人们决定,在mmap()时检测巨页的çŸç¼ºæƒ…况会更好。这个想法是,如果 没有足够的巨页æ¥è¦†ç›–æ˜ å°„ï¼Œmmap()将失败。这首先是在mmap()时在代ç ä¸åšä¸€ä¸ª 简å•çš„检查,以确定是å¦æœ‰è¶³å¤Ÿçš„空闲巨页æ¥è¦†ç›–æ˜ å°„ã€‚å°±åƒå†…æ ¸ä¸çš„大多数东西一 æ ·ï¼Œä»£ç éšç€æ—¶é—´çš„推移而ä¸æ–å‘展。然而,基本的想法是在mmap()æ—¶ “预留†巨页,以确ä¿å·¨é¡µå¯ä»¥ç”¨äºŽè¯¥æ˜ å°„ä¸çš„缺页异常。下é¢çš„æ述试图æ述在v4.10å†…æ ¸ ä¸æ˜¯å¦‚何进行巨页预留处ç†çš„。 读者 ==== 这个æ述主è¦æ˜¯é’ˆå¯¹æ£åœ¨ä¿®æ”¹hugetlbfs代ç çš„å†…æ ¸å¼€å‘者。 æ•°æ®ç»“æž„ ======== resv_huge_pages 这是一个全局的(per-hstate)预留的巨页的计数。预留的巨页åªå¯¹é¢„留它们的任 务å¯ç”¨ã€‚å› æ¤ï¼Œä¸€èˆ¬å¯ç”¨çš„巨页的数é‡è¢«è®¡ç®—为(``free_huge_pages - resv_huge_pages``)。 Reserve Map é¢„ç•™æ˜ å°„ç”±ä»¥ä¸‹ç»“æž„ä½“æè¿°:: struct resv_map { struct kref refs; spinlock_t lock; struct list_head regions; long adds_in_progress; struct list_head region_cache; long region_cache_count; }; 系统ä¸æ¯ä¸ªå·¨é¡µæ˜ å°„éƒ½æœ‰ä¸€ä¸ªé¢„ç•™æ˜ å°„ã€‚resv_mapä¸çš„regions列表æè¿°äº†æ˜ å°„ä¸çš„ 区域。一个区域被æ述为:: struct file_region { struct list_head link; long from; long to; }; file_region结构体的 ‘from’ å’Œ ‘to’ å—æ®µæ˜¯è¿›å…¥æ˜ å°„çš„å·¨é¡µç´¢å¼•ã€‚æ ¹æ®æ˜ 射的类型,在 reserv_map ä¸çš„一个区域å¯èƒ½è¡¨ç¤ºè¯¥èŒƒå›´å˜åœ¨é¢„留,或预留ä¸å˜åœ¨ã€‚ Flags for MAP_PRIVATE Reservations 这些被å˜å‚¨åœ¨é¢„ç•™çš„æ˜ å°„æŒ‡é’ˆçš„åº•éƒ¨ã€‚ ``#define HPAGE_RESV_OWNER (1UL << 0)`` è¡¨ç¤ºè¯¥ä»»åŠ¡æ˜¯ä¸Žè¯¥æ˜ å°„ç›¸å…³çš„é¢„ç•™çš„æ‰€æœ‰è€…ã€‚ ``#define HPAGE_RESV_UNMAPPED (1UL << 1)`` 表示最åˆæ˜ å°„æ¤èŒƒå›´ï¼ˆå¹¶åˆ›å»ºå‚¨å¤‡ï¼‰çš„任务由于COW失败而从该任务(å任务)ä¸å–æ¶ˆæ˜ å°„äº†ä¸€ä¸ªé¡µé¢ã€‚ Page Flags PagePrivate页é¢æ ‡å¿—是用æ¥æŒ‡ç¤ºåœ¨é‡Šæ”¾å·¨é¡µæ—¶å¿…é¡»æ¢å¤å·¨é¡µçš„预留。更多细节将在 “释放巨页†一节ä¸è®¨è®ºã€‚ é¢„ç•™æ˜ å°„ä½ç½®ï¼ˆç§æœ‰æˆ–共享) ========================== ä¸€ä¸ªå·¨é¡µæ˜ å°„æˆ–æ®µè¦ä¹ˆæ˜¯ç§æœ‰çš„,è¦ä¹ˆæ˜¯å…±äº«çš„。如果是ç§æœ‰çš„,它通常åªå¯¹ä¸€ä¸ªåœ°å€ç©ºé—´ (任务)å¯ç”¨ã€‚如果是共享的,它å¯ä»¥è¢«æ˜ 射到多个地å€ç©ºé—´ï¼ˆä»»åŠ¡ï¼‰ã€‚对于这两ç§ç±»åž‹çš„æ˜ å°„ï¼Œ é¢„ç•™æ˜ å°„çš„ä½ç½®å’Œè¯ä¹‰æ˜¯æ˜Žæ˜¾ä¸åŒçš„。ä½ç½®çš„差异是: - 对于ç§æœ‰æ˜ å°„ï¼Œé¢„ç•™æ˜ å°„æŒ‚åœ¨VMA结构体上。具体æ¥è¯´ï¼Œå°±æ˜¯vma->vm_private_dataã€‚è¿™ä¸ªä¿ ç•™æ˜ å°„æ˜¯åœ¨åˆ›å»ºæ˜ å°„ï¼ˆmmap(MAP_PRIVATE))时创建的。 - å¯¹äºŽå…±äº«æ˜ å°„ï¼Œé¢„ç•™æ˜ å°„æŒ‚åœ¨inode上。具体æ¥è¯´ï¼Œå°±æ˜¯inode->i_mapping->private_data。 ç”±äºŽå…±äº«æ˜ å°„æ€»æ˜¯ç”±hugetlbfs文件系统ä¸çš„文件支æŒï¼Œhugetlbfs代ç ç¡®ä¿æ¯ä¸ªèŠ‚点包å«ä¸€ä¸ªé¢„ ç•™æ˜ å°„ã€‚å› æ¤ï¼Œé¢„ç•™æ˜ å°„åœ¨åˆ›å»ºèŠ‚ç‚¹æ—¶è¢«åˆ†é…。 创建预留 ======== 当创建一个巨大的有页é¢æ”¯æŒçš„共享内å˜æ®µï¼ˆshmget(SHM_HUGETLB))或通过mmap(MAP_HUGETLB) åˆ›å»ºä¸€ä¸ªæ˜ å°„æ—¶ï¼Œå°±ä¼šåˆ›å»ºé¢„ç•™ã€‚è¿™äº›æ“作会导致对函数hugetlb_reserve_pages()的调用:: int hugetlb_reserve_pages(struct inode *inode, long from, long to, struct vm_area_struct *vma, vm_flags_t vm_flags) hugetlb_reserve_pages()åšçš„第一件事是检查在调用shmget()或mmap()时是å¦æŒ‡å®šäº†NORESERVE æ ‡å¿—ã€‚å¦‚æžœæŒ‡å®šäº†NORESERVE,那么这个函数立å³è¿”å›žï¼Œå› ä¸ºä¸éœ€è¦é¢„留。 å‚æ•°'from'å’Œ'to'æ˜¯æ˜ å°„æˆ–åŸºç¡€æ–‡ä»¶çš„å·¨é¡µç´¢å¼•ã€‚å¯¹äºŽshmget(),'from'总是0,'to'对应于段/æ˜ å°„ 的长度。对于mmap(),offsetå‚æ•°å¯ä»¥ç”¨æ¥æŒ‡å®šè¿›å…¥åº•å±‚文件的å移é‡ã€‚在这ç§æƒ…况下,'from'å’Œ'to' å‚æ•°å·²ç»è¢«è¿™ä¸ªå移é‡æ‰€è°ƒæ•´ã€‚ PRIVATEå’ŒSHAREDæ˜ å°„ä¹‹é—´çš„ä¸€ä¸ªå¾ˆå¤§çš„åŒºåˆ«æ˜¯é¢„ç•™åœ¨é¢„ç•™æ˜ å°„ä¸çš„表示方å¼ã€‚ - å¯¹äºŽå…±äº«æ˜ å°„ï¼Œé¢„ç•™æ˜ å°„ä¸çš„æ¡ç›®è¡¨ç¤ºå¯¹åº”页é¢çš„预留å˜åœ¨æˆ–曾ç»å˜åœ¨ã€‚å½“é¢„ç•™è¢«æ¶ˆè€—æ—¶ï¼Œé¢„ç•™æ˜ å°„ä¸è¢« 修改。 - 对于ç§æœ‰æ˜ å°„ï¼Œé¢„ç•™æ˜ å°„ä¸æ²¡æœ‰æ¡ç›®è¡¨ç¤ºç›¸åº”页é¢å˜åœ¨é¢„留。éšç€é¢„留被消耗,æ¡ç›®è¢«æ·»åŠ åˆ°é¢„ç•™æ˜ å°„ä¸ã€‚ å› æ¤ï¼Œé¢„ç•™æ˜ å°„ä¹Ÿå¯ç”¨äºŽç¡®å®šå“ªäº›é¢„留已被消耗。 对于ç§æœ‰æ˜ 射,hugetlb_reserve_pages()åˆ›å»ºé¢„ç•™æ˜ å°„å¹¶å°†å…¶æŒ‚åœ¨VMA结构体上。æ¤å¤–, HPAGE_RESV_OWNERæ ‡å¿—è¢«è®¾ç½®ï¼Œä»¥è¡¨æ˜Žè¯¥VMA拥有预留。 é¢„ç•™æ˜ å°„è¢«æŸ¥é˜…ä»¥ç¡®å®šå½“å‰æ˜ å°„/段需è¦å¤šå°‘巨页预留。对于ç§æœ‰æ˜ 射,这始终是一个值(to - from)。 ç„¶è€Œï¼Œå¯¹äºŽå…±äº«æ˜ å°„æ¥è¯´ï¼Œä¸€äº›é¢„ç•™å¯èƒ½å·²ç»å˜åœ¨äºŽ(to - from)的范围内。关于如何实现这一点的细节, 请å‚è§ :ref:`é¢„ç•™æ˜ å°„çš„ä¿®æ”¹ <resv_map_modifications>` 一节。 è¯¥æ˜ å°„å¯èƒ½ä¸Žä¸€ä¸ªåæ± ï¼ˆsubpool)相关è”ã€‚å¦‚æžœæ˜¯è¿™æ ·ï¼Œå°†æŸ¥è¯¢åæ± ä»¥ç¡®ä¿æœ‰è¶³å¤Ÿçš„ç©ºé—´ç”¨äºŽæ˜ å°„ã€‚åæ± æœ‰å¯èƒ½å·²ç»é¢„留了å¯ç”¨äºŽæ˜ 射的预留空间。更多细节请å‚è§ :ref: `åæ± é¢„ç•™ <sub_pool_resv>` 一节。 åœ¨å’¨è¯¢äº†é¢„ç•™æ˜ å°„å’Œåæ± ä¹‹åŽï¼Œå°±çŸ¥é“了需è¦çš„新预留数é‡ã€‚hugetlb_acct_memory()函数被调用以检查 并获å–所è¦æ±‚的预留数é‡ã€‚hugetlb_acct_memory()调用到å¯èƒ½åˆ†é…和调整剩余页数的函数。然而,在这 些函数ä¸ï¼Œä»£ç åªæ˜¯æ£€æŸ¥ä»¥ç¡®ä¿æœ‰è¶³å¤Ÿçš„空闲的巨页æ¥å®¹çº³é¢„留。如果有的è¯ï¼Œå…¨å±€é¢„留计数resv_huge_pages 会被调整,如下所示:: if (resv_needed <= (resv_huge_pages - free_huge_pages)) resv_huge_pages += resv_needed; 注æ„,在检查和调整这些计数器时,全局é”hugetlb_lock会被预留。 如果有足够的空闲的巨页,并且全局计数resv_huge_pagesè¢«è°ƒæ•´ï¼Œé‚£ä¹ˆä¸Žæ˜ å°„ç›¸å…³çš„é¢„ç•™æ˜ å°„è¢«ä¿®æ”¹ä»¥ åæ˜ é¢„ç•™ã€‚åœ¨å…±äº«æ˜ å°„çš„æƒ…å†µä¸‹ï¼Œå°†å˜åœ¨ä¸€ä¸ªfile_region,包括'from'-'to'范围。对于ç§æœ‰æ˜ 射, ä¸å¯¹é¢„ç•™æ˜ å°„è¿›è¡Œä¿®æ”¹ï¼Œå› ä¸ºæ²¡æœ‰æ¡ç›®è¡¨ç¤ºå˜åœ¨é¢„留。 如果hugetlb_reserve_pages()æˆåŠŸï¼Œå…¨å±€é¢„ç•™æ•°å’Œä¸Žæ˜ å°„ç›¸å…³çš„é¢„ç•™æ˜ å°„å°†æ ¹æ®éœ€è¦è¢«ä¿®æ”¹ï¼Œä»¥ç¡®ä¿ 在'from'-'to'范围内å˜åœ¨é¢„留。 消耗预留/分é…一个巨页 =========================== å½“ä¸Žé¢„ç•™ç›¸å…³çš„å·¨é¡µåœ¨ç›¸åº”çš„æ˜ å°„ä¸è¢«åˆ†é…和实例化时,预留就被消耗了。该分é…是在函数alloc_huge_page() ä¸è¿›è¡Œçš„:: struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr, int avoid_reserve) alloc_huge_pageè¢«ä¼ é€’ç»™ä¸€ä¸ªVMA指针和一个虚拟地å€ï¼Œå› æ¤å®ƒå¯ä»¥æŸ¥é˜…é¢„ç•™æ˜ å°„ä»¥ç¡®å®šæ˜¯å¦å˜åœ¨é¢„留。 æ¤å¤–,alloc_huge_page需è¦ä¸€ä¸ªå‚æ•°avoid_reserve,该å‚数表示å³ä½¿çœ‹èµ·æ¥å·²ç»ä¸ºæŒ‡å®šçš„地å€é¢„留了 预留,也ä¸åº”该使用预留。avoid_reserveå‚数最常被用于写时拷è´å’Œé¡µé¢è¿ç§»çš„情况下,å³çŽ°æœ‰é¡µé¢çš„é¢ å¤–æ‹·è´è¢«åˆ†é…。 调用辅助函数vma_needs_reservation()æ¥ç¡®å®šæ˜¯å¦å˜åœ¨å¯¹æ˜ å°„(vma)ä¸åœ°å€çš„预留。关于这个函数的详 细内容,请å‚è§ :ref:`é¢„ç•™æ˜ å°„å¸®åŠ©å‡½æ•° <resv_map_helpers>` 一节。从 vma_needs_reservation()返回的值通常为0或1。如果该地å€å˜åœ¨é¢„留,则为0,如果ä¸å˜åœ¨é¢„留,则为1。 如果ä¸å˜åœ¨é¢„ç•™ï¼Œå¹¶ä¸”æœ‰ä¸€ä¸ªä¸Žæ˜ å°„ç›¸å…³è”çš„åæ± ï¼Œåˆ™æŸ¥è¯¢åæ± ä»¥ç¡®å®šå®ƒæ˜¯å¦åŒ…å«é¢„留。如果åæ± åŒ…å«é¢„留, 则å¯å°†å…¶ä¸ä¸€ä¸ªç”¨äºŽè¯¥åˆ†é…。然而,在任何情况下,avoid_reserveå‚数都会优先考虑为分é…使用预留。在 确定预留是å¦å˜åœ¨å¹¶å¯ç”¨äºŽåˆ†é…åŽï¼Œè°ƒç”¨dequeue_huge_page_vma()函数。这个函数需è¦ä¸¤ä¸ªä¸Žé¢„留有关 çš„å‚数: - avoid_reserveï¼Œè¿™æ˜¯ä¼ é€’ç»™alloc_huge_page()çš„åŒä¸€ä¸ªå€¼/å‚数。 - chg,尽管这个å‚数的类型是long,但åªæœ‰0或1çš„å€¼è¢«ä¼ é€’ç»™dequeue_huge_page_vma。如果该值为0, 则表明å˜åœ¨é¢„留(关于å¯èƒ½çš„问题,请å‚è§ â€œé¢„ç•™å’Œå†…å˜ç–略†一节)。如果值 为1,则表示ä¸å˜åœ¨é¢„留,如果å¯èƒ½çš„è¯ï¼Œå¿…é¡»ä»Žå…¨å±€ç©ºé—²æ± ä¸å–出该页。 与VMA的内å˜ç–略相关的空闲列表被æœç´¢åˆ°ä¸€ä¸ªç©ºé—²é¡µã€‚如果找到了一个页é¢ï¼Œå½“该页é¢ä»Žç©ºé—²åˆ—表ä¸ç§»é™¤æ—¶ï¼Œ free_huge_pages的值被递å‡ã€‚如果有一个与该页相关的预留,将进行以下调整:: SetPagePrivate(page); /* 表示分é…这个页é¢æ¶ˆè€—了一个预留, * 如果é‡åˆ°é”™è¯¯ï¼Œä»¥è‡³äºŽå¿…须释放这个页é¢ï¼Œé¢„留将被 * æ¢å¤ã€‚ */ resv_huge_pages--; /* å‡å°‘全局预留计数 */ 注æ„,如果找ä¸åˆ°æ»¡è¶³VMA内å˜ç–略的巨页,将å°è¯•ä½¿ç”¨ä¼™ä¼´åˆ†é…器分é…一个。这就带æ¥äº†è¶…出预留范围 的剩余巨页和超é¢åˆ†é…的问题。å³ä½¿åˆ†é…了一个多余的页é¢ï¼Œä¹Ÿä¼šè¿›è¡Œä¸Žä¸Šé¢ä¸€æ ·çš„基于预留的调整: SetPagePrivate(page) å’Œ resv_huge_pages--. 在获得一个新的巨页åŽï¼Œ(page)->private被设置为与该页é¢ç›¸å…³çš„åæ± çš„å€¼ï¼Œå¦‚æžœå®ƒå˜åœ¨çš„è¯ã€‚当页 é¢è¢«é‡Šæ”¾æ—¶ï¼Œè¿™å°†è¢«ç”¨äºŽåæ± çš„è®¡æ•°ã€‚ 然åŽè°ƒç”¨å‡½æ•°vma_commit_reservation()ï¼Œæ ¹æ®é¢„ç•™çš„æ¶ˆè€—æƒ…å†µè°ƒæ•´é¢„ç•™æ˜ å°„ã€‚ä¸€èˆ¬æ¥è¯´ï¼Œè¿™æ¶‰åŠ 到确ä¿é¡µé¢åœ¨åŒºåŸŸæ˜ å°„çš„file_region结构体ä¸è¢«è¡¨ç¤ºã€‚对于预留å˜åœ¨çš„å…±äº«æ˜ å°„ï¼Œé¢„ç•™æ˜ å°„ä¸çš„æ¡ç›® å·²ç»å˜åœ¨ï¼Œæ‰€ä»¥ä¸åšä»»ä½•æ”¹å˜ã€‚ç„¶è€Œï¼Œå¦‚æžœå…±äº«æ˜ å°„ä¸æ²¡æœ‰é¢„留,或者这是一个ç§æœ‰æ˜ 射,则必须创建一 个新的æ¡ç›®ã€‚ 注æ„,如果找ä¸åˆ°æ»¡è¶³VMA内å˜ç–略的巨页,将å°è¯•ä½¿ç”¨ä¼™ä¼´åˆ†é…器分é…一个。这就带æ¥äº†è¶…出预留范围 的剩余巨页和过度分é…的问题。å³ä½¿åˆ†é…了一个多余的页é¢ï¼Œä¹Ÿä¼šè¿›è¡Œä¸Žä¸Šé¢ä¸€æ ·çš„基于预留的调整。 SetPagePrivate(page)å’Œresv_huge_pages-。 在获得一个新的巨页åŽï¼Œ(page)->private被设置为与该页é¢ç›¸å…³çš„åæ± çš„å€¼ï¼Œå¦‚æžœå®ƒå˜åœ¨çš„è¯ã€‚当页 é¢è¢«é‡Šæ”¾æ—¶ï¼Œè¿™å°†è¢«ç”¨äºŽåæ± çš„è®¡æ•°ã€‚ 然åŽè°ƒç”¨å‡½æ•°vma_commit_reservation()ï¼Œæ ¹æ®é¢„ç•™çš„æ¶ˆè€—æƒ…å†µè°ƒæ•´é¢„ç•™æ˜ å°„ã€‚ä¸€èˆ¬æ¥è¯´ï¼Œè¿™æ¶‰åŠ 到确ä¿é¡µé¢åœ¨åŒºåŸŸæ˜ å°„çš„file_region结构体ä¸è¢«è¡¨ç¤ºã€‚对于预留å˜åœ¨çš„å…±äº«æ˜ å°„ï¼Œé¢„ç•™æ˜ å°„ä¸çš„æ¡ç›® å·²ç»å˜åœ¨ï¼Œæ‰€ä»¥ä¸åšä»»ä½•æ”¹å˜ã€‚ç„¶è€Œï¼Œå¦‚æžœå…±äº«æ˜ å°„ä¸æ²¡æœ‰é¢„留,或者这是一个ç§æœ‰æ˜ 射,则必须创建 一个新的æ¡ç›®ã€‚ 在alloc_huge_page()开始调用vma_needs_reservation()和页é¢åˆ†é…åŽè°ƒç”¨ vma_commit_reservation()ä¹‹é—´ï¼Œé¢„ç•™æ˜ å°„æœ‰å¯èƒ½è¢«æ”¹å˜ã€‚如果hugetlb_reserve_pages在共 äº«æ˜ å°„ä¸ä¸ºåŒä¸€é¡µé¢è¢«è°ƒç”¨ï¼Œè¿™å°†æ˜¯å¯èƒ½çš„。在这ç§æƒ…况下,预留计数和åæ± ç©ºé—²é¡µè®¡æ•°ä¼šæœ‰ä¸€ä¸ªå差。 è¿™ç§ç½•è§çš„情况å¯ä»¥é€šè¿‡æ¯”较vma_needs_reservationå’Œvma_commit_reservationçš„è¿”å›žå€¼æ¥ è¯†åˆ«ã€‚å¦‚æžœæ£€æµ‹åˆ°è¿™ç§ç«žäº‰ï¼Œåæ± å’Œå…¨å±€é¢„ç•™è®¡æ•°å°†è¢«è°ƒæ•´ä»¥è¿›è¡Œè¡¥å¿ã€‚关于这些函数的更多信æ¯ï¼Œè¯· å‚è§ :ref:`é¢„ç•™æ˜ å°„å¸®åŠ©å‡½æ•° <resv_map_helpers>` 一节。 实例化巨页 ========== 在巨页分é…之åŽï¼Œé¡µé¢é€šå¸¸è¢«æ·»åŠ 到分é…任务的页表ä¸ã€‚在æ¤ä¹‹å‰ï¼Œå…±äº«æ˜ å°„ä¸çš„页é¢è¢«æ·»åŠ 到页é¢ç¼“ å˜ä¸ï¼Œç§æœ‰æ˜ å°„ä¸çš„页é¢è¢«æ·»åŠ 到匿ååå‘æ˜ å°„ä¸ã€‚在这两ç§æƒ…况下,PagePrivateæ ‡å¿—è¢«æ¸…é™¤ã€‚å› æ¤ï¼Œ 当一个已ç»å®žä¾‹åŒ–的巨页被释放时,ä¸ä¼šå¯¹å…¨å±€é¢„留计数(resv_huge_pages)进行调整。 释放巨页 ======== 巨页释放是由函数free_huge_page()执行的。这个函数是hugetlbfså¤åˆé¡µçš„æžæž„å™¨ã€‚å› æ¤ï¼Œå®ƒåªä¼ 递一个指å‘页é¢ç»“构体的指针。当一个巨页被释放时,å¯èƒ½éœ€è¦è¿›è¡Œé¢„留计算。如果该页与包å«ä¿ 留的åæ± ç›¸å…³è”,或者该页在错误路径上被释放,必须æ¢å¤å…¨å±€é¢„留计数,就会出现这ç§æƒ…况。 page->privateå—段指å‘与该页相关的任何åæ± ã€‚å¦‚æžœPagePrivateæ ‡å¿—è¢«è®¾ç½®ï¼Œå®ƒè¡¨æ˜Žå…¨å±€é¢„ç•™è®¡æ•° åº”è¯¥è¢«è°ƒæ•´ï¼ˆå…³äºŽå¦‚ä½•è®¾ç½®è¿™äº›æ ‡å¿—çš„ä¿¡æ¯ï¼Œè¯·å‚è§ :ref: `消耗预留/分é…一个巨页 <consume_resv>` )。 该函数首先调用hugepage_subpool_put_pages()æ¥å¤„ç†è¯¥é¡µã€‚如果这个函数返回一个0的值(ä¸ç‰äºŽ ä¼ é€’çš„1的值),它表明预留与åæ± ç›¸å…³è”,这个新释放的页é¢å¿…须被用æ¥ä¿æŒåæ± é¢„ç•™çš„æ•°é‡è¶…过最å°å€¼ã€‚ å› æ¤ï¼Œåœ¨è¿™ç§æƒ…况下,全局resv_huge_pages计数器被递增。 如果页é¢ä¸è®¾ç½®äº†PagePrivateæ ‡å¿—ï¼Œé‚£ä¹ˆå…¨å±€resv_huge_pages计数器将永远被递增。 åæ± é¢„ç•™ ======== 有一个结构体hstate与æ¯ä¸ªå·¨é¡µå°ºå¯¸ç›¸å…³è”。hstate跟踪所有指定大å°çš„巨页。一个åæ± ä»£è¡¨ä¸€ 个hstateä¸çš„页é¢å集,它与一个已挂载的hugetlbfs文件系统相关 当一个hugetlbfs文件系统被挂载时,å¯ä»¥æŒ‡å®šmin_size选项,它表示文件系统所需的最å°çš„巨页数é‡ã€‚ 如果指定了这个选项,与min_size相对应的巨页的数é‡å°†è¢«é¢„留给文件系统使用。这个数å—在结构体 hugepage_subpoolçš„min_hpageså—段ä¸è¢«è·Ÿè¸ªã€‚在挂载时,hugetlb_acct_memory(min_hpages) 被调用以预留指定数é‡çš„巨页。如果它们ä¸èƒ½è¢«é¢„留,挂载就会失败。 当从åæ± ä¸èŽ·å–或释放页é¢æ—¶ï¼Œä¼šè°ƒç”¨hugepage_subpool_get/put_pages()函数。 hugepage_subpool_get/put_pagesè¢«ä¼ é€’ç»™å·¨é¡µæ•°é‡ï¼Œä»¥æ¤æ¥è°ƒæ•´åæ± çš„ “已用页é¢â€ 计数 (get为下é™ï¼Œput为上å‡ï¼‰ã€‚通常情况下,如果åæ± ä¸æ²¡æœ‰è¶³å¤Ÿçš„页é¢ï¼Œå®ƒä»¬ä¼šè¿”å›žä¸Žä¼ é€’çš„ç›¸åŒçš„值或 一个错误。 然而,如果预留与åæ± ç›¸å…³è”,å¯èƒ½ä¼šè¿”回一个å°äºŽä¼ 递值的返回值。这个返回值表示必须进行的é¢å¤–全局 æ± è°ƒæ•´çš„æ•°é‡ã€‚例如,å‡è®¾ä¸€ä¸ªåæ± åŒ…å«3个预留的巨页,有人è¦æ±‚5个。与åæ± ç›¸å…³çš„3个预留页å¯ä»¥ç”¨æ¥ æ»¡è¶³éƒ¨åˆ†è¯·æ±‚ã€‚ä½†æ˜¯ï¼Œå¿…é¡»ä»Žå…¨å±€æ± ä¸èŽ·å¾—2个页é¢ã€‚为了å‘调用者转达这一信æ¯ï¼Œå°†è¿”回值2。然åŽï¼Œè°ƒç”¨ 者è¦è´Ÿè´£ä»Žå…¨å±€æ± ä¸èŽ·å–å¦å¤–两个页é¢ã€‚ COW和预留 ========== ç”±äºŽå…±äº«æ˜ å°„éƒ½æŒ‡å‘并使用相åŒçš„底层页é¢ï¼ŒCOW最大的预留问题是ç§æœ‰æ˜ 射。在这ç§æƒ…å†µä¸‹ï¼Œä¸¤ä¸ªä»»åŠ¡å¯ ä»¥æŒ‡å‘åŒä¸€ä¸ªå…ˆå‰åˆ†é…的页é¢ã€‚一个任务试图写到该页,所以必须分é…一个新的页,以便æ¯ä¸ªä»»åŠ¡éƒ½æŒ‡å‘它 自己的页。 当该页最åˆè¢«åˆ†é…时,该页的预留被消耗了。当由于COW而试图分é…一个新的页é¢æ—¶ï¼Œæœ‰å¯èƒ½æ²¡æœ‰ç©ºé—²çš„å·¨ 页,分é…会失败。 当最åˆåˆ›å»ºç§æœ‰æ˜ å°„æ—¶ï¼Œé€šè¿‡è®¾ç½®æ‰€æœ‰è€…çš„é¢„ç•™æ˜ å°„æŒ‡é’ˆä¸çš„HPAGE_RESV_OWNERä½æ¥æ ‡è®°æ˜ 射的所有者。 ç”±äºŽæ‰€æœ‰è€…åˆ›å»ºäº†æ˜ å°„ï¼Œæ‰€æœ‰è€…æ‹¥æœ‰ä¸Žæ˜ å°„ç›¸å…³çš„æ‰€æœ‰é¢„ç•™ã€‚å› æ¤ï¼Œå½“一个写异常å‘生并且没有å¯ç”¨çš„é¡µé¢ æ—¶ï¼Œå¯¹é¢„ç•™çš„æ‰€æœ‰è€…å’Œéžæ‰€æœ‰è€…采å–ä¸åŒçš„行动。 在å‘生异常的任务ä¸æ˜¯æ‰€æœ‰è€…的情况下,异常将失败,该任务通常会收到一个SIGBUS。 如果所有者是å‘生异常的任务,我们希望它能够æˆåŠŸï¼Œå› 为它拥有原始的预留。为了达到这个目的,该页被 从éžæ‰€æœ‰è€…任务ä¸è§£æ˜ 射出æ¥ã€‚è¿™æ ·ä¸€æ¥ï¼Œå”¯ä¸€çš„引用就是æ¥è‡ªæ‹¥æœ‰è€…的任务。æ¤å¤–,HPAGE_RESV_UNMAPPED ä½è¢«è®¾ç½®åœ¨éžæ‹¥æœ‰ä»»åŠ¡çš„é¢„ç•™æ˜ å°„æŒ‡é’ˆä¸ã€‚如果éžæ‹¥æœ‰è€…任务åŽæ¥åœ¨ä¸€ä¸ªä¸å˜åœ¨çš„页é¢ä¸Šå‘生异常,它å¯èƒ½ 会收到一个SIGBUSã€‚ä½†æ˜¯ï¼Œæ˜ å°„/预留的原始拥有者的行为将与预期一致。 é¢„ç•™æ˜ å°„çš„ä¿®æ”¹ ============== ä»¥ä¸‹ä½Žçº§å‡½æ•°ç”¨äºŽå¯¹é¢„ç•™æ˜ å°„è¿›è¡Œä¿®æ”¹ã€‚é€šå¸¸æƒ…å†µä¸‹ï¼Œè¿™äº›å‡½æ•°ä¸ä¼šè¢«ç›´æŽ¥è°ƒç”¨ã€‚è€Œæ˜¯è°ƒç”¨ä¸€ä¸ªé¢„ç•™æ˜ å°„è¾… 助函数,该函数调用这些低级函数ä¸çš„一个。这些低级函数在æºä»£ç (mm/hugetlb.c)ä¸å¾—到了相当好的 记录。这些函数是:: long region_chg(struct resv_map *resv, long f, long t); long region_add(struct resv_map *resv, long f, long t); void region_abort(struct resv_map *resv, long f, long t); long region_count(struct resv_map *resv, long f, long t); åœ¨é¢„ç•™æ˜ å°„ä¸Šçš„æ“作通常涉åŠä¸¤ä¸ªæ“作: 1) region_chg()被调用æ¥æ£€æŸ¥é¢„ç•™æ˜ å°„ï¼Œå¹¶ç¡®å®šåœ¨æŒ‡å®šçš„èŒƒå›´[f, t]内有多少页目å‰æ²¡æœ‰è¢«ä»£è¡¨ã€‚ 调用代ç 执行全局检查和分é…,以确定是å¦æœ‰è¶³å¤Ÿçš„巨页使æ“作æˆåŠŸã€‚ 2) a) 如果æ“作能够æˆåŠŸï¼Œregi_add()将被调用,以实际修改先å‰ä¼ 递给regi_chg()的相åŒèŒƒå›´ [f, t]çš„é¢„ç•™æ˜ å°„ã€‚ b) 如果æ“作ä¸èƒ½æˆåŠŸï¼Œregion_abort被调用,在相åŒçš„范围[f, t]内ä¸æ¢æ“作。 注æ„,这是一个两æ¥çš„过程, region_add()å’Œ region_abort()在事先调用 region_chg()åŽä¿è¯ æˆåŠŸã€‚ region_chg()负责预先分é…任何必è¦çš„æ•°æ®ç»“构以确ä¿åŽç»æ“作(特别是 region_add())的 æˆåŠŸã€‚ 如上所述,region_chg()确定该范围内当å‰æ²¡æœ‰åœ¨æ˜ å°„ä¸è¡¨ç¤ºçš„页é¢çš„æ•°é‡ã€‚region_add()è¿”å›žæ·»åŠ åˆ°æ˜ å°„ä¸çš„范围内的页数。在大多数情况下, region_add() 的返回值与 region_chg() 的返回值相 åŒã€‚ç„¶è€Œï¼Œåœ¨å…±äº«æ˜ å°„çš„æƒ…å†µä¸‹ï¼Œæœ‰å¯èƒ½åœ¨è°ƒç”¨ region_chg() å’Œ region_add() ä¹‹é—´å¯¹é¢„ç•™æ˜ å°„è¿› 行更改。在这ç§æƒ…况下,regi_add()的返回值将与regi_chg()的返回值ä¸ç¬¦ã€‚在这ç§æƒ…况下,全局计数 å’Œåæ± è®¡æ•°å¾ˆå¯èƒ½æ˜¯ä¸æ£ç¡®çš„,需è¦è°ƒæ•´ã€‚检查这ç§æƒ…况并进行适当的调整是调用者的责任。 函数region_del()è¢«è°ƒç”¨ä»¥ä»Žé¢„ç•™æ˜ å°„ä¸ç§»é™¤åŒºåŸŸã€‚ 它通常在以下情况下被调用: - 当hugetlbfs文件系统ä¸çš„ä¸€ä¸ªæ–‡ä»¶è¢«åˆ é™¤æ—¶ï¼Œè¯¥èŠ‚ç‚¹å°†è¢«é‡Šæ”¾ï¼Œé¢„ç•™æ˜ å°„ä¹Ÿè¢«é‡Šæ”¾ã€‚åœ¨é‡Šæ”¾é¢„ç•™æ˜ å°„ 之å‰ï¼Œæ‰€æœ‰å•ç‹¬çš„file_region结构体必须被释放。在这ç§æƒ…况下,region_del的范围是[0, LONG_MAX]。 - 当一个hugetlbfs文件æ£åœ¨è¢«æˆªæ–时。在这ç§æƒ…况下,所有在新文件大å°ä¹‹åŽåˆ†é…的页é¢å¿…须被释放。 æ¤å¤–ï¼Œé¢„ç•™æ˜ å°„ä¸ä»»ä½•è¶…过新文件大å°çš„file_regionæ¡ç›®å¿…é¡»è¢«åˆ é™¤ã€‚åœ¨è¿™ç§æƒ…况下,region_del 的范围是[new_end_of_file, LONG_MAX]。 - 当在一个hugetlbfs文件ä¸æ‰“洞时。在这ç§æƒ…况下,巨页被一次次从文件的ä¸é—´ç§»é™¤ã€‚当这些页被移除 时,region_del()è¢«è°ƒç”¨ä»¥ä»Žé¢„ç•™æ˜ å°„ä¸ç§»é™¤ç›¸åº”çš„æ¡ç›®ã€‚在这ç§æƒ…况下,region_delè¢«ä¼ é€’çš„èŒƒ 围是[page_idx, page_idx + 1]。 在任何情况下,region_del()éƒ½ä¼šè¿”å›žä»Žé¢„ç•™æ˜ å°„ä¸åˆ 除的页é¢æ•°é‡ã€‚在éžå¸¸ç½•è§çš„情况下,region_del() 会失败。这åªèƒ½å‘生在打洞的情况下,å³å®ƒå¿…须分割一个现有的file_regionæ¡ç›®ï¼Œè€Œä¸èƒ½åˆ†é…一个新的 结构体。在这ç§é”™è¯¯æƒ…况下,region_del()将返回-ENOMEMã€‚è¿™é‡Œçš„é—®é¢˜æ˜¯ï¼Œé¢„ç•™æ˜ å°„å°†æ˜¾ç¤ºå¯¹è¯¥é¡µæœ‰ 预留。然而,åæ± å’Œå…¨å±€é¢„ç•™è®¡æ•°å°†ä¸åæ˜ è¯¥é¢„ç•™ã€‚ä¸ºäº†å¤„ç†è¿™ç§æƒ…况,调用函数hugetlb_fix_reserve_counts() æ¥è°ƒæ•´è®¡æ•°å™¨ï¼Œä½¿å…¶ä¸Žä¸èƒ½è¢«åˆ é™¤çš„é¢„ç•™æ˜ å°„æ¡ç›®ç›¸å¯¹åº”。 region_count()在解除ç§æœ‰å·¨é¡µæ˜ 射时被调用。在ç§æœ‰æ˜ å°„ä¸ï¼Œé¢„ç•™æ˜ å°„ä¸æ²¡æœ‰æ¡ç›®è¡¨æ˜Žå˜åœ¨ä¸€ä¸ªé¢„留。 å› æ¤ï¼Œé€šè¿‡è®¡ç®—é¢„ç•™æ˜ å°„ä¸çš„æ¡ç›®æ•°ï¼Œæˆ‘们知é“有多少预留被消耗了,有多少预留是未完æˆçš„ (Outstanding = (end - start) - region_count(resv, start, endï¼‰ï¼‰ã€‚ç”±äºŽæ˜ å°„æ£åœ¨æ¶ˆ 失,åæ± å’Œå…¨å±€é¢„ç•™è®¡æ•°è¢«æœªå®Œæˆçš„预留数é‡æ‰€å‡åŽ»ã€‚ é¢„ç•™æ˜ å°„å¸®åŠ©å‡½æ•° ================ æœ‰å‡ ä¸ªè¾…åŠ©å‡½æ•°å¯ä»¥æŸ¥è¯¢å’Œä¿®æ”¹é¢„ç•™æ˜ å°„ã€‚è¿™äº›å‡½æ•°åªå¯¹ç‰¹å®šçš„巨页的预留感兴趣,所以它们åªæ˜¯ä¼ 入一个 地å€è€Œä¸æ˜¯ä¸€ä¸ªèŒƒå›´ã€‚æ¤å¤–ï¼Œå®ƒä»¬è¿˜ä¼ å…¥ç›¸å…³çš„VMA。从VMAä¸ï¼Œå¯ä»¥ç¡®å®šæ˜ 射的类型(ç§æœ‰æˆ–共享)和预留 æ˜ å°„çš„ä½ç½®ï¼ˆinode或VMA)。这些函数åªæ˜¯è°ƒç”¨ â€œé¢„ç•™æ˜ å°„çš„ä¿®æ”¹â€ ä¸€èŠ‚ä¸æ述的基础函数。然而, 它们确实考虑到了ç§æœ‰å’Œå…±äº«æ˜ å°„çš„é¢„ç•™æ˜ å°„æ¡ç›®çš„ “相å†å«ä¹‰ï¼Œå¹¶å‘调用者éšè—了这个细节:: long vma_needs_reservation(struct hstate *h, struct vm_area_struct *vma, unsigned long addr) 该函数为指定的页é¢è°ƒç”¨ region_chg()。如果ä¸å˜åœ¨é¢„留,则返回1。如果å˜åœ¨é¢„留,则返回0:: long vma_commit_reservation(struct hstate *h, struct vm_area_struct *vma, unsigned long addr) 这将调用 region_add(),用于指定的页é¢ã€‚与region_chgå’Œregion_addçš„æƒ…å†µä¸€æ ·ï¼Œè¯¥å‡½æ•°åº”åœ¨ å…ˆå‰è°ƒç”¨çš„vma_needs_reservationåŽè°ƒç”¨ã€‚å®ƒå°†ä¸ºè¯¥é¡µæ·»åŠ ä¸€ä¸ªé¢„ç•™æ¡ç›®ã€‚å¦‚æžœé¢„ç•™è¢«æ·»åŠ ï¼Œå®ƒå°† 返回1,如果没有则返回0。返回值应与之å‰è°ƒç”¨vma_needs_reservation的返回值进行比较。如果出 现æ„å¤–çš„å·®å¼‚ï¼Œè¯´æ˜Žåœ¨ä¸¤æ¬¡è°ƒç”¨ä¹‹é—´ä¿®æ”¹äº†é¢„ç•™æ˜ å°„:: void vma_end_reservation(struct hstate *h, struct vm_area_struct *vma, unsigned long addr) 这将调用指定页é¢çš„ region_abort()。与region_chgå’Œregion_abortçš„æƒ…å†µä¸€æ ·ï¼Œè¯¥å‡½æ•°åº”åœ¨ å…ˆå‰è°ƒç”¨çš„vma_needs_reservationåŽè¢«è°ƒç”¨ã€‚它将ä¸æ¢/结æŸæ£åœ¨è¿›è¡Œçš„é¢„ç•™æ·»åŠ æ“作:: long vma_add_reservation(struct hstate *h, struct vm_area_struct *vma, unsigned long addr) 这是一个特殊的包装函数,有助于在错误路径上清ç†é¢„留。它åªä»Žrepare_reserve_on_error()函数 ä¸è°ƒç”¨ã€‚该函数与vma_needs_reservationä¸€èµ·ä½¿ç”¨ï¼Œè¯•å›¾å°†ä¸€ä¸ªé¢„ç•™æ·»åŠ åˆ°é¢„ç•™æ˜ å°„ä¸ã€‚它考虑到 了ç§æœ‰å’Œå…±äº«æ˜ å°„çš„ä¸åŒé¢„ç•™æ˜ å°„è¯ä¹‰ã€‚å› æ¤ï¼Œregion_addè¢«è°ƒç”¨ç”¨äºŽå…±äº«æ˜ å°„ï¼ˆå› ä¸ºæ˜ å°„ä¸çš„æ¡ç›®è¡¨ 示预留),而region_del被调用用于ç§æœ‰æ˜ å°„ï¼ˆå› ä¸ºæ˜ å°„ä¸æ²¡æœ‰æ¡ç›®è¡¨ç¤ºé¢„留)。关于在错误路径上需 è¦åšä»€ä¹ˆçš„更多信æ¯ï¼Œè¯·å‚è§ â€œé”™è¯¯è·¯å¾„ä¸çš„预留清ç†â€ 。 错误路径ä¸çš„é¢„ç•™æ¸…ç† ==================== æ£å¦‚在:ref:`é¢„ç•™æ˜ å°„å¸®åŠ©å‡½æ•°<resv_map_helpers>` 一节ä¸æ到的,预留的修改分两æ¥è¿›è¡Œã€‚首 先,在分é…页é¢ä¹‹å‰è°ƒç”¨vma_needs_reservation。如果分é…æˆåŠŸï¼Œåˆ™è°ƒç”¨vma_commit_reservation。 如果ä¸æ˜¯ï¼Œåˆ™è°ƒç”¨vma_end_reservation。全局和åæ± çš„é¢„ç•™è®¡æ•°æ ¹æ®æ“作的æˆåŠŸæˆ–失败进行调整, 一切都很好。 æ¤å¤–,在一个巨页被实例化åŽï¼ŒPagePrivateæ ‡å¿—è¢«æ¸…ç©ºï¼Œè¿™æ ·ï¼Œå½“é¡µé¢æœ€ç»ˆè¢«é‡Šæ”¾æ—¶ï¼Œè®¡æ•°æ˜¯ æ£ç¡®çš„。 ç„¶è€Œï¼Œæœ‰å‡ ç§æƒ…况是,在一个巨页被分é…åŽï¼Œä½†åœ¨å®ƒè¢«å®žä¾‹åŒ–之å‰ï¼Œå°±é‡åˆ°äº†é”™è¯¯ã€‚在这ç§æƒ…况下, 页é¢åˆ†é…å·²ç»æ¶ˆè€—了预留,并进行了适当的åæ± ã€é¢„ç•™æ˜ å°„å’Œå…¨å±€è®¡æ•°è°ƒæ•´ã€‚å¦‚æžœé¡µé¢åœ¨è¿™ä¸ªæ—¶å€™è¢«é‡Šæ”¾ (在实例化和清除PagePrivate之å‰ï¼‰ï¼Œé‚£ä¹ˆfree_huge_pageå°†å¢žåŠ å…¨å±€é¢„ç•™è®¡æ•°ã€‚ç„¶è€Œï¼Œé¢„ç•™æ˜ å°„ 显示报留被消耗了。这ç§ä¸ä¸€è‡´çš„状æ€å°†å¯¼è‡´é¢„留的巨页的 “泄æ¼â€ 。全局预留计数将比它原本的è¦é«˜ï¼Œ 并阻æ¢åˆ†é…一个预先分é…的页é¢ã€‚ 函数 restore_reserve_on_error() 试图处ç†è¿™ç§æƒ…况。它有相当完善的文档。这个函数的目的 æ˜¯å°†é¢„ç•™æ˜ å°„æ¢å¤åˆ°é¡µé¢åˆ†é…å‰çš„状æ€ã€‚通过这ç§æ–¹å¼ï¼Œé¢„ç•™æ˜ å°„çš„çŠ¶æ€å°†ä¸Žé¡µé¢é‡Šæ”¾åŽçš„全局预留计 数相对应。 函数restore_reserve_on_error本身在试图æ¢å¤é¢„ç•™æ˜ å°„æ¡ç›®æ—¶å¯èƒ½ä¼šé‡åˆ°é”™è¯¯ã€‚在这ç§æƒ…况下, 它将简å•åœ°æ¸…除该页的PagePrivateæ ‡å¿—ã€‚è¿™æ ·ä¸€æ¥ï¼Œå½“页é¢è¢«é‡Šæ”¾æ—¶ï¼Œå…¨å±€é¢„留计数将ä¸ä¼šè¢«é€’增。 ç„¶è€Œï¼Œé¢„ç•™æ˜ å°„å°†ç»§ç»çœ‹èµ·æ¥åƒé¢„ç•™è¢«æ¶ˆè€—äº†ä¸€æ ·ã€‚ä¸€ä¸ªé¡µé¢ä»ç„¶å¯ä»¥è¢«åˆ†é…到该地å€ï¼Œä½†å®ƒä¸ä¼šåƒæœ€ åˆè®¾æƒ³çš„é‚£æ ·ä½¿ç”¨ä¸€ä¸ªé¢„ç•™é¡µã€‚ 有一些代ç (最明显的是userfaultfd)ä¸èƒ½è°ƒç”¨restore_reserve_on_error。在这ç§æƒ…况下, 它简å•åœ°ä¿®æ”¹äº†PagePrivate,以便在释放巨页时ä¸ä¼šæ³„露预留。 预留和内å˜ç–ç•¥ ============== 当git第一次被用æ¥ç®¡ç†Linux代ç 时,æ¯ä¸ªèŠ‚点的巨页列表就å˜åœ¨äºŽhstate结构ä¸ã€‚预留的概念是 在一段时间åŽåŠ å…¥çš„ã€‚å½“é¢„ç•™è¢«æ·»åŠ æ—¶ï¼Œæ²¡æœ‰å°è¯•å°†å†…å˜ç–略考虑在内。虽然cpusets与内å˜ç–ç•¥ä¸ å®Œå…¨ç›¸åŒï¼Œä½†hugetlb_acct_memoryä¸çš„这个注释总结了预留和cpusets/内å˜ç–略之间的相互作 用:: /* * 当cpuset被é…ç½®æ—¶ï¼Œå®ƒæ‰“ç ´äº†ä¸¥æ ¼çš„hugetlb页é¢é¢„ç•™ï¼Œå› ä¸ºè®¡æ•°æ˜¯åœ¨ä¸€ä¸ªå…¨å±€å˜é‡ä¸Šå®Œ * æˆçš„。在有cpusetçš„æƒ…å†µä¸‹ï¼Œè¿™æ ·çš„é¢„ç•™å®Œå…¨æ˜¯åžƒåœ¾ï¼Œå› ä¸ºé¢„ç•™æ²¡æœ‰æ ¹æ®å½“å‰cpusetçš„ * 页é¢å¯ç”¨æ€§æ¥æ£€æŸ¥ã€‚在任务所在的cpusetä¸ç¼ºä¹ç©ºé—²çš„htlb页é¢æ—¶ï¼Œåº”用程åºä»ç„¶æœ‰å¯èƒ½ * è¢«å†…æ ¸OOM'ed。试图用cpusetæ¥æ‰§è¡Œä¸¥æ ¼çš„è®¡æ•°å‡ ä¹Žæ˜¯ä¸å¯èƒ½çš„ï¼ˆæˆ–è€…è¯´å¤ªéš¾çœ‹äº†ï¼‰ï¼Œå› * 为cpuset太ä¸ç¨³å®šäº†ï¼Œä»»åŠ¡æˆ–内å˜èŠ‚点å¯ä»¥åœ¨cpuset之间动æ€ç§»åŠ¨ã€‚与cpuset共享 * hugetlbæ˜ å°„çš„è¯ä¹‰å˜åŒ–是ä¸å¯å–的。然而,为了预留一些è¯ä¹‰ï¼Œæˆ‘们退回到检查当å‰ç©ºé—² * 页的å¯ç”¨æ€§ï¼Œä½œä¸ºä¸€ç§æœ€å¥½çš„å°è¯•ï¼Œå¸Œæœ›èƒ½å°†cpuset改å˜è¯ä¹‰çš„å½±å“é™åˆ°æœ€ä½Žã€‚ */ æ·»åŠ å·¨é¡µé¢„ç•™æ˜¯ä¸ºäº†é˜²æ¢åœ¨ç¼ºé¡µå¼‚常时出现æ„外的页é¢åˆ†é…失败(OOM)。然而,如果一个应用 程åºä½¿ç”¨cpusets或内å˜ç–略,就ä¸èƒ½ä¿è¯åœ¨æ‰€éœ€çš„节点上有巨页å¯ç”¨ã€‚å³ä½¿æœ‰è¶³å¤Ÿæ•°é‡çš„全局 预留,也是如æ¤ã€‚ Hugetlbfs回归测试 ================= 最完整的hugetlb测试集在libhugetlbfsä»“åº“ã€‚å¦‚æžœä½ ä¿®æ”¹äº†ä»»ä½•hugetlb相关的代ç ,请使用 libhugetlbfs测试套件æ¥æ£€æŸ¥å›žå½’情况。æ¤å¤–ï¼Œå¦‚æžœä½ æ·»åŠ äº†ä»»ä½•æ–°çš„hugetlb功能,请在 libhugetlbfsä¸æ·»åŠ 适当的测试。 -- Mike Kravetz,2017å¹´4月7æ—¥