All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH -next] docs/zh_CN: add vm transhuge translation
@ 2022-06-28 13:37 Guo Mengqi
  2022-06-29  3:50 ` YanTeng Si
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Guo Mengqi @ 2022-06-28 13:37 UTC (permalink / raw)
  To: alexs, siyanteng, corbet, bobwxc, linux-doc, linux-kernel
  Cc: xuqiang36, guomengqi3

Translate .../vm/transhuge.rst into Chinese.

Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
---
 Documentation/translations/zh_CN/vm/index.rst |   2 +-
 .../translations/zh_CN/vm/transhuge.rst       | 151 ++++++++++++++++++
 2 files changed, 152 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/translations/zh_CN/vm/transhuge.rst

diff --git a/Documentation/translations/zh_CN/vm/index.rst b/Documentation/translations/zh_CN/vm/index.rst
index c77a56553845..2d82b15b272b 100644
--- a/Documentation/translations/zh_CN/vm/index.rst
+++ b/Documentation/translations/zh_CN/vm/index.rst
@@ -59,11 +59,11 @@ Linux内存管理文档
    vmalloced-kernel-stacks
    z3fold
    zsmalloc
+   transhuge
 
 TODOLIST:
 * arch_pgtable_helpers
 * free_page_reporting
 * hugetlbfs_reserv
 * slub
-* transhuge
 * unevictable-lru
diff --git a/Documentation/translations/zh_CN/vm/transhuge.rst b/Documentation/translations/zh_CN/vm/transhuge.rst
new file mode 100644
index 000000000000..a7bed8b13a47
--- /dev/null
+++ b/Documentation/translations/zh_CN/vm/transhuge.rst
@@ -0,0 +1,151 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/vm/transhuge.rst
+
+:翻译:
+
+ 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
+
+:校译:
+
+==============
+透明大页机制
+==============
+
+本文档描述透明大页(THP)的设计理念,以及它是如何与内存管理系统其他部分交互的。
+
+设计原则
+========
+
+- “优雅fallback”:有些mm组件不了解透明大页的存在,它们的回退方法是将PMD页表项
+  拆分成PTE页表项。必要时还需要拆分透明大页。这样就可以在常规大小的页或页表项上
+  继续工作。
+
+- 如果内存碎片化导致大页分配失败,则分配常规页作为替代放入原vma中,此期间不应
+  产生任何失败或明显延迟,不要引起用户态的注意。
+
+- 如果一些进程退出后释放了空余的大页(不论在伙伴系统还是在VM),由常规页支持的
+  guest物理内存应该自动重新申请为大页。(通过khugepaged进程)
+
+- 透明大页不需要预留内存,而是尽可能使用已经存在的大页。(唯为避免不可移动的页
+  将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅
+  针对透明大页,而对内核中所有动态的多级页面申请都通用。)
+
+get_user_pages和follow_page
+===========================
+
+不论对单个大页还是hugetlbfs,使用get_user_pages和follow_page时,返回的会是首页或
+尾页。大多数情况下调用get_user_page功能的人不关心页的大小,只关心页的真实物理
+地址以及暂时的pin页,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问
+尾页的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者
+尾页被引用,大页就不能再被拆分了。
+
+.. note::
+   以上限制不是针对GUP API新增,而是为了与在hugetlbfs中保持一致。这样如果驱动
+   能在hugetlbfs中使用GUP,就能够切换到透明大页机制支持的GUP。
+
+优雅fallback
+============
+
+为查页表流程增加大页支持只需添加split_huge_pmd(vma, pmd,
+addr)即可。其中pmd为pmd_offset返回值。要为代码添加透明大页支持很简单,搜索
+"pmd_offset"并将split_huge_pmd添加到所有返回的pmd后面。这短短一行的fallback函数
+很巧妙,为我们省去了额外的适配代码(通常会很长或者很复杂)。
+
+如果你需要在没有页表的情况下处理一个大页,可以使用split_huge_page(page)把它拆分
+成小页。linux VM就是通过这种方式将大页换出。如果页面被pin住了,split_huge_page
+就会失败。
+
+例子:添加一行代码使mremap.c支持透明大页::
+
+        diff --git a/mm/mremap.c b/mm/mremap.c
+        --- a/mm/mremap.c
+        +++ b/mm/mremap.c
+        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
+                return NULL;
+
+                pmd = pmd_offset(pud, addr);
+        +       split_huge_pmd(vma, pmd, addr);
+                if (pmd_none_or_clear_bad(pmd))
+                    return NULL;
+
+大页支持中的锁使用
+==================
+
+我们希望尽可能多的代码能原生支持透明大页,因为调用split_huge_page()和
+split_huge_pmd()还是有开销的。
+
+要让查页表操作变得能处理huge pmd,只需对pmd_offset返回的pmd调用
+pmd_trans_huge()。一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的
+大页pmd(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
+如果pmd_trans_huge返回false,那就回到原来的流程。如果pmd_trans_huge返回true,
+就需要先持有页表锁(pmd_lock()),然后再调一次pmd_trans_huge. 持页表锁是为了防止
+大页pmd被转换成小页(split_huge_pmd可以跟查页表操作同时进行)。如果第二次
+pmd_trans_huge返回false,那就释放页表锁,依然回到原有流程。如果返回true,就可以
+继续处理huge pmd和hugepage了。处理完毕,再释放页表锁。
+
+引用计数和透明大页
+==================
+
+THP的计数跟其他复合页的计数大致相同:
+
+ - get_page()/put_page()和GUP都在首页上进行计数(修改head page->_refcount)
+
+ - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
+
+ - map/unmap特定PTE entry时,增减的是复合页中相应子页的_mapcount.
+
+ - map/unmap整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
+   尾页中。对于文件中的大页,还要增加所有子页中的_mapcount,这样是为了在检测
+   子页的解映射时不需考虑竞争问题。
+
+PageDoubleMap() 表明大页 *可能* 被映射为了PTE.
+
+对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
+在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。
+
+这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次
+map/unmap整个复合页时更改所有子页的_mapcount.
+
+对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map;
+当compound_mapcount值降为0时,取消设置。
+
+对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存
+page cache中移除时,取消设置。
+
+split_huge_page中,在清除page struct中所有PG_head/tail位之前,需要先将首页中的
+引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的
+引用计数来源难以确定(如通过get_user_pages的pin页)。如果大页被pin住,
+split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为
+split_huge_page的调用者也必须对首页持有一个引用)。
+
+对匿名页,split_huge_page用页表项迁移(migration
+entries)保持来page->_refcount和page->_mapcount稳定。对文件页,直接解映射就好。
+
+这套机制对物理内存扫描(physical memory scanners)也安全,scanner唯一合法引用页
+的途径就是get_page_unless_zero().
+
+没调atomic_add()时,所有尾页的_refcount都为0. 这时scanner无法获取尾页的引用。
+调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用
+计数减去多少即可。
+
+对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了:
+引用计数将会留在首页中。
+
+split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会
+失败。
+
+局部unmap和deferred_split_huge_page()函数
+==========================================
+
+透明大页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap()
+中检查透明大页的某个子页是否已经还在使用,并将透明大页加入一个预备队列,当内存
+使用需求变大时,把透明大页拆分,释放已经不用的子页。
+
+如果检测到局部unmap,由于处在锁中,无法拆页。而且在很多情况下,透明大页会跨VMA,
+这时会在exit(2)中进行局部unmap,这时拆页效果适得其反。
+
+deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正
+的拆页操作是通过内存压力导致的shrinker函数来触发。
+
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH -next] docs/zh_CN: add vm transhuge translation
  2022-06-28 13:37 [PATCH -next] docs/zh_CN: add vm transhuge translation Guo Mengqi
@ 2022-06-29  3:50 ` YanTeng Si
  2022-06-30  2:11   ` Wu XiangCheng
  2022-07-01  3:28   ` guomengqi (A)
  2022-06-29  6:37 ` Alex Shi
  2022-07-05 14:11 ` [PATCH -next v2] docs/zh_CN: add mm " Guo Mengqi
  2 siblings, 2 replies; 12+ messages in thread
From: YanTeng Si @ 2022-06-29  3:50 UTC (permalink / raw)
  To: Guo Mengqi, alexs, corbet, bobwxc, linux-doc, linux-kernel,
	yizhou.tang, Binbin Zhou
  Cc: xuqiang36

Hi Mengqi

在 2022/6/28 21:37, Guo Mengqi 写道:
> Translate .../vm/transhuge.rst into Chinese.
>
> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
> ---
>   Documentation/translations/zh_CN/vm/index.rst |   2 +-
>   .../translations/zh_CN/vm/transhuge.rst       | 151 ++++++++++++++++++
>   2 files changed, 152 insertions(+), 1 deletion(-)
>   create mode 100644 Documentation/translations/zh_CN/vm/transhuge.rst

When I apply your patch(next-tree), git complains:

Applying: docs/zh_CN: add vm transhuge translation

error: Documentation/translations/zh_CN/vm/index.rst: does not exist in 
index
.git/rebase-apply/patch:180: new blank line at EOF.
+
Patch failed at 0001 docs/zh_CN: add vm transhuge translation
>
> diff --git a/Documentation/translations/zh_CN/vm/index.rst b/Documentation/translations/zh_CN/vm/index.rst
> index c77a56553845..2d82b15b272b 100644
> --- a/Documentation/translations/zh_CN/vm/index.rst
> +++ b/Documentation/translations/zh_CN/vm/index.rst
> @@ -59,11 +59,11 @@ Linux内存管理文档
>      vmalloced-kernel-stacks
>      z3fold
>      zsmalloc
> +   transhuge
>   
>   TODOLIST:
>   * arch_pgtable_helpers
>   * free_page_reporting
>   * hugetlbfs_reserv
>   * slub
> -* transhuge
>   * unevictable-lru
> diff --git a/Documentation/translations/zh_CN/vm/transhuge.rst b/Documentation/translations/zh_CN/vm/transhuge.rst
> new file mode 100644
> index 000000000000..a7bed8b13a47
> --- /dev/null
> +++ b/Documentation/translations/zh_CN/vm/transhuge.rst
> @@ -0,0 +1,151 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +.. include:: ../disclaimer-zh_CN.rst
> +
> +:Original: Documentation/vm/transhuge.rst
> +
> +:翻译:
> +
> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
> +
> +:校译:
> +
> +==============
> +透明大页机制

huge 巨大

large 大


so 大页 -> 巨页

> +==============
> +
> +本文档描述透明大页(THP)的设计理念,以及它是如何与内存管理系统其他部分交互的。

以及它是如何与内存管理系统的其他部分交互的

> +
> +设计原则
> +========
> +
> +- “优雅fallback”:有些mm组件不了解透明大页的存在,它们的回退方法是将PMD页表项
> +  拆分成PTE页表项。必要时还需要拆分透明大页。这样就可以在常规大小的页或页表项上
> +  继续工作。
> +
> +- 如果内存碎片化导致大页分配失败,则分配常规页作为替代放入原vma中,此期间不应
> +  产生任何失败或明显延迟,不要引起用户态的注意。

How about

此期间不会产生任何失败或明显延迟,也不会引起用户态的注意。

> +
> +- 如果一些进程退出后释放了空余的大页(不论在伙伴系统还是在VM),由常规页支持的
空余 -> 空闲 or 可用
> +  guest物理内存应该自动重新申请为大页。(通过khugepaged进程)
> +
> +- 透明大页不需要预留内存,而是尽可能使用已经存在的大页。(唯为避免不可移动的页
del 唯
> +  将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅
> +  针对透明大页,而对内核中所有动态的多级页面申请都通用。)
都适用 or 对xxxxx页面申请通用。
> +
> +get_user_pages和follow_page
> +===========================
> +
> +不论对单个大页还是hugetlbfs,使用get_user_pages和follow_page时,返回的会是首页或

使用get_user_pages(GUP)

> +尾页。大多数情况下调用get_user_page功能的人不关心页的大小,只关心页的真实物理

调用GUP功能

