mm: rework anon_vma and remove anon_vma_chain
| From: | tao <tao.wangtao-AT-honor.com> | |
| To: | <akpm-AT-linux-foundation.org>, <david-AT-kernel.org>, <catalin.marinas-AT-arm.com>, <will-AT-kernel.org>, <tglx-AT-kernel.org>, <mingo-AT-redhat.com>, <bp-AT-alien8.de>, <dave.hansen-AT-linux.intel.com>, <x86-AT-kernel.org>, <willy-AT-infradead.org>, <sj-AT-kernel.org>, <kees-AT-kernel.org>, <luizcap-AT-redhat.com>, <zhangjiao2-AT-cmss.chinamobile.com>, <kas-AT-kernel.org>, <ljs-AT-kernel.org> | |
| Subject: | [RFC PATCH v2 00/13] mm: rework anon_vma and remove anon_vma_chain | |
| Date: | Tue, 07 Jul 2026 14:32:55 +0800 | |
| Message-ID: | <20260707063308.29176-1-tao.wangtao@honor.com> | |
| Cc: | <hpa-AT-zytor.com>, <liam-AT-infradead.org>, <vbabka-AT-kernel.org>, <rppt-AT-kernel.org>, <surenb-AT-google.com>, <mhocko-AT-suse.com>, <jack-AT-suse.cz>, <riel-AT-surriel.com>, <harry-AT-kernel.org>, <jannh-AT-google.com>, <jgg-AT-ziepe.ca>, <jhubbard-AT-nvidia.com>, <peterx-AT-redhat.com>, <ziy-AT-nvidia.com>, <baolin.wang-AT-linux.alibaba.com>, <npache-AT-redhat.com>, <ryan.roberts-AT-arm.com>, <dev.jain-AT-arm.com>, <baohua-AT-kernel.org>, <lance.yang-AT-linux.dev>, <xu.xin16-AT-zte.com.cn>, <chengming.zhou-AT-linux.dev>, <muchun.song-AT-linux.dev>, <baoquan.he-AT-linux.dev>, <nao.horiguchi-AT-gmail.com>, <matthew.brost-AT-intel.com>, <joshua.hahnjy-AT-gmail.com>, <rakie.kim-AT-sk.com>, <byungchul-AT-sk.com>, <gourry-AT-gourry.net>, <ying.huang-AT-linux.alibaba.com>, <apopple-AT-nvidia.com>, <pfalcato-AT-suse.de>, <linux-arm-kernel-AT-lists.infradead.org>, <linux-kernel-AT-vger.kernel.org>, <linux-fsdevel-AT-vger.kernel.org>, <linux-mm-AT-kvack.org>, <damon-AT-lists.linux.dev>, <shakeel.butt-AT-linux.dev>, <ryncsn-AT-gmail.com>, <jparsana-AT-google.com>, <dvander-AT-google.com>, <zhangji1-AT-honor.com>, <wangzicheng-AT-honor.com>, tao <tao.wangtao-AT-honor.com> | |
| Archive-link: | Article |
Hi all,
Since v1 was relatively complex and difficult to extend, this version
adopts a simpler anon_vma implementation approach.
Replace the original anon_vma + anon_vma_chain multiple rbtree
structures with a depth-aware doubly linked list, and remove anon_vma_chain.
During rmap walks, vma_rmap_base(vma) is used to compute the page
address and look up the corresponding VMA from mm_mt:
vma_rmap_base(vma) = vma->vm_start - vma->vm_pgoff * PAGE_SIZE
page_address(vma, pgoff)
= vma->vm_start + (pgoff - vma->vm_pgoff) * PAGE_SIZE
= vma->vm_start - vma->vm_pgoff * PAGE_SIZE + pgoff * PAGE_SIZE
= vma_rmap_base(vma) + pgoff * PAGE_SIZE
Since vma_rmap_base(vma) remains invariant across VMA merge and split
operations, VMA updates only need to adjust the VMA count of the
corresponding anon_vma. The anon_vma no longer directly tracks VMAs,
which eliminates the need for anon_vma_chain.
Process fork behaves like a fractal expansion of both tasks and
anon_vmas. A dedicated fractal_list records forked anon_vmas, while
descendant anon_vmas are derived from fork depth during rmap walks.
For this reason, the new design is named ANON_VMA_FRACTAL.
The depth is initialized to 0.
When a child is added, the root depth is set to 1.
A remap child has a depth of parent->depth + 1,
while a fork child has a depth of parent->depth + 2.
For example:
1) A forks B and C:
(1A)
/ \
(3B)---(3C)
2) B remaps D:
(1A)
/ \
(3B) (3C)
/ /
(4D)-----o
3) B forks E and F:
(1A)--o
/ \
(3B) (3C)
/ /
(4D) /
/ /
(5E)------(5F)
4) C forks G:
(1A)------------o
/ \
(3B) (3C) o
/ / \ /
(4D) / \ /
/ / \ /
(5E)------(5F) (5G)
Only the root node A needs to traverse all descendants; non-root nodes
only traverse their own descendant nodes. For example:
- When rmap-ing A: first process A, then traverse all descendants
B/D/E/F/C/G. A does not need to be traversed again.
- When rmap-ing B: first process B, then traverse its descendants
D/E/F. Since C->depth <= B->depth, the rmap walk terminates at C.
The fractal_list remains stable across VMA merge and split operations.
It is updated only when anon_vmas are forked, remapped, or unlinked, and
is traversed during rmap walks.
On an Android device after boot, memory usage of vm_area_struct,
anon_vma, and anon_vma_chain is reduced by about 35 MB.
struct base(KB) patch(KB) patch_struct saved(KB)
--------------------------------------------------------------------
vm_area_struct 110760 103837 vm_area_struct 6887
anon_vma 19152 8576 anon_node 10576
anon_vma_chain 17560 0 NA 17560
NA 0 346 anon_semaphore -346
lat_proc shows fork performance improves by about 15% at P=10.
Changes since v1:
- anon_vma now stores mm and rmap_base for VMA lookup, and only tracks
the number of associated VMAs instead of directly tracking VMAs
- Use fractal_list + depth to maintain anon_vma topology and remove
anon_vma_chain completely
- Keep folio->mapping storing anon_vma
- Preserve existing APIs and external callers unchanged while
introducing ANON_RMAP_FOREACH_VMA() to unify anonymous rmap traversal
- Use vm_refcnt on leaf VMAs for rmap protection
- Optimize rwsem memory usage with shared semaphores
Patch layout:
1-2: add CONFIG_ANON_VMA_FRACTAL and basic helpers
3-7: implement anon_vma fractal infrastructure
8: implement anonymous folio rmap
9-10: replace anon_vma with anon_node
11: use vm_refcnt on leaf VMAs for rmap protection
12: optimize anon_vma memory usage with shared semaphores
v1:
https://lore.kernel.org/all/20260527110147.17815-1-tao.wa...
tao (13):
mm: add CONFIG_ANON_VMA_FRACTAL
mm: implement helpers for ANON_VMA_FRACTAL
mm: implement __anon_node_prepare for ANON_VMA_FRACTAL
mm: implement anon_node_clone for ANON_VMA_FRACTAL
mm: implement anon_node_fork_with_prev for ANON_VMA_FRACTAL
mm: implement unlink_anon_nodes for ANON_VMA_FRACTAL
mm: handle rmap_base changes for ANON_VMA_FRACTAL
mm: implement anonymous folio rmap for ANON_VMA_FRACTAL
mm: prepare anon_node replacement for ANON_VMA_FRACTAL
mm: replace anon_vma with anon_node for ANON_VMA_FRACTAL
mm: optimize rmap for ANON_VMA_FRACTAL with PVL
mm: shared semaphores for ANON_VMA_FRACTAL
mm: Enable CONFIG_ANON_VMA_FRACTAL by default
include/linux/mm.h | 2 +
include/linux/mm_types.h | 2 +
include/linux/rmap.h | 56 ++++
include/linux/rwsem.h | 10 +
mm/Kconfig | 37 +++
mm/internal.h | 205 ++++++++++++
mm/ksm.c | 19 +-
mm/memory-failure.c | 8 +-
mm/mmap.c | 7 +-
mm/rmap.c | 686 +++++++++++++++++++++++++++++++++++++--
mm/vma.c | 76 ++++-
mm/vma_init.c | 2 +
12 files changed, 1056 insertions(+), 54 deletions(-)
--
2.17.1