> +地址以及暂时的pin页,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问
> +尾页的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者
> +尾页被引用,大页就不能再被拆分了。
> +
> +.. note::
> +   以上限制不是针对GUP API新增,而是为了与在hugetlbfs中保持一致。这样如果驱动
> +   能在hugetlbfs中使用GUP,就能够切换到透明大页机制支持的GUP。
> +
> +优雅fallback
> +============
> +
> +为查页表流程增加大页支持只需添加split_huge_pmd(vma, pmd,
> +addr)即可。其中pmd为pmd_offset返回值。要为代码添加透明大页支持很简单,搜索
> +"pmd_offset"并将split_huge_pmd添加到所有返回的pmd后面。这短短一行的fallback函数
> +很巧妙,为我们省去了额外的适配代码(通常会很长或者很复杂)。
> +
> +如果你需要在没有页表的情况下处理一个大页,可以使用split_huge_page(page)把它拆分
> +成小页。linux VM就是通过这种方式将大页换出。如果页面被pin住了,split_huge_page
> +就会失败。
> +
> +例子:添加一行代码使mremap.c支持透明大页::
> +
> +        diff --git a/mm/mremap.c b/mm/mremap.c
> +        --- a/mm/mremap.c
> +        +++ b/mm/mremap.c
> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
> +                return NULL;
> +
> +                pmd = pmd_offset(pud, addr);
> +        +       split_huge_pmd(vma, pmd, addr);
> +                if (pmd_none_or_clear_bad(pmd))
> +                    return NULL;
> +
> +大页支持中的锁使用
> +==================
> +
> +我们希望尽可能多的代码能原生支持透明大页,因为调用split_huge_page()和
> +split_huge_pmd()还是有开销的。
> +
> +要让查页表操作变得能处理huge pmd,只需对pmd_offset返回的pmd调用
> +pmd_trans_huge()。一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的
> +大页pmd(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
> +如果pmd_trans_huge返回false,那就回到原来的流程。如果pmd_trans_huge返回true,
> +就需要先持有页表锁(pmd_lock()),然后再调一次pmd_trans_huge. 持页表锁是为了防止
> +大页pmd被转换成小页(split_huge_pmd可以跟查页表操作同时进行)。如果第二次
> +pmd_trans_huge返回false,那就释放页表锁,依然回到原有流程。如果返回true,就可以
> +继续处理huge pmd和hugepage了。处理完毕,再释放页表锁。
> +
> +引用计数和透明大页
> +==================
> +
> +THP的计数跟其他复合页的计数大致相同:
> +
> + - get_page()/put_page()和GUP都在首页上进行计数(修改head page->_refcount)
> +
> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
> +
> + - map/unmap特定PTE entry时,增减的是复合页中相应子页的_mapcount.
> +
> + - map/unmap整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
> +   尾页中。对于文件中的大页,还要增加所有子页中的_mapcount,这样是为了在检测
> +   子页的解映射时不需考虑竞争问题。
map/unmap: Either you don't translate, or you translate them all.
> +
> +PageDoubleMap() 表明大页 *可能* 被映射为了PTE.
> +
> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。
> +
> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次
> +map/unmap整个复合页时更改所有子页的_mapcount.
> +
> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map;
> +当compound_mapcount值降为0时,取消设置。
> +
> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存
> +page cache中移除时,取消设置。
页缓存 == page cache
> +
> +split_huge_page中,在清除page struct中所有PG_head/tail位之前,需要先将首页中的
> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的
> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果大页被pin住,
> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为
> +split_huge_page的调用者也必须对首页持有一个引用)。
> +
> +对匿名页,split_huge_page用页表项迁移(migration
> +entries)保持来page->_refcount和page->_mapcount稳定。对文件页,直接解映射就好。

保持来 -> 来保持

> +
> +这套机制对物理内存扫描(physical memory scanners)也安全,scanner唯一合法引用页
> +的途径就是get_page_unless_zero().
> +
> +没调atomic_add()时,所有尾页的_refcount都为0. 这时scanner无法获取尾页的引用。
> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用
> +计数减去多少即可。
> +
> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了:
> +引用计数将会留在首页中。
> +
> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会
> +失败。
> +
> +局部unmap和deferred_split_huge_page()函数
> +==========================================
> +
> +透明大页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap()
> +中检查透明大页的某个子页是否已经还在使用,并将透明大页加入一个预备队列,当内存
> +使用需求变大时,把透明大页拆分,释放已经不用的子页。
> +
> +如果检测到局部unmap,由于处在锁中,无法拆页。而且在很多情况下,透明大页会跨VMA,
> +这时会在exit(2)中进行局部unmap,这时拆页效果适得其反。

由于xxxxx而且xxxxxx所以xxxxxxx

这时 is used too much


> +
> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正
> +的拆页操作是通过内存压力导致的shrinker函数来触发。

shrinker接口

> +

CC Yizhou

CC Binbin


I like your way of translating docs, good job!


Thanks,
Yanteng


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH -next] docs/zh_CN: add vm transhuge translation
  2022-06-28 13:37 [PATCH -next] docs/zh_CN: add vm transhuge translation Guo Mengqi
  2022-06-29  3:50 ` YanTeng Si
@ 2022-06-29  6:37 ` Alex Shi
  2022-07-05 14:11 ` [PATCH -next v2] docs/zh_CN: add mm " Guo Mengqi
  2 siblings, 0 replies; 12+ messages in thread
From: Alex Shi @ 2022-06-29  6:37 UTC (permalink / raw)
  To: Guo Mengqi
  Cc: Alex Shi, Yanteng Si, Jonathan Corbet, Wu X.C.,
	Linux Doc Mailing List, LKML, xuqiang36

On Tue, Jun 28, 2022 at 9:43 PM Guo Mengqi <guomengqi3@huawei.com> wrote:
>
> Translate .../vm/transhuge.rst into Chinese.
>
> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
> ---
>  Documentation/translations/zh_CN/vm/index.rst |   2 +-
>  .../translations/zh_CN/vm/transhuge.rst       | 151 ++++++++++++++++++
>  2 files changed, 152 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/translations/zh_CN/vm/transhuge.rst
>
> diff --git a/Documentation/translations/zh_CN/vm/index.rst b/Documentation/translations/zh_CN/vm/index.rst
> index c77a56553845..2d82b15b272b 100644
> --- a/Documentation/translations/zh_CN/vm/index.rst
> +++ b/Documentation/translations/zh_CN/vm/index.rst
> @@ -59,11 +59,11 @@ Linux内存管理文档
>     vmalloced-kernel-stacks
>     z3fold
>     zsmalloc
> +   transhuge
>
>  TODOLIST:
>  * arch_pgtable_helpers
>  * free_page_reporting
>  * hugetlbfs_reserv
>  * slub
> -* transhuge
>  * unevictable-lru
> diff --git a/Documentation/translations/zh_CN/vm/transhuge.rst b/Documentation/translations/zh_CN/vm/transhuge.rst
> new file mode 100644
> index 000000000000..a7bed8b13a47
> --- /dev/null
> +++ b/Documentation/translations/zh_CN/vm/transhuge.rst
> @@ -0,0 +1,151 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +.. include:: ../disclaimer-zh_CN.rst
> +
> +:Original: Documentation/vm/transhuge.rst
> +
> +:翻译:
> +
> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
> +
> +:校译:
> +
> +==============
> +透明大页机制
> +==============
> +
> +本文档描述透明大页(THP)的设计理念,以及它是如何与内存管理系统其他部分交互的。
> +
> +设计原则
> +========
> +
> +- “优雅fallback”:有些mm组件不了解透明大页的存在,它们的回退方法是将PMD页表项

"fallback" could be translated as '回退' here.

> +  拆分成PTE页表项。必要时还需要拆分透明大页。这样就可以在常规大小的页或页表项上
> +  继续工作。
> +
> +- 如果内存碎片化导致大页分配失败,则分配常规页作为替代放入原vma中,此期间不应
> +  产生任何失败或明显延迟,不要引起用户态的注意。
> +
> +- 如果一些进程退出后释放了空余的大页(不论在伙伴系统还是在VM),由常规页支持的
> +  guest物理内存应该自动重新申请为大页。(通过khugepaged进程)
> +
> +- 透明大页不需要预留内存,而是尽可能使用已经存在的大页。(唯为避免不可移动的页
> +  将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅
> +  针对透明大页,而对内核中所有动态的多级页面申请都通用。)
> +
> +get_user_pages和follow_page
> +===========================
> +
> +不论对单个大页还是hugetlbfs,使用get_user_pages和follow_page时,返回的会是首页或
> +尾页。大多数情况下调用get_user_page功能的人不关心页的大小,只关心页的真实物理
> +地址以及暂时的pin页,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问

'pin' could be translated as 固定 here.

> +尾页的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者
> +尾页被引用,大页就不能再被拆分了。
> +
> +.. note::
> +   以上限制不是针对GUP API新增,而是为了与在hugetlbfs中保持一致。这样如果驱动
> +   能在hugetlbfs中使用GUP,就能够切换到透明大页机制支持的GUP。
> +
> +优雅fallback
> +============
> +
> +为查页表流程增加大页支持只需添加split_huge_pmd(vma, pmd,
> +addr)即可。其中pmd为pmd_offset返回值。要为代码添加透明大页支持很简单,搜索
> +"pmd_offset"并将split_huge_pmd添加到所有返回的pmd后面。这短短一行的fallback函数
> +很巧妙,为我们省去了额外的适配代码(通常会很长或者很复杂)。
> +
> +如果你需要在没有页表的情况下处理一个大页,可以使用split_huge_page(page)把它拆分
> +成小页。linux VM就是通过这种方式将大页换出。如果页面被pin住了,split_huge_page
> +就会失败。
> +
> +例子:添加一行代码使mremap.c支持透明大页::
> +
> +        diff --git a/mm/mremap.c b/mm/mremap.c
> +        --- a/mm/mremap.c
> +        +++ b/mm/mremap.c
> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
> +                return NULL;
> +
> +                pmd = pmd_offset(pud, addr);
> +        +       split_huge_pmd(vma, pmd, addr);
> +                if (pmd_none_or_clear_bad(pmd))
> +                    return NULL;
> +
> +大页支持中的锁使用
> +==================
> +
> +我们希望尽可能多的代码能原生支持透明大页,因为调用split_huge_page()和
> +split_huge_pmd()还是有开销的。
> +
> +要让查页表操作变得能处理huge pmd,只需对pmd_offset返回的pmd调用
> +pmd_trans_huge()。一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的
> +大页pmd(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
> +如果pmd_trans_huge返回false,那就回到原来的流程。如果pmd_trans_huge返回true,

'false' could be translated as 假, 'true' is 真.

> +就需要先持有页表锁(pmd_lock()),然后再调一次pmd_trans_huge. 持页表锁是为了防止
> +大页pmd被转换成小页(split_huge_pmd可以跟查页表操作同时进行)。如果第二次
> +pmd_trans_huge返回false,那就释放页表锁,依然回到原有流程。如果返回true,就可以
> +继续处理huge pmd和hugepage了。处理完毕,再释放页表锁。
> +
> +引用计数和透明大页
> +==================
> +
> +THP的计数跟其他复合页的计数大致相同:
> +
> + - get_page()/put_page()和GUP都在首页上进行计数(修改head page->_refcount)
> +
> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
> +
> + - map/unmap特定PTE entry时,增减的是复合页中相应子页的_mapcount.
> +
> + - map/unmap整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
> +   尾页中。对于文件中的大页,还要增加所有子页中的_mapcount,这样是为了在检测
> +   子页的解映射时不需考虑竞争问题。
> +
> +PageDoubleMap() 表明大页 *可能* 被映射为了PTE.
> +
> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。
> +
> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次
> +map/unmap整个复合页时更改所有子页的_mapcount.
> +
> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map;
> +当compound_mapcount值降为0时,取消设置。
> +
> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存
> +page cache中移除时,取消设置。
> +
> +split_huge_page中,在清除page struct中所有PG_head/tail位之前,需要先将首页中的
> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的
> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果大页被pin住,
> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为
> +split_huge_page的调用者也必须对首页持有一个引用)。
> +
> +对匿名页,split_huge_page用页表项迁移(migration
> +entries)保持来page->_refcount和page->_mapcount稳定。对文件页,直接解映射就好。
> +
> +这套机制对物理内存扫描(physical memory scanners)也安全,scanner唯一合法引用页
> +的途径就是get_page_unless_zero().
> +
> +没调atomic_add()时,所有尾页的_refcount都为0. 这时scanner无法获取尾页的引用。
> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用
> +计数减去多少即可。
> +
> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了:
> +引用计数将会留在首页中。
> +
> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会
> +失败。
> +
> +局部unmap和deferred_split_huge_page()函数
> +==========================================
> +
> +透明大页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap()
> +中检查透明大页的某个子页是否已经还在使用,并将透明大页加入一个预备队列,当内存

'已经还在' duplicate meaning, leave one is fine.

Thanks
Alex
> +使用需求变大时,把透明大页拆分,释放已经不用的子页。
> +
> +如果检测到局部unmap,由于处在锁中,无法拆页。而且在很多情况下,透明大页会跨VMA,
> +这时会在exit(2)中进行局部unmap,这时拆页效果适得其反。
> +
> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正
> +的拆页操作是通过内存压力导致的shrinker函数来触发。
> +
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH -next] docs/zh_CN: add vm transhuge translation
  2022-06-29  3:50 ` YanTeng Si
@ 2022-06-30  2:11   ` Wu XiangCheng
  2022-07-01  2:49     ` guomengqi (A)
  2022-07-01  3:28   ` guomengqi (A)
  1 sibling, 1 reply; 12+ messages in thread
From: Wu XiangCheng @ 2022-06-30  2:11 UTC (permalink / raw)
  To: YanTeng Si, Guo Mengqi, alexs, corbet, linux-doc, linux-kernel,
	yizhou.tang, Binbin Zhou
  Cc: xuqiang36



于 2022年6月29日 GMT+08:00 上午11:50:11, YanTeng Si <siyanteng@loongson.cn> 写到:
>Hi Mengqi
>
>在 2022/6/28 21:37, Guo Mengqi 写道:
>> Translate .../vm/transhuge.rst into Chinese.
>> 
>> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
>> ---
>>   Documentation/translations/zh_CN/vm/index.rst |   2 +-
>>   .../translations/zh_CN/vm/transhuge.rst       | 151 ++++++++++++++++++
>>   2 files changed, 152 insertions(+), 1 deletion(-)
>>   create mode 100644 Documentation/translations/zh_CN/vm/transhuge.rst
>
>When I apply your patch(next-tree), git complains:
>
>Applying: docs/zh_CN: add vm transhuge translation
>
>error: Documentation/translations/zh_CN/vm/index.rst: does not exist in index
>.git/rebase-apply/patch:180: new blank line at EOF.
>+
>Patch failed at 0001 docs/zh_CN: add vm transhuge translation


The /vm/ documentations (including translations) have been moved to /mm/ in linux-next tree.

Not sure about docs-next, please check that.


>> 
>> diff --git a/Documentation/translations/zh_CN/vm/index.rst b/Documentation/translations/zh_CN/vm/index.rst
>> index c77a56553845..2d82b15b272b 100644
>> --- a/Documentation/translations/zh_CN/vm/index.rst
>> +++ b/Documentation/translations/zh_CN/vm/index.rst
>> @@ -59,11 +59,11 @@ Linux内存管理文档
>>      vmalloced-kernel-stacks
>>      z3fold
>>      zsmalloc
>> +   transhuge
>>     TODOLIST:
>>   * arch_pgtable_helpers
>>   * free_page_reporting
>>   * hugetlbfs_reserv
>>   * slub
>> -* transhuge
>>   * unevictable-lru
>> diff --git a/Documentation/translations/zh_CN/vm/transhuge.rst b/Documentation/translations/zh_CN/vm/transhuge.rst
>> new file mode 100644
>> index 000000000000..a7bed8b13a47
>> --- /dev/null
>> +++ b/Documentation/translations/zh_CN/vm/transhuge.rst
>> @@ -0,0 +1,151 @@
>> +.. SPDX-License-Identifier: GPL-2.0
>> +.. include:: ../disclaimer-zh_CN.rst
>> +
>> +:Original: Documentation/vm/transhuge.rst
>> +
>> +:翻译:
>> +
>> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
>> +
>> +:校译:
>> +
>> +==============
>> +透明大页机制
>
>huge 巨大
>
>large 大
>
>
>so 大页 -> 巨页

Here I think both is OK, and 大页 seems more common?

Thanks,
Wu

>
>> +==============
>> +
>> +本文档描述透明大页(THP)的设计理念,以及它是如何与内存管理系统其他部分交互的。
>
>以及它是如何与内存管理系统的其他部分交互的
>
>> +
>> +设计原则
>> +========
>> +
>> +- “优雅fallback”:有些mm组件不了解透明大页的存在,它们的回退方法是将PMD页表项
>> +  拆分成PTE页表项。必要时还需要拆分透明大页。这样就可以在常规大小的页或页表项上
>> +  继续工作。
>> +
>> +- 如果内存碎片化导致大页分配失败,则分配常规页作为替代放入原vma中,此期间不应
>> +  产生任何失败或明显延迟,不要引起用户态的注意。
>
>How about
>
>此期间不会产生任何失败或明显延迟,也不会引起用户态的注意。
>
>> +
>> +- 如果一些进程退出后释放了空余的大页(不论在伙伴系统还是在VM),由常规页支持的
>空余 -> 空闲 or 可用
>> +  guest物理内存应该自动重新申请为大页。(通过khugepaged进程)
>> +
>> +- 透明大页不需要预留内存,而是尽可能使用已经存在的大页。(唯为避免不可移动的页
>del 唯
>> +  将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅
>> +  针对透明大页,而对内核中所有动态的多级页面申请都通用。)
>都适用 or 对xxxxx页面申请通用。
>> +
>> +get_user_pages和follow_page
>> +===========================
>> +
>> +不论对单个大页还是hugetlbfs,使用get_user_pages和follow_page时,返回的会是首页或
>
>使用get_user_pages(GUP)
>
>> +尾页。大多数情况下调用get_user_page功能的人不关心页的大小,只关心页的真实物理
>
>调用GUP功能
>
>> +地址以及暂时的pin页,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问
>> +尾页的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者
>> +尾页被引用,大页就不能再被拆分了。
>> +
>> +.. note::
>> +   以上限制不是针对GUP API新增,而是为了与在hugetlbfs中保持一致。这样如果驱动
>> +   能在hugetlbfs中使用GUP,就能够切换到透明大页机制支持的GUP。
>> +
>> +优雅fallback
>> +============
>> +
>> +为查页表流程增加大页支持只需添加split_huge_pmd(vma, pmd,
>> +addr)即可。其中pmd为pmd_offset返回值。要为代码添加透明大页支持很简单,搜索
>> +"pmd_offset"并将split_huge_pmd添加到所有返回的pmd后面。这短短一行的fallback函数
>> +很巧妙,为我们省去了额外的适配代码(通常会很长或者很复杂)。
>> +
>> +如果你需要在没有页表的情况下处理一个大页,可以使用split_huge_page(page)把它拆分
>> +成小页。linux VM就是通过这种方式将大页换出。如果页面被pin住了,split_huge_page
>> +就会失败。
>> +
>> +例子:添加一行代码使mremap.c支持透明大页::
>> +
>> +        diff --git a/mm/mremap.c b/mm/mremap.c
>> +        --- a/mm/mremap.c
>> +        +++ b/mm/mremap.c
>> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
>> +                return NULL;
>> +
>> +                pmd = pmd_offset(pud, addr);
>> +        +       split_huge_pmd(vma, pmd, addr);
>> +                if (pmd_none_or_clear_bad(pmd))
>> +                    return NULL;
>> +
>> +大页支持中的锁使用
>> +==================
>> +
>> +我们希望尽可能多的代码能原生支持透明大页,因为调用split_huge_page()和
>> +split_huge_pmd()还是有开销的。
>> +
>> +要让查页表操作变得能处理huge pmd,只需对pmd_offset返回的pmd调用
>> +pmd_trans_huge()。一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的
>> +大页pmd(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
>> +如果pmd_trans_huge返回false,那就回到原来的流程。如果pmd_trans_huge返回true,
>> +就需要先持有页表锁(pmd_lock()),然后再调一次pmd_trans_huge. 持页表锁是为了防止
>> +大页pmd被转换成小页(split_huge_pmd可以跟查页表操作同时进行)。如果第二次
>> +pmd_trans_huge返回false,那就释放页表锁,依然回到原有流程。如果返回true,就可以
>> +继续处理huge pmd和hugepage了。处理完毕,再释放页表锁。
>> +
>> +引用计数和透明大页
>> +==================
>> +
>> +THP的计数跟其他复合页的计数大致相同:
>> +
>> + - get_page()/put_page()和GUP都在首页上进行计数(修改head page->_refcount)
>> +
>> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
>> +
>> + - map/unmap特定PTE entry时,增减的是复合页中相应子页的_mapcount.
>> +
>> + - map/unmap整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
>> +   尾页中。对于文件中的大页,还要增加所有子页中的_mapcount,这样是为了在检测
>> +   子页的解映射时不需考虑竞争问题。
>map/unmap: Either you don't translate, or you translate them all.
>> +
>> +PageDoubleMap() 表明大页 *可能* 被映射为了PTE.
>> +
>> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
>> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。
>> +
>> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次
>> +map/unmap整个复合页时更改所有子页的_mapcount.
>> +
>> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map;
>> +当compound_mapcount值降为0时,取消设置。
>> +
>> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存
>> +page cache中移除时,取消设置。
>页缓存 == page cache
>> +
>> +split_huge_page中,在清除page struct中所有PG_head/tail位之前,需要先将首页中的
>> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的
>> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果大页被pin住,
>> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为
>> +split_huge_page的调用者也必须对首页持有一个引用)。
>> +
>> +对匿名页,split_huge_page用页表项迁移(migration
>> +entries)保持来page->_refcount和page->_mapcount稳定。对文件页,直接解映射就好。
>
>保持来 -> 来保持
>
>> +
>> +这套机制对物理内存扫描(physical memory scanners)也安全,scanner唯一合法引用页
>> +的途径就是get_page_unless_zero().
>> +
>> +没调atomic_add()时,所有尾页的_refcount都为0. 这时scanner无法获取尾页的引用。
>> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用
>> +计数减去多少即可。
>> +
>> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了:
>> +引用计数将会留在首页中。
>> +
>> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会
>> +失败。
>> +
>> +局部unmap和deferred_split_huge_page()函数
>> +==========================================
>> +
>> +透明大页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap()
>> +中检查透明大页的某个子页是否已经还在使用,并将透明大页加入一个预备队列,当内存
>> +使用需求变大时,把透明大页拆分,释放已经不用的子页。
>> +
>> +如果检测到局部unmap,由于处在锁中,无法拆页。而且在很多情况下,透明大页会跨VMA,
>> +这时会在exit(2)中进行局部unmap,这时拆页效果适得其反。
>
>由于xxxxx而且xxxxxx所以xxxxxxx
>
>这时 is used too much
>
>
>> +
>> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正
>> +的拆页操作是通过内存压力导致的shrinker函数来触发。
>
>shrinker接口
>
>> +
>
>CC Yizhou
>
>CC Binbin
>
>
>I like your way of translating docs, good job!
>
>
>Thanks,
>Yanteng


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH -next] docs/zh_CN: add vm transhuge translation
  2022-06-30  2:11   ` Wu XiangCheng
@ 2022-07-01  2:49     ` guomengqi (A)
  2022-07-01  9:24       ` YanTeng Si
  0 siblings, 1 reply; 12+ messages in thread
From: guomengqi (A) @ 2022-07-01  2:49 UTC (permalink / raw)
  To: Wu XiangCheng, YanTeng Si, alexs, corbet, linux-doc,
	linux-kernel, yizhou.tang, Binbin Zhou
  Cc: xuqiang36


在 2022/6/30 10:11, Wu XiangCheng 写道:
>
> 于 2022年6月29日 GMT+08:00 上午11:50:11, YanTeng Si <siyanteng@loongson.cn> 写到:
>> Hi Mengqi
>>
>> 在 2022/6/28 21:37, Guo Mengqi 写道:
>>> Translate .../vm/transhuge.rst into Chinese.
>>>
>>> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
>>> ---
>>>    Documentation/translations/zh_CN/vm/index.rst |   2 +-
>>>    .../translations/zh_CN/vm/transhuge.rst       | 151 ++++++++++++++++++
>>>    2 files changed, 152 insertions(+), 1 deletion(-)
>>>    create mode 100644 Documentation/translations/zh_CN/vm/transhuge.rst
>> When I apply your patch(next-tree), git complains:
>>
>> Applying: docs/zh_CN: add vm transhuge translation
>>
>> error: Documentation/translations/zh_CN/vm/index.rst: does not exist in index
>> .git/rebase-apply/patch:180: new blank line at EOF.
>> +
>> Patch failed at 0001 docs/zh_CN: add vm transhuge translation
>
> The /vm/ documentations (including translations) have been moved to /mm/ in linux-next tree.
>
> Not sure about docs-next, please check that.

Yes, I just found out /vm/ changed to /mm/ in docs-next a few days ago.

>>> diff --git a/Documentation/translations/zh_CN/vm/index.rst b/Documentation/translations/zh_CN/vm/index.rst
>>> index c77a56553845..2d82b15b272b 100644
>>> --- a/Documentation/translations/zh_CN/vm/index.rst
>>> +++ b/Documentation/translations/zh_CN/vm/index.rst
>>> @@ -59,11 +59,11 @@ Linux内存管理文档
>>>       vmalloced-kernel-stacks
>>>       z3fold
>>>       zsmalloc
>>> +   transhuge
>>>      TODOLIST:
>>>    * arch_pgtable_helpers
>>>    * free_page_reporting
>>>    * hugetlbfs_reserv
>>>    * slub
>>> -* transhuge
>>>    * unevictable-lru
>>> diff --git a/Documentation/translations/zh_CN/vm/transhuge.rst b/Documentation/translations/zh_CN/vm/transhuge.rst
>>> new file mode 100644
>>> index 000000000000..a7bed8b13a47
>>> --- /dev/null
>>> +++ b/Documentation/translations/zh_CN/vm/transhuge.rst
>>> @@ -0,0 +1,151 @@
>>> +.. SPDX-License-Identifier: GPL-2.0
>>> +.. include:: ../disclaimer-zh_CN.rst
>>> +
>>> +:Original: Documentation/vm/transhuge.rst
>>> +
>>> +:翻译:
>>> +
>>> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
>>> +
>>> +:校译:
>>> +
>>> +==============
>>> +透明大页机制
>> huge 巨大
>>
>> large 大
>>
>>
>> so 大页 -> 巨页
> Here I think both is OK, and 大页 seems more common?
>
> Thanks,
> Wu

Hi Yanteng and Wu

Huge->巨 is more faithful to its original word, but I translate it into 
大页 because in our company we do use 大页 more.

If it is not ambiguous, I think both of them are OK?

>>> +==============
>>> +
>>> +本文档描述透明大页(THP)的设计理念,以及它是如何与内存管理系统其他部分交互的。
>> 以及它是如何与内存管理系统的其他部分交互的
>>
>>> +
>>> +设计原则
>>> +========
>>> +
>>> +- “优雅fallback”:有些mm组件不了解透明大页的存在,它们的回退方法是将PMD页表项
>>> +  拆分成PTE页表项。必要时还需要拆分透明大页。这样就可以在常规大小的页或页表项上
>>> +  继续工作。
>>> +
>>> +- 如果内存碎片化导致大页分配失败,则分配常规页作为替代放入原vma中,此期间不应
>>> +  产生任何失败或明显延迟,不要引起用户态的注意。
>> How about
>>
>> 此期间不会产生任何失败或明显延迟,也不会引起用户态的注意。
>>
>>> +
>>> +- 如果一些进程退出后释放了空余的大页(不论在伙伴系统还是在VM),由常规页支持的
>> 空余 -> 空闲 or 可用
>>> +  guest物理内存应该自动重新申请为大页。(通过khugepaged进程)
>>> +
>>> +- 透明大页不需要预留内存,而是尽可能使用已经存在的大页。(唯为避免不可移动的页
>> del 唯
>>> +  将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅
>>> +  针对透明大页,而对内核中所有动态的多级页面申请都通用。)
>> 都适用 or 对xxxxx页面申请通用。
>>> +
>>> +get_user_pages和follow_page
>>> +===========================
>>> +
>>> +不论对单个大页还是hugetlbfs,使用get_user_pages和follow_page时,返回的会是首页或
>> 使用get_user_pages(GUP)
>>
>>> +尾页。大多数情况下调用get_user_page功能的人不关心页的大小,只关心页的真实物理
>> 调用GUP功能
>>
>>> +地址以及暂时的pin页,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问
>>> +尾页的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者
>>> +尾页被引用,大页就不能再被拆分了。
>>> +
>>> +.. note::
>>> +   以上限制不是针对GUP API新增,而是为了与在hugetlbfs中保持一致。这样如果驱动
>>> +   能在hugetlbfs中使用GUP,就能够切换到透明大页机制支持的GUP。
>>> +
>>> +优雅fallback
>>> +============
>>> +
>>> +为查页表流程增加大页支持只需添加split_huge_pmd(vma, pmd,
>>> +addr)即可。其中pmd为pmd_offset返回值。要为代码添加透明大页支持很简单,搜索
>>> +"pmd_offset"并将split_huge_pmd添加到所有返回的pmd后面。这短短一行的fallback函数
>>> +很巧妙,为我们省去了额外的适配代码(通常会很长或者很复杂)。
>>> +
>>> +如果你需要在没有页表的情况下处理一个大页,可以使用split_huge_page(page)把它拆分
>>> +成小页。linux VM就是通过这种方式将大页换出。如果页面被pin住了,split_huge_page
>>> +就会失败。
>>> +
>>> +例子:添加一行代码使mremap.c支持透明大页::
>>> +
>>> +        diff --git a/mm/mremap.c b/mm/mremap.c
>>> +        --- a/mm/mremap.c
>>> +        +++ b/mm/mremap.c
>>> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
>>> +                return NULL;
>>> +
>>> +                pmd = pmd_offset(pud, addr);
>>> +        +       split_huge_pmd(vma, pmd, addr);
>>> +                if (pmd_none_or_clear_bad(pmd))
>>> +                    return NULL;
>>> +
>>> +大页支持中的锁使用
>>> +==================
>>> +
>>> +我们希望尽可能多的代码能原生支持透明大页,因为调用split_huge_page()和
>>> +split_huge_pmd()还是有开销的。
>>> +
>>> +要让查页表操作变得能处理huge pmd,只需对pmd_offset返回的pmd调用
>>> +pmd_trans_huge()。一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的
>>> +大页pmd(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
>>> +如果pmd_trans_huge返回false,那就回到原来的流程。如果pmd_trans_huge返回true,
>>> +就需要先持有页表锁(pmd_lock()),然后再调一次pmd_trans_huge. 持页表锁是为了防止
>>> +大页pmd被转换成小页(split_huge_pmd可以跟查页表操作同时进行)。如果第二次
>>> +pmd_trans_huge返回false,那就释放页表锁,依然回到原有流程。如果返回true,就可以
>>> +继续处理huge pmd和hugepage了。处理完毕,再释放页表锁。
>>> +
>>> +引用计数和透明大页
>>> +==================
>>> +
>>> +THP的计数跟其他复合页的计数大致相同:
>>> +
>>> + - get_page()/put_page()和GUP都在首页上进行计数(修改head page->_refcount)
>>> +
>>> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
>>> +
>>> + - map/unmap特定PTE entry时,增减的是复合页中相应子页的_mapcount.
>>> +
>>> + - map/unmap整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
>>> +   尾页中。对于文件中的大页,还要增加所有子页中的_mapcount,这样是为了在检测
>>> +   子页的解映射时不需考虑竞争问题。
>> map/unmap: Either you don't translate, or you translate them all.
>>> +
>>> +PageDoubleMap() 表明大页 *可能* 被映射为了PTE.
>>> +
>>> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
>>> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。
>>> +
>>> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次
>>> +map/unmap整个复合页时更改所有子页的_mapcount.
>>> +
>>> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map;
>>> +当compound_mapcount值降为0时,取消设置。
>>> +
>>> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存
>>> +page cache中移除时,取消设置。
>> 页缓存 == page cache
>>> +
>>> +split_huge_page中,在清除page struct中所有PG_head/tail位之前,需要先将首页中的
>>> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的
>>> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果大页被pin住,
>>> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为
>>> +split_huge_page的调用者也必须对首页持有一个引用)。
>>> +
>>> +对匿名页,split_huge_page用页表项迁移(migration
>>> +entries)保持来page->_refcount和page->_mapcount稳定。对文件页,直接解映射就好。
>> 保持来 -> 来保持
>>
>>> +
>>> +这套机制对物理内存扫描(physical memory scanners)也安全,scanner唯一合法引用页
>>> +的途径就是get_page_unless_zero().
>>> +
>>> +没调atomic_add()时,所有尾页的_refcount都为0. 这时scanner无法获取尾页的引用。
>>> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用
>>> +计数减去多少即可。
>>> +
>>> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了:
>>> +引用计数将会留在首页中。
>>> +
>>> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会
>>> +失败。
>>> +
>>> +局部unmap和deferred_split_huge_page()函数
>>> +==========================================
>>> +
>>> +透明大页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap()
>>> +中检查透明大页的某个子页是否已经还在使用,并将透明大页加入一个预备队列,当内存
>>> +使用需求变大时,把透明大页拆分,释放已经不用的子页。
>>> +
>>> +如果检测到局部unmap,由于处在锁中,无法拆页。而且在很多情况下,透明大页会跨VMA,
>>> +这时会在exit(2)中进行局部unmap,这时拆页效果适得其反。
>> 由于xxxxx而且xxxxxx所以xxxxxxx
>>
>> 这时 is used too much
>>
>>
>>> +
>>> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正
>>> +的拆页操作是通过内存压力导致的shrinker函数来触发。
>> shrinker接口
>>
>>> +
>> CC Yizhou
>>
>> CC Binbin
>>
>>
>> I like your way of translating docs, good job!
>>
>>
>> Thanks,
>> Yanteng
> .

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH -next] docs/zh_CN: add vm transhuge translation
  2022-06-29  3:50 ` YanTeng Si
  2022-06-30  2:11   ` Wu XiangCheng
@ 2022-07-01  3:28   ` guomengqi (A)
  1 sibling, 0 replies; 12+ messages in thread
From: guomengqi (A) @ 2022-07-01  3:28 UTC (permalink / raw)
  To: YanTeng Si, alexs, corbet, bobwxc, linux-doc, linux-kernel,
	yizhou.tang, Binbin Zhou
  Cc: xuqiang36


在 2022/6/29 11:50, YanTeng Si 写道:
> Hi Mengqi
>
> 在 2022/6/28 21:37, Guo Mengqi 写道:
>> Translate .../vm/transhuge.rst into Chinese.
>>
>> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
>> ---
>>   Documentation/translations/zh_CN/vm/index.rst |   2 +-
>>   .../translations/zh_CN/vm/transhuge.rst       | 151 ++++++++++++++++++
>>   2 files changed, 152 insertions(+), 1 deletion(-)
>>   create mode 100644 Documentation/translations/zh_CN/vm/transhuge.rst
>
> When I apply your patch(next-tree), git complains:
>
> Applying: docs/zh_CN: add vm transhuge translation
>
> error: Documentation/translations/zh_CN/vm/index.rst: does not exist 
> in index
> .git/rebase-apply/patch:180: new blank line at EOF.
> +
> Patch failed at 0001 docs/zh_CN: add vm transhuge translation
I found vm/ changed to mm/. Will fix this.
>>
>> diff --git a/Documentation/translations/zh_CN/vm/index.rst 
>> b/Documentation/translations/zh_CN/vm/index.rst
>> index c77a56553845..2d82b15b272b 100644
>> --- a/Documentation/translations/zh_CN/vm/index.rst
>> +++ b/Documentation/translations/zh_CN/vm/index.rst
>> @@ -59,11 +59,11 @@ Linux内存管理文档
>>      vmalloced-kernel-stacks
>>      z3fold
>>      zsmalloc
>> +   transhuge
>>     TODOLIST:
>>   * arch_pgtable_helpers
>>   * free_page_reporting
>>   * hugetlbfs_reserv
>>   * slub
>> -* transhuge
>>   * unevictable-lru
>> diff --git a/Documentation/translations/zh_CN/vm/transhuge.rst 
>> b/Documentation/translations/zh_CN/vm/transhuge.rst
>> new file mode 100644
>> index 000000000000..a7bed8b13a47
>> --- /dev/null
>> +++ b/Documentation/translations/zh_CN/vm/transhuge.rst
>> @@ -0,0 +1,151 @@
>> +.. SPDX-License-Identifier: GPL-2.0
>> +.. include:: ../disclaimer-zh_CN.rst
>> +
>> +:Original: Documentation/vm/transhuge.rst
>> +
>> +:翻译:
>> +
>> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
>> +
>> +:校译:
>> +
>> +==============
>> +透明大页机制
>
> huge 巨大
>
> large 大
>
>
> so 大页 -> 巨页
>
Please see the reply to later discussions with Wu XiangCheng.
>> +==============
>> +
>> +本文档描述透明大页(THP)的设计理念,以及它是如何与内存管理系统其他部分交互的。 
>>
>
> 以及它是如何与内存管理系统的其他部分交互的
>
ok
>> +
>> +设计原则
>> +========
>> +
>> +- 
>> “优雅fallback”:有些mm组件不了解透明大页的存在,它们的回退方法是将PMD页表项 
>>
>> +  
>> 拆分成PTE页表项。必要时还需要拆分透明大页。这样就可以在常规大小的页或页表项上 
>>
>> +  继续工作。
>> +
>> +- 
>> 如果内存碎片化导致大页分配失败,则分配常规页作为替代放入原vma中,此期间不应 
>>
>> +  产生任何失败或明显延迟,不要引起用户态的注意。
>
> How about
>
> 此期间不会产生任何失败或明显延迟,也不会引起用户态的注意。
>
ok
>> +
>> +- 
>> 如果一些进程退出后释放了空余的大页(不论在伙伴系统还是在VM),由常规页支持的 
>>
> 空余 -> 空闲 or 可用
ok
>> +  guest物理内存应该自动重新申请为大页。(通过khugepaged进程)
>> +
>> +- 
>> 透明大页不需要预留内存,而是尽可能使用已经存在的大页。(唯为避免不可移动的页 
>>
> del 唯
ok
>> + 
>> 将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅 
>>
>> +  针对透明大页,而对内核中所有动态的多级页面申请都通用。)
> 都适用 or 对xxxxx页面申请通用。
ok
>> +
>> +get_user_pages和follow_page
>> +===========================
>> +
>> +不论对单个大页还是hugetlbfs,使用get_user_pages和follow_page时,返回的会是首页或 
>>
>
> 使用get_user_pages(GUP)
>
>> +尾页。大多数情况下调用get_user_page功能的人不关心页的大小,只关心页的真实物理 
>>
>
> 调用GUP功能
>
ok
>> +地址以及暂时的pin页,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问 
>>
>> +尾页的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者 
>>
>> +尾页被引用,大页就不能再被拆分了。
>> +
>> +.. note::
>> +   以上限制不是针对GUP 
>> API新增,而是为了与在hugetlbfs中保持一致。这样如果驱动
>> +   能在hugetlbfs中使用GUP,就能够切换到透明大页机制支持的GUP。
>> +
>> +优雅fallback
>> +============
>> +
>> +为查页表流程增加大页支持只需添加split_huge_pmd(vma, pmd,
>> +addr)即可。其中pmd为pmd_offset返回值。要为代码添加透明大页支持很简单,搜索 
>>
>> +"pmd_offset"并将split_huge_pmd添加到所有返回的pmd后面。这短短一行的fallback函数 
>>
>> +很巧妙,为我们省去了额外的适配代码(通常会很长或者很复杂)。
>> +
>> +如果你需要在没有页表的情况下处理一个大页,可以使用split_huge_page(page)把它拆分 
>>
>> +成小页。linux 
>> VM就是通过这种方式将大页换出。如果页面被pin住了,split_huge_page
>> +就会失败。
>> +
>> +例子:添加一行代码使mremap.c支持透明大页::
>> +
>> +        diff --git a/mm/mremap.c b/mm/mremap.c
>> +        --- a/mm/mremap.c
>> +        +++ b/mm/mremap.c
>> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
>> +                return NULL;
>> +
>> +                pmd = pmd_offset(pud, addr);
>> +        +       split_huge_pmd(vma, pmd, addr);
>> +                if (pmd_none_or_clear_bad(pmd))
>> +                    return NULL;
>> +
>> +大页支持中的锁使用
>> +==================
>> +
>> +我们希望尽可能多的代码能原生支持透明大页,因为调用split_huge_page()和
>> +split_huge_pmd()还是有开销的。
>> +
>> +要让查页表操作变得能处理huge pmd,只需对pmd_offset返回的pmd调用
>> +pmd_trans_huge()。一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的 
>>
>> +大页pmd(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma 
>> lock)。
>> +如果pmd_trans_huge返回false,那就回到原来的流程。如果pmd_trans_huge返回true, 
>>
>> +就需要先持有页表锁(pmd_lock()),然后再调一次pmd_trans_huge. 
>> 持页表锁是为了防止
>> +大页pmd被转换成小页(split_huge_pmd可以跟查页表操作同时进行)。如果第二次 
>>
>> +pmd_trans_huge返回false,那就释放页表锁,依然回到原有流程。如果返回true,就可以 
>>
>> +继续处理huge pmd和hugepage了。处理完毕,再释放页表锁。
>> +
>> +引用计数和透明大页
>> +==================
>> +
>> +THP的计数跟其他复合页的计数大致相同:
>> +
>> + - get_page()/put_page()和GUP都在首页上进行计数(修改head 
>> page->_refcount)
>> +
>> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
>> +
>> + - map/unmap特定PTE entry时,增减的是复合页中相应子页的_mapcount.
>> +
>> + - 
>> map/unmap整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
>> +   
>> 尾页中。对于文件中的大页,还要增加所有子页中的_mapcount,这样是为了在检测 
>>
>> +   子页的解映射时不需考虑竞争问题。
> map/unmap: Either you don't translate, or you translate them all.
ok
>> +
>> +PageDoubleMap() 表明大页 *可能* 被映射为了PTE.
>> +
>> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
>> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。 
>>
>> +
>> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次 
>>
>> +map/unmap整个复合页时更改所有子页的_mapcount.
>> +
>> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map; 
>>
>> +当compound_mapcount值降为0时,取消设置。
>> +
>> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存 
>>
>> +page cache中移除时,取消设置。
> 页缓存 == page cache
ok
>> +
>> +split_huge_page中,在清除page 
>> struct中所有PG_head/tail位之前,需要先将首页中的
>> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的 
>>
>> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果大页被pin住,
>> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为 
>>
>> +split_huge_page的调用者也必须对首页持有一个引用)。
>> +
>> +对匿名页,split_huge_page用页表项迁移(migration
>> +entries)保持来page->_refcount和page->_mapcount稳定。对文件页,直接解映射就好。 
>>
>
> 保持来 -> 来保持
ok
>
>> +
>> +这套机制对物理内存扫描(physical memory 
>> scanners)也安全,scanner唯一合法引用页
>> +的途径就是get_page_unless_zero().
>> +
>> +没调atomic_add()时,所有尾页的_refcount都为0. 
>> 这时scanner无法获取尾页的引用。
>> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用 
>>
>> +计数减去多少即可。
>> +
>> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了: 
>>
>> +引用计数将会留在首页中。
>> +
>> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会 
>>
>> +失败。
>> +
>> +局部unmap和deferred_split_huge_page()函数
>> +==========================================
>> +
>> +透明大页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap() 
>>
>> +中检查透明大页的某个子页是否已经还在使用,并将透明大页加入一个预备队列,当内存 
>>
>> +使用需求变大时,把透明大页拆分,释放已经不用的子页。
>> +
>> +如果检测到局部unmap,由于处在锁中,无法拆页。而且在很多情况下,透明大页会跨VMA, 
>>
>> +这时会在exit(2)中进行局部unmap,这时拆页效果适得其反。
>
> 由于xxxxx而且xxxxxx所以xxxxxxx
>
> 这时 is used too much
>
>
ok
>> +
>> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正 
>>
>> +的拆页操作是通过内存压力导致的shrinker函数来触发。
>
> shrinker接口
ok
>
>> +
>
> CC Yizhou
>
> CC Binbin
>
>
> I like your way of translating docs, good job!
>
Thank you! : )
>
> Thanks,
> Yanteng
>
> .

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH -next] docs/zh_CN: add vm transhuge translation
  2022-07-01  2:49     ` guomengqi (A)
@ 2022-07-01  9:24       ` YanTeng Si
  0 siblings, 0 replies; 12+ messages in thread
From: YanTeng Si @ 2022-07-01  9:24 UTC (permalink / raw)
  To: guomengqi (A),
	Wu XiangCheng, alexs, corbet, linux-doc, linux-kernel,
	yizhou.tang, Binbin Zhou
  Cc: xuqiang36


在 2022/7/1 10:49, guomengqi (A) 写道:
>
> 在 2022/6/30 10:11, Wu XiangCheng 写道:
>>
>> 于 2022年6月29日 GMT+08:00 上午11:50:11, YanTeng Si 
>> <siyanteng@loongson.cn> 写到:
>>> Hi Mengqi
>>>
>>> 在 2022/6/28 21:37, Guo Mengqi 写道:
>>>> Translate .../vm/transhuge.rst into Chinese.
>>>>
>>>> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
>>>> ---
>>>>    Documentation/translations/zh_CN/vm/index.rst |   2 +-
>>>>    .../translations/zh_CN/vm/transhuge.rst       | 151 
>>>> ++++++++++++++++++
>>>>    2 files changed, 152 insertions(+), 1 deletion(-)
>>>>    create mode 100644 
>>>> Documentation/translations/zh_CN/vm/transhuge.rst
>>> When I apply your patch(next-tree), git complains:
>>>
>>> Applying: docs/zh_CN: add vm transhuge translation
>>>
>>> error: Documentation/translations/zh_CN/vm/index.rst: does not exist 
>>> in index
>>> .git/rebase-apply/patch:180: new blank line at EOF.
>>> +
>>> Patch failed at 0001 docs/zh_CN: add vm transhuge translation
>>
>> The /vm/ documentations (including translations) have been moved to 
>> /mm/ in linux-next tree.
>>
>> Not sure about docs-next, please check that.
>
> Yes, I just found out /vm/ changed to /mm/ in docs-next a few days ago.
>
>>>> diff --git a/Documentation/translations/zh_CN/vm/index.rst 
>>>> b/Documentation/translations/zh_CN/vm/index.rst
>>>> index c77a56553845..2d82b15b272b 100644
>>>> --- a/Documentation/translations/zh_CN/vm/index.rst
>>>> +++ b/Documentation/translations/zh_CN/vm/index.rst
>>>> @@ -59,11 +59,11 @@ Linux内存管理文档
>>>>       vmalloced-kernel-stacks
>>>>       z3fold
>>>>       zsmalloc
>>>> +   transhuge
>>>>      TODOLIST:
>>>>    * arch_pgtable_helpers
>>>>    * free_page_reporting
>>>>    * hugetlbfs_reserv
>>>>    * slub
>>>> -* transhuge
>>>>    * unevictable-lru
>>>> diff --git a/Documentation/translations/zh_CN/vm/transhuge.rst 
>>>> b/Documentation/translations/zh_CN/vm/transhuge.rst
>>>> new file mode 100644
>>>> index 000000000000..a7bed8b13a47
>>>> --- /dev/null
>>>> +++ b/Documentation/translations/zh_CN/vm/transhuge.rst
>>>> @@ -0,0 +1,151 @@
>>>> +.. SPDX-License-Identifier: GPL-2.0
>>>> +.. include:: ../disclaimer-zh_CN.rst
>>>> +
>>>> +:Original: Documentation/vm/transhuge.rst
>>>> +
>>>> +:翻译:
>>>> +
>>>> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
>>>> +
>>>> +:校译:
>>>> +
>>>> +==============
>>>> +透明大页机制
>>> huge 巨大
>>>
>>> large 大
>>>
>>>
>>> so 大页 -> 巨页
>> Here I think both is OK, and 大页 seems more common?
>>
>> Thanks,
>> Wu
>
> Hi Yanteng and Wu
>
> Huge->巨 is more faithful to its original word, but I translate it into 
> 大页 because in our company we do use 大页 more.
I've translated hugepages to 巨页 in zh_CN/mm/hugetlbfs_reserv.rst.
>
> If it is not ambiguous, I think both of them are OK?

If both of them are OK, I suggest we better keep a consistent translation.


Thanks,

Yanteng

>
>>>> +==============
>>>> +
>>>> +本文档描述透明大页(THP)的设计理念,以及它是如何与内存管理系统其他部分交互的。 
>>>>
>>> 以及它是如何与内存管理系统的其他部分交互的
>>>
>>>> +
>>>> +设计原则
>>>> +========
>>>> +
>>>> +- 
>>>> “优雅fallback”:有些mm组件不了解透明大页的存在,它们的回退方法是将PMD页表项 
>>>>
>>>> +  
>>>> 拆分成PTE页表项。必要时还需要拆分透明大页。这样就可以在常规大小的页或页表项上 
>>>>
>>>> +  继续工作。
>>>> +
>>>> +- 
>>>> 如果内存碎片化导致大页分配失败,则分配常规页作为替代放入原vma中,此期间不应 
>>>>
>>>> +  产生任何失败或明显延迟,不要引起用户态的注意。
>>> How about
>>>
>>> 此期间不会产生任何失败或明显延迟,也不会引起用户态的注意。
>>>
>>>> +
>>>> +- 
>>>> 如果一些进程退出后释放了空余的大页(不论在伙伴系统还是在VM),由常规页支持的 
>>>>
>>> 空余 -> 空闲 or 可用
>>>> + guest物理内存应该自动重新申请为大页。(通过khugepaged进程)
>>>> +
>>>> +- 
>>>> 透明大页不需要预留内存,而是尽可能使用已经存在的大页。(唯为避免不可移动的页 
>>>>
>>> del 唯
>>>> + 
>>>> 将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅 
>>>>
>>>> +  针对透明大页,而对内核中所有动态的多级页面申请都通用。)
>>> 都适用 or 对xxxxx页面申请通用。
>>>> +
>>>> +get_user_pages和follow_page
>>>> +===========================
>>>> +
>>>> +不论对单个大页还是hugetlbfs,使用get_user_pages和follow_page时,返回的会是首页或 
>>>>
>>> 使用get_user_pages(GUP)
>>>
>>>> +尾页。大多数情况下调用get_user_page功能的人不关心页的大小,只关心页的真实物理 
>>>>
>>> 调用GUP功能
>>>
>>>> +地址以及暂时的pin页,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问 
>>>>
>>>> +尾页的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者 
>>>>
>>>> +尾页被引用,大页就不能再被拆分了。
>>>> +
>>>> +.. note::
>>>> +   以上限制不是针对GUP 
>>>> API新增,而是为了与在hugetlbfs中保持一致。这样如果驱动
>>>> +   能在hugetlbfs中使用GUP,就能够切换到透明大页机制支持的GUP。
>>>> +
>>>> +优雅fallback
>>>> +============
>>>> +
>>>> +为查页表流程增加大页支持只需添加split_huge_pmd(vma, pmd,
>>>> +addr)即可。其中pmd为pmd_offset返回值。要为代码添加透明大页支持很简单,搜索 
>>>>
>>>> +"pmd_offset"并将split_huge_pmd添加到所有返回的pmd后面。这短短一行的fallback函数 
>>>>
>>>> +很巧妙,为我们省去了额外的适配代码(通常会很长或者很复杂)。
>>>> +
>>>> +如果你需要在没有页表的情况下处理一个大页,可以使用split_huge_page(page)把它拆分 
>>>>
>>>> +成小页。linux 
>>>> VM就是通过这种方式将大页换出。如果页面被pin住了,split_huge_page
>>>> +就会失败。
>>>> +
>>>> +例子:添加一行代码使mremap.c支持透明大页::
>>>> +
>>>> +        diff --git a/mm/mremap.c b/mm/mremap.c
>>>> +        --- a/mm/mremap.c
>>>> +        +++ b/mm/mremap.c
>>>> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
>>>> +                return NULL;
>>>> +
>>>> +                pmd = pmd_offset(pud, addr);
>>>> +        +       split_huge_pmd(vma, pmd, addr);
>>>> +                if (pmd_none_or_clear_bad(pmd))
>>>> +                    return NULL;
>>>> +
>>>> +大页支持中的锁使用
>>>> +==================
>>>> +
>>>> +我们希望尽可能多的代码能原生支持透明大页,因为调用split_huge_page()和
>>>> +split_huge_pmd()还是有开销的。
>>>> +
>>>> +要让查页表操作变得能处理huge pmd,只需对pmd_offset返回的pmd调用
>>>> +pmd_trans_huge()。一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的 
>>>>
>>>> +大页pmd(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma 
>>>> lock)。
>>>> +如果pmd_trans_huge返回false,那就回到原来的流程。如果pmd_trans_huge返回true, 
>>>>
>>>> +就需要先持有页表锁(pmd_lock()),然后再调一次pmd_trans_huge. 
>>>> 持页表锁是为了防止
>>>> +大页pmd被转换成小页(split_huge_pmd可以跟查页表操作同时进行)。如果第二次 
>>>>
>>>> +pmd_trans_huge返回false,那就释放页表锁,依然回到原有流程。如果返回true,就可以 
>>>>
>>>> +继续处理huge pmd和hugepage了。处理完毕,再释放页表锁。
>>>> +
>>>> +引用计数和透明大页
>>>> +==================
>>>> +
>>>> +THP的计数跟其他复合页的计数大致相同:
>>>> +
>>>> + - get_page()/put_page()和GUP都在首页上进行计数(修改head 
>>>> page->_refcount)
>>>> +
>>>> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
>>>> +
>>>> + - map/unmap特定PTE entry时,增减的是复合页中相应子页的_mapcount.
>>>> +
>>>> + - 
>>>> map/unmap整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个 
>>>>
>>>> +   
>>>> 尾页中。对于文件中的大页,还要增加所有子页中的_mapcount,这样是为了在检测 
>>>>
>>>> +   子页的解映射时不需考虑竞争问题。
>>> map/unmap: Either you don't translate, or you translate them all.
>>>> +
>>>> +PageDoubleMap() 表明大页 *可能* 被映射为了PTE.
>>>> +
>>>> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
>>>> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。 
>>>>
>>>> +
>>>> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次 
>>>>
>>>> +map/unmap整个复合页时更改所有子页的_mapcount.
>>>> +
>>>> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map; 
>>>>
>>>> +当compound_mapcount值降为0时,取消设置。
>>>> +
>>>> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 
>>>> 在页面从页缓存
>>>> +page cache中移除时,取消设置。
>>> 页缓存 == page cache
>>>> +
>>>> +split_huge_page中,在清除page 
>>>> struct中所有PG_head/tail位之前,需要先将首页中的
>>>> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的 
>>>>
>>>> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果大页被pin住, 
>>>>
>>>> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为 
>>>>
>>>> +split_huge_page的调用者也必须对首页持有一个引用)。
>>>> +
>>>> +对匿名页,split_huge_page用页表项迁移(migration
>>>> +entries)保持来page->_refcount和page->_mapcount稳定。对文件页,直接解映射就好。 
>>>>
>>> 保持来 -> 来保持
>>>
>>>> +
>>>> +这套机制对物理内存扫描(physical memory 
>>>> scanners)也安全,scanner唯一合法引用页
>>>> +的途径就是get_page_unless_zero().
>>>> +
>>>> +没调atomic_add()时,所有尾页的_refcount都为0. 
>>>> 这时scanner无法获取尾页的引用。
>>>> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用 
>>>>
>>>> +计数减去多少即可。
>>>> +
>>>> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了: 
>>>>
>>>> +引用计数将会留在首页中。
>>>> +
>>>> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会 
>>>>
>>>> +失败。
>>>> +
>>>> +局部unmap和deferred_split_huge_page()函数
>>>> +==========================================
>>>> +
>>>> +透明大页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap() 
>>>>
>>>> +中检查透明大页的某个子页是否已经还在使用,并将透明大页加入一个预备队列,当内存 
>>>>
>>>> +使用需求变大时,把透明大页拆分,释放已经不用的子页。
>>>> +
>>>> +如果检测到局部unmap,由于处在锁中,无法拆页。而且在很多情况下,透明大页会跨VMA, 
>>>>
>>>> +这时会在exit(2)中进行局部unmap,这时拆页效果适得其反。
>>> 由于xxxxx而且xxxxxx所以xxxxxxx
>>>
>>> 这时 is used too much
>>>
>>>
>>>> +
>>>> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正 
>>>>
>>>> +的拆页操作是通过内存压力导致的shrinker函数来触发。
>>> shrinker接口
>>>
>>>> +
>>> CC Yizhou
>>>
>>> CC Binbin
>>>
>>>
>>> I like your way of translating docs, good job!
>>>
>>>
>>> Thanks,
>>> Yanteng
>> .


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH -next v2] docs/zh_CN: add mm transhuge translation
  2022-06-28 13:37 [PATCH -next] docs/zh_CN: add vm transhuge translation Guo Mengqi
  2022-06-29  3:50 ` YanTeng Si
  2022-06-29  6:37 ` Alex Shi
@ 2022-07-05 14:11 ` Guo Mengqi
  2022-07-06  3:00   ` Alex Shi
  2022-07-07  1:14   ` YanTeng Si
  2 siblings, 2 replies; 12+ messages in thread
From: Guo Mengqi @ 2022-07-05 14:11 UTC (permalink / raw)
  To: alexs, siyanteng, corbet, tangyizhou, linux-doc, linux-kernel
  Cc: xuqiang36, zhouguanghui1, guomengqi3, zhoubinbin, bobwxc

Translate .../mm/transhuge.rst into Chinese.

Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
---
 Documentation/translations/zh_CN/mm/index.rst |   2 +-
 .../translations/zh_CN/mm/transhuge.rst       | 153 ++++++++++++++++++
 2 files changed, 154 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/translations/zh_CN/mm/transhuge.rst

diff --git a/Documentation/translations/zh_CN/mm/index.rst b/Documentation/translations/zh_CN/mm/index.rst
index 2f53e37b8049..d0c80025c3ce 100644
--- a/Documentation/translations/zh_CN/mm/index.rst
+++ b/Documentation/translations/zh_CN/mm/index.rst
@@ -56,6 +56,7 @@ Linux内存管理文档
    page_table_check
    remap_file_pages
    split_page_table_lock
+   transhuge
    vmalloced-kernel-stacks
    z3fold
    zsmalloc
@@ -65,5 +66,4 @@ TODOLIST:
 * free_page_reporting
 * hugetlbfs_reserv
 * slub
-* transhuge
 * unevictable-lru
diff --git a/Documentation/translations/zh_CN/mm/transhuge.rst b/Documentation/translations/zh_CN/mm/transhuge.rst
new file mode 100644
index 000000000000..5204b1113fbf
--- /dev/null
+++ b/Documentation/translations/zh_CN/mm/transhuge.rst
@@ -0,0 +1,153 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: Documentation/vm/transhuge.rst
+
+:翻译:
+
+ 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
+
+:校译:
+
+ 司延腾 Yanteng Si <siyanteng@loongson.cn>
+ 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
+ 时奎亮 Alex Shi <alexs@kernel.org>
+
+==============
+透明巨页机制
+==============
+
+本文档描述透明巨页(THP)的设计理念,以及它是如何与内存管理系统的其它部分交互的。
+
+设计原则
+========
+
+- “优雅回退”:有些mm组件不感知透明巨页,它们的回退方法是将PMD页表项拆分成PTE
+  页表项。必要时还需要拆分透明巨页。这样就可以在常规大小的页或页表项上继续工作。
+
+- 如果内存碎片化导致巨页分配失败,则分配常规页作为替代放入原vma中,此期间不会
+  产生任何失败或明显延迟,也不会引起用户态的注意。
+
+- 如果一些进程退出后释放了空闲的巨页(不论在伙伴系统还是在VM),由常规页支持的
+  guest物理内存应该自动重新申请为巨页。(通过khugepaged进程)
+
+- 透明巨页不需要预留内存,而是尽可能使用已经存在的巨页。(为避免不可移动的页
+  将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅
+  针对透明巨页,而对内核中所有动态的多级页面申请都适用。)
+
+get_user_pages和follow_page
+===========================
+
+不论对单个巨页还是hugetlbfs,使用get_user_pages(GUP)和follow_page时,返回的会是
+首页或尾页。大多数情况下调用GUP功能的人不关心页的大小,只关心页的真实物理地址
+以及暂时将页固定,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问尾页
+的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者尾页
+被引用,巨页就不能再被拆分了。
+
+.. note::
+   以上不是针对GUP API的新增限制,它们和hugetlbfs的限制保持一致。因此,如果任何
+   驱动能够在hugetlbfs中处理GUP,它们也能在基于透明巨页的映射中很好的工作。
+
+优雅回退
+============
+
+遍历页表但又不需感知巨页pmd的代码可以这样简单处理:对pmd_offset返回的pmd添加一行
+split_huge_pmd(vma, pmd, addr)调用。只需grep搜索"pmd_offset",并将
+split_huge_pmd添加到所有返回的pmd后面,代码就能够自己处理透明巨页了,非常简单。
+这短短一行的回退函数很巧妙,为我们省去了成百上千行额外的适配代码。
+
+如果你不是在遍历页表,而是遇到了一个无法直接处理的巨物理页,可以使用
+split_huge_page(page)把它拆分成小页。linux VM就是通过这种方式将巨页换出。
+如果页面被pin住了,split_huge_page就会失败。
+
+例子:添加一行代码使mremap.c支持透明巨页::
+
+        diff --git a/mm/mremap.c b/mm/mremap.c
+        --- a/mm/mremap.c
+        +++ b/mm/mremap.c
+        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
+                return NULL;
+
+                pmd = pmd_offset(pud, addr);
+        +       split_huge_pmd(vma, pmd, addr);
+                if (pmd_none_or_clear_bad(pmd))
+                    return NULL;
+
+巨页支持中的锁使用
+==================
+
+我们还是希望尽可能多的代码能感知透明巨页,因为调用split_huge_page()和
+split_huge_pmd()还是有开销的。
+
+要使遍历页表流程能够感知巨页pmd,只需对pmd_offset返回的pmd调用pmd_trans_huge()。
+一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的巨页pmd
+(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
+如果pmd_trans_huge返回结果为假,那就回到原来的流程。如果pmd_trans_huge返回结果
+为真,就需要先持有页表锁(pmd_lock()),然后再进行一次pmd_trans_huge判断。持页表锁
+是为了防止巨页pmd被转换成小页(split_huge_pmd是可以跟遍历页表操作同时进行的)。
+如果第二次pmd_trans_huge返回结果为假,那就释放页表锁,依然回到原有流程。如果返回
+结果继续为真,那就按照巨页pmd和巨页来处理,处理完毕再释放页表锁。
+
+引用计数和透明巨页
+==================
+
+THP的计数跟其他复合页的计数大致相同:
+
+ - get_page()/put_page()和GUP都在首页上进行计数(修改head page->_refcount)
+
+ - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
+
+ - 映射/解映射特定PTE entry时,增减的是复合页中相应子页的_mapcount.
+
+ - 映射/解映射整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
+   尾页中。对于文件中的巨页,还要增加所有子页中的_mapcount,这样是为了在检测
+   子页的解映射时不需考虑竞争问题。
+
+PageDoubleMap() 表明巨页 *可能* 被映射为了PTE.
+
+对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
+在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。
+
+这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次
+映射/解映射整个复合页时更改所有子页的_mapcount.
+
+对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map;
+当compound_mapcount值降为0时,取消设置。
+
+对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存中
+移除时,取消设置。
+
+split_huge_page中,在清除page struct中所有PG_head/tail位之前,需要先将首页中的
+引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的
+引用计数来源难以确定(如通过get_user_pages的pin页)。如果巨页被pin住,
+split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为
+split_huge_page的调用者也必须对首页持有一个引用)。
+
+对匿名页,split_huge_page用页表项迁移(migration entries)来保持page->_refcount
+和page->_mapcount稳定。对文件页则会直接解映射。
+
+这套机制对物理内存扫描(physical memory scanners)也安全,scanner唯一合法引用页
+的途径就是get_page_unless_zero().
+
+没调atomic_add()时,所有尾页的_refcount都为0. 这时scanner无法获取尾页的引用。
+调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用
+计数减去多少即可。
+
+对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了:
+引用计数将会留在首页中。
+
+split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会
+失败。
+
+局部解映射和deferred_split_huge_page()函数
+==========================================
+
+透明巨页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap()
+中检查透明巨页的某个子页是否还在使用,并将透明巨页加入一个预备队列,当内存
+使用需求变大时,把透明巨页拆分,释放已经不用的子页。
+
+检测到局部解映射时,由于处在锁中,无法立即进行拆页。而且在很多情况下,如果透明
+巨页是跨VMA的, 那么会在exit(2)中进行局部解映射。这时拆页效果适得其反。
+
+deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正
+的拆页操作是通过内存压力导致的shrinker接口来触发的。
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH -next v2] docs/zh_CN: add mm transhuge translation
  2022-07-05 14:11 ` [PATCH -next v2] docs/zh_CN: add mm " Guo Mengqi
@ 2022-07-06  3:00   ` Alex Shi
  2022-07-07  1:14   ` YanTeng Si
  1 sibling, 0 replies; 12+ messages in thread
From: Alex Shi @ 2022-07-06  3:00 UTC (permalink / raw)
  To: Guo Mengqi
  Cc: Alex Shi, Yanteng Si, Jonathan Corbet, Tang Yizhou,
	Linux Doc Mailing List, LKML, xuqiang36, zhouguanghui1,
	zhoubinbin, Wu X.C.

On Tue, Jul 5, 2022 at 10:13 PM Guo Mengqi <guomengqi3@huawei.com> wrote:
>
> Translate .../mm/transhuge.rst into Chinese.
>
> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>

Reviewed-by: Alex Shi <alexs@kernel.org>

> ---
>  Documentation/translations/zh_CN/mm/index.rst |   2 +-
>  .../translations/zh_CN/mm/transhuge.rst       | 153 ++++++++++++++++++
>  2 files changed, 154 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/translations/zh_CN/mm/transhuge.rst
>
> diff --git a/Documentation/translations/zh_CN/mm/index.rst b/Documentation/translations/zh_CN/mm/index.rst
> index 2f53e37b8049..d0c80025c3ce 100644
> --- a/Documentation/translations/zh_CN/mm/index.rst
> +++ b/Documentation/translations/zh_CN/mm/index.rst
> @@ -56,6 +56,7 @@ Linux内存管理文档
>     page_table_check
>     remap_file_pages
>     split_page_table_lock
> +   transhuge
>     vmalloced-kernel-stacks
>     z3fold
>     zsmalloc
> @@ -65,5 +66,4 @@ TODOLIST:
>  * free_page_reporting
>  * hugetlbfs_reserv
>  * slub
> -* transhuge
>  * unevictable-lru
> diff --git a/Documentation/translations/zh_CN/mm/transhuge.rst b/Documentation/translations/zh_CN/mm/transhuge.rst
> new file mode 100644
> index 000000000000..5204b1113fbf
> --- /dev/null
> +++ b/Documentation/translations/zh_CN/mm/transhuge.rst
> @@ -0,0 +1,153 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +.. include:: ../disclaimer-zh_CN.rst
> +
> +:Original: Documentation/vm/transhuge.rst
> +
> +:翻译:
> +
> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
> +
> +:校译:
> +
> + 司延腾 Yanteng Si <siyanteng@loongson.cn>
> + 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
> + 时奎亮 Alex Shi <alexs@kernel.org>
> +
> +==============
> +透明巨页机制
> +==============
> +
> +本文档描述透明巨页(THP)的设计理念,以及它是如何与内存管理系统的其它部分交互的。
> +
> +设计原则
> +========
> +
> +- “优雅回退”:有些mm组件不感知透明巨页,它们的回退方法是将PMD页表项拆分成PTE
> +  页表项。必要时还需要拆分透明巨页。这样就可以在常规大小的页或页表项上继续工作。
> +
> +- 如果内存碎片化导致巨页分配失败,则分配常规页作为替代放入原vma中,此期间不会
> +  产生任何失败或明显延迟,也不会引起用户态的注意。
> +
> +- 如果一些进程退出后释放了空闲的巨页(不论在伙伴系统还是在VM),由常规页支持的
> +  guest物理内存应该自动重新申请为巨页。(通过khugepaged进程)
> +
> +- 透明巨页不需要预留内存,而是尽可能使用已经存在的巨页。(为避免不可移动的页
> +  将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅
> +  针对透明巨页,而对内核中所有动态的多级页面申请都适用。)
> +
> +get_user_pages和follow_page
> +===========================
> +
> +不论对单个巨页还是hugetlbfs,使用get_user_pages(GUP)和follow_page时,返回的会是
> +首页或尾页。大多数情况下调用GUP功能的人不关心页的大小,只关心页的真实物理地址
> +以及暂时将页固定,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问尾页
> +的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者尾页
> +被引用,巨页就不能再被拆分了。
> +
> +.. note::
> +   以上不是针对GUP API的新增限制,它们和hugetlbfs的限制保持一致。因此,如果任何
> +   驱动能够在hugetlbfs中处理GUP,它们也能在基于透明巨页的映射中很好的工作。
> +
> +优雅回退
> +============
> +
> +遍历页表但又不需感知巨页pmd的代码可以这样简单处理:对pmd_offset返回的pmd添加一行
> +split_huge_pmd(vma, pmd, addr)调用。只需grep搜索"pmd_offset",并将
> +split_huge_pmd添加到所有返回的pmd后面,代码就能够自己处理透明巨页了,非常简单。
> +这短短一行的回退函数很巧妙,为我们省去了成百上千行额外的适配代码。
> +
> +如果你不是在遍历页表,而是遇到了一个无法直接处理的巨物理页,可以使用
> +split_huge_page(page)把它拆分成小页。linux VM就是通过这种方式将巨页换出。
> +如果页面被pin住了,split_huge_page就会失败。
> +
> +例子:添加一行代码使mremap.c支持透明巨页::
> +
> +        diff --git a/mm/mremap.c b/mm/mremap.c
> +        --- a/mm/mremap.c
> +        +++ b/mm/mremap.c
> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
> +                return NULL;
> +
> +                pmd = pmd_offset(pud, addr);
> +        +       split_huge_pmd(vma, pmd, addr);
> +                if (pmd_none_or_clear_bad(pmd))
> +                    return NULL;
> +
> +巨页支持中的锁使用
> +==================
> +
> +我们还是希望尽可能多的代码能感知透明巨页,因为调用split_huge_page()和
> +split_huge_pmd()还是有开销的。
> +
> +要使遍历页表流程能够感知巨页pmd,只需对pmd_offset返回的pmd调用pmd_trans_huge()。
> +一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的巨页pmd
> +(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
> +如果pmd_trans_huge返回结果为假,那就回到原来的流程。如果pmd_trans_huge返回结果
> +为真,就需要先持有页表锁(pmd_lock()),然后再进行一次pmd_trans_huge判断。持页表锁
> +是为了防止巨页pmd被转换成小页(split_huge_pmd是可以跟遍历页表操作同时进行的)。
> +如果第二次pmd_trans_huge返回结果为假,那就释放页表锁,依然回到原有流程。如果返回
> +结果继续为真,那就按照巨页pmd和巨页来处理,处理完毕再释放页表锁。
> +
> +引用计数和透明巨页
> +==================
> +
> +THP的计数跟其他复合页的计数大致相同:
> +
> + - get_page()/put_page()和GUP都在首页上进行计数(修改head page->_refcount)
> +
> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
> +
> + - 映射/解映射特定PTE entry时,增减的是复合页中相应子页的_mapcount.
> +
> + - 映射/解映射整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
> +   尾页中。对于文件中的巨页,还要增加所有子页中的_mapcount,这样是为了在检测
> +   子页的解映射时不需考虑竞争问题。
> +
> +PageDoubleMap() 表明巨页 *可能* 被映射为了PTE.
> +
> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。
> +
> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次
> +映射/解映射整个复合页时更改所有子页的_mapcount.
> +
> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map;
> +当compound_mapcount值降为0时,取消设置。
> +
> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存中
> +移除时,取消设置。
> +
> +split_huge_page中,在清除page struct中所有PG_head/tail位之前,需要先将首页中的
> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的
> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果巨页被pin住,
> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为
> +split_huge_page的调用者也必须对首页持有一个引用)。
> +
> +对匿名页,split_huge_page用页表项迁移(migration entries)来保持page->_refcount
> +和page->_mapcount稳定。对文件页则会直接解映射。
> +
> +这套机制对物理内存扫描(physical memory scanners)也安全,scanner唯一合法引用页
> +的途径就是get_page_unless_zero().
> +
> +没调atomic_add()时,所有尾页的_refcount都为0. 这时scanner无法获取尾页的引用。
> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用
> +计数减去多少即可。
> +
> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了:
> +引用计数将会留在首页中。
> +
> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会
> +失败。
> +
> +局部解映射和deferred_split_huge_page()函数
> +==========================================
> +
> +透明巨页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap()
> +中检查透明巨页的某个子页是否还在使用,并将透明巨页加入一个预备队列,当内存
> +使用需求变大时,把透明巨页拆分,释放已经不用的子页。
> +
> +检测到局部解映射时,由于处在锁中,无法立即进行拆页。而且在很多情况下,如果透明
> +巨页是跨VMA的, 那么会在exit(2)中进行局部解映射。这时拆页效果适得其反。
> +
> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正
> +的拆页操作是通过内存压力导致的shrinker接口来触发的。
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH -next v2] docs/zh_CN: add mm transhuge translation
  2022-07-05 14:11 ` [PATCH -next v2] docs/zh_CN: add mm " Guo Mengqi
  2022-07-06  3:00   ` Alex Shi
@ 2022-07-07  1:14   ` YanTeng Si
  2022-07-20  2:12     ` guomengqi (A)
  1 sibling, 1 reply; 12+ messages in thread
From: YanTeng Si @ 2022-07-07  1:14 UTC (permalink / raw)
  To: Guo Mengqi, alexs, corbet, tangyizhou, linux-doc, linux-kernel
  Cc: xuqiang36, zhouguanghui1, zhoubinbin, bobwxc


在 2022/7/5 22:11, Guo Mengqi 写道:
> Translate .../mm/transhuge.rst into Chinese.
>
> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>

Reviewed-by: Yanteng Si<siyanteng@loongson.cn>


Thanks,

Yanteng


> ---
>   Documentation/translations/zh_CN/mm/index.rst |   2 +-
>   .../translations/zh_CN/mm/transhuge.rst       | 153 ++++++++++++++++++
>   2 files changed, 154 insertions(+), 1 deletion(-)
>   create mode 100644 Documentation/translations/zh_CN/mm/transhuge.rst
>
> diff --git a/Documentation/translations/zh_CN/mm/index.rst b/Documentation/translations/zh_CN/mm/index.rst
> index 2f53e37b8049..d0c80025c3ce 100644
> --- a/Documentation/translations/zh_CN/mm/index.rst
> +++ b/Documentation/translations/zh_CN/mm/index.rst
> @@ -56,6 +56,7 @@ Linux内存管理文档
>      page_table_check
>      remap_file_pages
>      split_page_table_lock
> +   transhuge
>      vmalloced-kernel-stacks
>      z3fold
>      zsmalloc
> @@ -65,5 +66,4 @@ TODOLIST:
>   * free_page_reporting
>   * hugetlbfs_reserv
>   * slub
> -* transhuge
>   * unevictable-lru
> diff --git a/Documentation/translations/zh_CN/mm/transhuge.rst b/Documentation/translations/zh_CN/mm/transhuge.rst
> new file mode 100644
> index 000000000000..5204b1113fbf
> --- /dev/null
> +++ b/Documentation/translations/zh_CN/mm/transhuge.rst
> @@ -0,0 +1,153 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +.. include:: ../disclaimer-zh_CN.rst
> +
> +:Original: Documentation/vm/transhuge.rst
> +
> +:翻译:
> +
> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
> +
> +:校译:
> +
> + 司延腾 Yanteng Si <siyanteng@loongson.cn>
> + 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
> + 时奎亮 Alex Shi <alexs@kernel.org>
> +
> +==============
> +透明巨页机制
> +==============
> +
> +本文档描述透明巨页(THP)的设计理念,以及它是如何与内存管理系统的其它部分交互的。
> +
> +设计原则
> +========
> +
> +- “优雅回退”:有些mm组件不感知透明巨页,它们的回退方法是将PMD页表项拆分成PTE
> +  页表项。必要时还需要拆分透明巨页。这样就可以在常规大小的页或页表项上继续工作。
> +
> +- 如果内存碎片化导致巨页分配失败,则分配常规页作为替代放入原vma中,此期间不会
> +  产生任何失败或明显延迟,也不会引起用户态的注意。
> +
> +- 如果一些进程退出后释放了空闲的巨页(不论在伙伴系统还是在VM),由常规页支持的
> +  guest物理内存应该自动重新申请为巨页。(通过khugepaged进程)
> +
> +- 透明巨页不需要预留内存,而是尽可能使用已经存在的巨页。(为避免不可移动的页
> +  将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅
> +  针对透明巨页,而对内核中所有动态的多级页面申请都适用。)
> +
> +get_user_pages和follow_page
> +===========================
> +
> +不论对单个巨页还是hugetlbfs,使用get_user_pages(GUP)和follow_page时,返回的会是
> +首页或尾页。大多数情况下调用GUP功能的人不关心页的大小,只关心页的真实物理地址
> +以及暂时将页固定,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问尾页
> +的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者尾页
> +被引用,巨页就不能再被拆分了。
> +
> +.. note::
> +   以上不是针对GUP API的新增限制,它们和hugetlbfs的限制保持一致。因此,如果任何
> +   驱动能够在hugetlbfs中处理GUP,它们也能在基于透明巨页的映射中很好的工作。
> +
> +优雅回退
> +============
> +
> +遍历页表但又不需感知巨页pmd的代码可以这样简单处理:对pmd_offset返回的pmd添加一行
> +split_huge_pmd(vma, pmd, addr)调用。只需grep搜索"pmd_offset",并将
> +split_huge_pmd添加到所有返回的pmd后面,代码就能够自己处理透明巨页了,非常简单。
> +这短短一行的回退函数很巧妙,为我们省去了成百上千行额外的适配代码。
> +
> +如果你不是在遍历页表,而是遇到了一个无法直接处理的巨物理页,可以使用
> +split_huge_page(page)把它拆分成小页。linux VM就是通过这种方式将巨页换出。
> +如果页面被pin住了,split_huge_page就会失败。
> +
> +例子:添加一行代码使mremap.c支持透明巨页::
> +
> +        diff --git a/mm/mremap.c b/mm/mremap.c
> +        --- a/mm/mremap.c
> +        +++ b/mm/mremap.c
> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
> +                return NULL;
> +
> +                pmd = pmd_offset(pud, addr);
> +        +       split_huge_pmd(vma, pmd, addr);
> +                if (pmd_none_or_clear_bad(pmd))
> +                    return NULL;
> +
> +巨页支持中的锁使用
> +==================
> +
> +我们还是希望尽可能多的代码能感知透明巨页,因为调用split_huge_page()和
> +split_huge_pmd()还是有开销的。
> +
> +要使遍历页表流程能够感知巨页pmd,只需对pmd_offset返回的pmd调用pmd_trans_huge()。
> +一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的巨页pmd
> +(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
> +如果pmd_trans_huge返回结果为假,那就回到原来的流程。如果pmd_trans_huge返回结果
> +为真,就需要先持有页表锁(pmd_lock()),然后再进行一次pmd_trans_huge判断。持页表锁
> +是为了防止巨页pmd被转换成小页(split_huge_pmd是可以跟遍历页表操作同时进行的)。
> +如果第二次pmd_trans_huge返回结果为假,那就释放页表锁,依然回到原有流程。如果返回
> +结果继续为真,那就按照巨页pmd和巨页来处理,处理完毕再释放页表锁。
> +
> +引用计数和透明巨页
> +==================
> +
> +THP的计数跟其他复合页的计数大致相同:
> +
> + - get_page()/put_page()和GUP都在首页上进行计数(修改head page->_refcount)
> +
> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
> +
> + - 映射/解映射特定PTE entry时,增减的是复合页中相应子页的_mapcount.
> +
> + - 映射/解映射整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个
> +   尾页中。对于文件中的巨页,还要增加所有子页中的_mapcount,这样是为了在检测
> +   子页的解映射时不需考虑竞争问题。
> +
> +PageDoubleMap() 表明巨页 *可能* 被映射为了PTE.
> +
> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。
> +
> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次
> +映射/解映射整个复合页时更改所有子页的_mapcount.
> +
> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map;
> +当compound_mapcount值降为0时,取消设置。
> +
> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 在页面从页缓存中
> +移除时,取消设置。
> +
> +split_huge_page中,在清除page struct中所有PG_head/tail位之前,需要先将首页中的
> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的
> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果巨页被pin住,
> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为
> +split_huge_page的调用者也必须对首页持有一个引用)。
> +
> +对匿名页,split_huge_page用页表项迁移(migration entries)来保持page->_refcount
> +和page->_mapcount稳定。对文件页则会直接解映射。
> +
> +这套机制对物理内存扫描(physical memory scanners)也安全,scanner唯一合法引用页
> +的途径就是get_page_unless_zero().
> +
> +没调atomic_add()时,所有尾页的_refcount都为0. 这时scanner无法获取尾页的引用。
> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用
> +计数减去多少即可。
> +
> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了:
> +引用计数将会留在首页中。
> +
> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会
> +失败。
> +
> +局部解映射和deferred_split_huge_page()函数
> +==========================================
> +
> +透明巨页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap()
> +中检查透明巨页的某个子页是否还在使用,并将透明巨页加入一个预备队列,当内存
> +使用需求变大时,把透明巨页拆分,释放已经不用的子页。
> +
> +检测到局部解映射时,由于处在锁中,无法立即进行拆页。而且在很多情况下,如果透明
> +巨页是跨VMA的, 那么会在exit(2)中进行局部解映射。这时拆页效果适得其反。
> +
> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正
> +的拆页操作是通过内存压力导致的shrinker接口来触发的。


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH -next v2] docs/zh_CN: add mm transhuge translation
  2022-07-07  1:14   ` YanTeng Si
@ 2022-07-20  2:12     ` guomengqi (A)
  2022-07-20 21:15       ` Jonathan Corbet
  0 siblings, 1 reply; 12+ messages in thread
From: guomengqi (A) @ 2022-07-20  2:12 UTC (permalink / raw)
  To: corbet
  Cc: xuqiang36, zhouguanghui1, Tang Yizhou, Alex Shi, YanTeng Si,
	Linux Doc Mailing List

Hi Jon,

Is this patch applied? Is there anything else to be done?

Thanks,

Mengqi

在 2022/7/7 9:14, YanTeng Si 写道:
>
> 在 2022/7/5 22:11, Guo Mengqi 写道:
>> Translate .../mm/transhuge.rst into Chinese.
>>
>> Signed-off-by: Guo Mengqi <guomengqi3@huawei.com>
>
> Reviewed-by: Yanteng Si<siyanteng@loongson.cn>
>
>
> Thanks,
>
> Yanteng
>
>
>> ---
>>   Documentation/translations/zh_CN/mm/index.rst |   2 +-
>>   .../translations/zh_CN/mm/transhuge.rst       | 153 ++++++++++++++++++
>>   2 files changed, 154 insertions(+), 1 deletion(-)
>>   create mode 100644 Documentation/translations/zh_CN/mm/transhuge.rst
>>
>> diff --git a/Documentation/translations/zh_CN/mm/index.rst 
>> b/Documentation/translations/zh_CN/mm/index.rst
>> index 2f53e37b8049..d0c80025c3ce 100644
>> --- a/Documentation/translations/zh_CN/mm/index.rst
>> +++ b/Documentation/translations/zh_CN/mm/index.rst
>> @@ -56,6 +56,7 @@ Linux内存管理文档
>>      page_table_check
>>      remap_file_pages
>>      split_page_table_lock
>> +   transhuge
>>      vmalloced-kernel-stacks
>>      z3fold
>>      zsmalloc
>> @@ -65,5 +66,4 @@ TODOLIST:
>>   * free_page_reporting
>>   * hugetlbfs_reserv
>>   * slub
>> -* transhuge
>>   * unevictable-lru
>> diff --git a/Documentation/translations/zh_CN/mm/transhuge.rst 
>> b/Documentation/translations/zh_CN/mm/transhuge.rst
>> new file mode 100644
>> index 000000000000..5204b1113fbf
>> --- /dev/null
>> +++ b/Documentation/translations/zh_CN/mm/transhuge.rst
>> @@ -0,0 +1,153 @@
>> +.. SPDX-License-Identifier: GPL-2.0
>> +.. include:: ../disclaimer-zh_CN.rst
>> +
>> +:Original: Documentation/vm/transhuge.rst
>> +
>> +:翻译:
>> +
>> + 郭梦琪 Guo Mengqi <guomengqi3@huawei.com>
>> +
>> +:校译:
>> +
>> + 司延腾 Yanteng Si <siyanteng@loongson.cn>
>> + 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
>> + 时奎亮 Alex Shi <alexs@kernel.org>
>> +
>> +==============
>> +透明巨页机制
>> +==============
>> +
>> +本文档描述透明巨页(THP)的设计理念,以及它是如何与内存管理系统的其它部分交互的。 
>>
>> +
>> +设计原则
>> +========
>> +
>> +- 
>> “优雅回退”:有些mm组件不感知透明巨页,它们的回退方法是将PMD页表项拆分成PTE 
>>
>> +  
>> 页表项。必要时还需要拆分透明巨页。这样就可以在常规大小的页或页表项上继续工作。 
>>
>> +
>> +- 
>> 如果内存碎片化导致巨页分配失败,则分配常规页作为替代放入原vma中,此期间不会 
>>
>> +  产生任何失败或明显延迟,也不会引起用户态的注意。
>> +
>> +- 
>> 如果一些进程退出后释放了空闲的巨页(不论在伙伴系统还是在VM),由常规页支持的 
>>
>> +  guest物理内存应该自动重新申请为巨页。(通过khugepaged进程)
>> +
>> +- 
>> 透明巨页不需要预留内存,而是尽可能使用已经存在的巨页。(为避免不可移动的页 
>>
>> +  
>> 将整个内存碎片化,唯一可能的预留是在kernelcore=的设置中。不过这个调整并不仅 
>>
>> +  针对透明巨页,而对内核中所有动态的多级页面申请都适用。)
>> +
>> +get_user_pages和follow_page
>> +===========================
>> +
>> +不论对单个巨页还是hugetlbfs,使用get_user_pages(GUP)和follow_page时,返回的会是 
>>
>> +首页或尾页。大多数情况下调用GUP功能的人不关心页的大小,只关心页的真实物理地址 
>>
>> +以及暂时将页固定,好在I/O结束后将页释放。但在驱动中,在某些情况下有可能访问尾页 
>>
>> +的page_struct(如检查page->mapping字段),这时应该转而检查首页。一旦首页或者尾页 
>>
>> +被引用,巨页就不能再被拆分了。
>> +
>> +.. note::
>> +   以上不是针对GUP 
>> API的新增限制,它们和hugetlbfs的限制保持一致。因此,如果任何
>> +   
>> 驱动能够在hugetlbfs中处理GUP,它们也能在基于透明巨页的映射中很好的工作。
>> +
>> +优雅回退
>> +============
>> +
>> +遍历页表但又不需感知巨页pmd的代码可以这样简单处理:对pmd_offset返回的pmd添加一行 
>>
>> +split_huge_pmd(vma, pmd, addr)调用。只需grep搜索"pmd_offset",并将
>> +split_huge_pmd添加到所有返回的pmd后面,代码就能够自己处理透明巨页了,非常简单。 
>>
>> +这短短一行的回退函数很巧妙,为我们省去了成百上千行额外的适配代码。
>> +
>> +如果你不是在遍历页表,而是遇到了一个无法直接处理的巨物理页,可以使用
>> +split_huge_page(page)把它拆分成小页。linux 
>> VM就是通过这种方式将巨页换出。
>> +如果页面被pin住了,split_huge_page就会失败。
>> +
>> +例子:添加一行代码使mremap.c支持透明巨页::
>> +
>> +        diff --git a/mm/mremap.c b/mm/mremap.c
>> +        --- a/mm/mremap.c
>> +        +++ b/mm/mremap.c
>> +        @@ -41,6 +41,7 @@ static pmd_t *get_old_pmd(struct mm_stru
>> +                return NULL;
>> +
>> +                pmd = pmd_offset(pud, addr);
>> +        +       split_huge_pmd(vma, pmd, addr);
>> +                if (pmd_none_or_clear_bad(pmd))
>> +                    return NULL;
>> +
>> +巨页支持中的锁使用
>> +==================
>> +
>> +我们还是希望尽可能多的代码能感知透明巨页,因为调用split_huge_page()和
>> +split_huge_pmd()还是有开销的。
>> +
>> +要使遍历页表流程能够感知巨页pmd,只需对pmd_offset返回的pmd调用pmd_trans_huge()。 
>>
>> +一定要持有mmap_lock读锁,以避免khugepaged在此期间申请新的巨页pmd
>> +(khugepaged collapse_huge_page会持有mmap_lock写锁而非anon_vma lock)。
>> +如果pmd_trans_huge返回结果为假,那就回到原来的流程。如果pmd_trans_huge返回结果 
>>
>> +为真,就需要先持有页表锁(pmd_lock()),然后再进行一次pmd_trans_huge判断。持页表锁 
>>
>> +是为了防止巨页pmd被转换成小页(split_huge_pmd是可以跟遍历页表操作同时进行的)。 
>>
>> +如果第二次pmd_trans_huge返回结果为假,那就释放页表锁,依然回到原有流程。如果返回 
>>
>> +结果继续为真,那就按照巨页pmd和巨页来处理,处理完毕再释放页表锁。
>> +
>> +引用计数和透明巨页
>> +==================
>> +
>> +THP的计数跟其他复合页的计数大致相同:
>> +
>> + - get_page()/put_page()和GUP都在首页上进行计数(修改head 
>> page->_refcount)
>> +
>> + - 尾页的_refcount永远是0. get_page_unless_zero()永远无法get到尾页。
>> +
>> + - 映射/解映射特定PTE entry时,增减的是复合页中相应子页的_mapcount.
>> +
>> + - 
>> 映射/解映射整个复合页时,增减的是compound_mapcount属性。该属性保存在第一个 
>>
>> +   
>> 尾页中。对于文件中的巨页,还要增加所有子页中的_mapcount,这样是为了在检测 
>>
>> +   子页的解映射时不需考虑竞争问题。
>> +
>> +PageDoubleMap() 表明巨页 *可能* 被映射为了PTE.
>> +
>> +对匿名页,PageDoubleMap()也表示所有子页的_mapcount都偏移了1.
>> +在页被同时映射为了PMD和PTE的情况下,这个额外的引用可以避免子页解映射时的竞争。 
>>
>> +
>> +这个优化也可以追踪每个子页mapcount所带来的性能开销。另一种解决方法是在每次 
>>
>> +映射/解映射整个复合页时更改所有子页的_mapcount.
>> +
>> +对于匿名页,如果页面的PMD在首次被拆分时同时还具有PMD映射,则设置PG_double_map; 
>>
>> +当compound_mapcount值降为0时,取消设置。
>> +
>> +对于映射到文件的页,在其首次映射PTE时,设置PG_double_map; 
>> 在页面从页缓存中
>> +移除时,取消设置。
>> +
>> +split_huge_page中,在清除page 
>> struct中所有PG_head/tail位之前,需要先将首页中的
>> +引用计数refcount分发到所有其他尾页中。页表项PTE占用的引用计数很好处理,但剩下的 
>>
>> +引用计数来源难以确定(如通过get_user_pages的pin页)。如果巨页被pin住,
>> +split_huge_page()会失败。页的引用计数必须等于所有子页mapcount之和再加一(因为 
>>
>> +split_huge_page的调用者也必须对首页持有一个引用)。
>> +
>> +对匿名页,split_huge_page用页表项迁移(migration 
>> entries)来保持page->_refcount
>> +和page->_mapcount稳定。对文件页则会直接解映射。
>> +
>> +这套机制对物理内存扫描(physical memory 
>> scanners)也安全,scanner唯一合法引用页
>> +的途径就是get_page_unless_zero().
>> +
>> +没调atomic_add()时,所有尾页的_refcount都为0. 
>> 这时scanner无法获取尾页的引用。
>> +调了atomic_add()后,我们也不在乎页的_refcount是多少了。只要知道应该从首页的引用 
>>
>> +计数减去多少即可。
>> +
>> +对首页进行get_page_unless_zero()是可以成功的。此时引用计数的再分配非常明了: 
>>
>> +引用计数将会留在首页中。
>> +
>> +split_huge_pmd()对引用计数没有任何限制,在任何时候都可以拆分PMD,而且永远不会 
>>
>> +失败。
>> +
>> +局部解映射和deferred_split_huge_page()函数
>> +==========================================
>> +
>> +透明巨页通过munmap()或其他方式解映射时,并不会立即释放内存。在page_remove_rmap() 
>>
>> +中检查透明巨页的某个子页是否还在使用,并将透明巨页加入一个预备队列,当内存 
>>
>> +使用需求变大时,把透明巨页拆分,释放已经不用的子页。
>> +
>> +检测到局部解映射时,由于处在锁中,无法立即进行拆页。而且在很多情况下,如果透明 
>>
>> +巨页是跨VMA的, 那么会在exit(2)中进行局部解映射。这时拆页效果适得其反。
>> +
>> +deferred_split_huge_page函数就是用来进行上文所说的将页排队以预备后续的拆分。真正 
>>
>> +的拆页操作是通过内存压力导致的shrinker接口来触发的。
>
> .

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH -next v2] docs/zh_CN: add mm transhuge translation
  2022-07-20  2:12     ` guomengqi (A)
@ 2022-07-20 21:15       ` Jonathan Corbet
  0 siblings, 0 replies; 12+ messages in thread
From: Jonathan Corbet @ 2022-07-20 21:15 UTC (permalink / raw)
  To: guomengqi (A)
  Cc: xuqiang36, zhouguanghui1, Tang Yizhou, Alex Shi, YanTeng Si,
	Linux Doc Mailing List

"guomengqi (A)" <guomengqi3@huawei.com> writes:

> Hi Jon,
>
> Is this patch applied? Is there anything else to be done?

It is applied (now).  However, it took some work on my side.

This patch puts the file into .../zh_CN/mm/, but that directory doesn't
exist in docs-next - that is a change that is sitting in the -mm tree
and won't make it into docs-next until after the merge window.
Interestingly, "git am" somehow found vm/index.html and applied the
relevant change there, but transhuge.rst ended up in the wrong place.

It wouldn't be hard to move it over, but that would introduce another
conflict against -mm.  So the right thing to do, I think, is to hold it
until after the merge window.

In the future, *please* make your changes against docs-next if you're
going to send them to me.

Thanks,

jon

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2022-07-20 21:15 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-28 13:37 [PATCH -next] docs/zh_CN: add vm transhuge translation Guo Mengqi
2022-06-29  3:50 ` YanTeng Si
2022-06-30  2:11   ` Wu XiangCheng
2022-07-01  2:49     ` guomengqi (A)
2022-07-01  9:24       ` YanTeng Si
2022-07-01  3:28   ` guomengqi (A)
2022-06-29  6:37 ` Alex Shi
2022-07-05 14:11 ` [PATCH -next v2] docs/zh_CN: add mm " Guo Mengqi
2022-07-06  3:00   ` Alex Shi
2022-07-07  1:14   ` YanTeng Si
2022-07-20  2:12     ` guomengqi (A)
2022-07-20 21:15       ` Jonathan Corbet

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.