news 2026/5/8 8:55:16

mremap:用户态调用mremap后VMA的pgoff以及page会发生发生

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
mremap:用户态调用mremap后VMA的pgoff以及page会发生发生

结论

先说结论:

1、执行mremap后,如果新的addr之前被映射过,之前映射过的page会被释放掉,新的addr先unmap掉。重新把旧addr的page重新映射到新的addr

2、VMA 确实会发生变化:如果原来的一个连续 VMA地址 会被拆分成两个独立的 VMA,中间出现一段未映射的地址空隙。那么就会新建一个vma。

3、旧的page内容不会变,page->index(pgoff)也不会变。变的只有VMA的 vm_start和vm_pgoff.

4、反向映射时的地址计算公式永远成立:

用户态的虚拟地址 = vma->vm_start + (page->index - vma->vm_pgoff) * PAGE_SIZE

背景

我们知道mremap可以改变一个已申请内存区域的映射地址范围,例如原先申请的地址范围是A到A+len,我们可以改变为B到B+len2。可是,你知道这样改变后,VMA会发生什么变化吗?VMA可能会拆成新的VMA,但是page呢?page有可能不变,那这时反向映射RMAP是如何能通过page再次找到映射这个page的新VMA呢?这个问题来源一个ksm优化引发的讨论:https://lore.kernel.org/all/a14a89ba-e870-47d2-a903-564332da9877@kernel.org/

实验方法:

带着这个疑问咱们做一个实验:用户态调用mremap。在内核态的do_mremap函数中的入口和出口打印出VMA以及对应page的信息。

用户态编写这样一个C程序:

433 /* To test if ksm page can be migrated when it's mremapped */ 434 int merge_mremap_and_migrate(struct global_data *data) 435 { 436 int ret = 0; 437 /* Allocate range and set the same data */ 438 >diff --git a/include/linux/mm.h b/include/linux/mm.h index 13336340612e..818e0eb2bb2c 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -4200,6 +4200,10 @@ static inline vm_fault_t vmf_error(int err) return VM_FAULT_SIGBUS; } +struct page *follow_page_mask(struct vm_area_struct *vma, + unsigned long address, unsigned int foll_flags, + unsigned long *page_mask); + /* * Convert errno to return value for ->page_mkwrite() calls. * diff --git a/mm/gup.c b/mm/gup.c index 8e7dc2c6ee73..a0b13934c7be 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -1004,7 +1004,7 @@ static struct page *follow_p4d_mask(struct vm_area_struct *vma, * an error pointer if there is a mapping to something not represented * by a page descriptor (see also vm_normal_page()). */ -static struct page *follow_page_mask(struct vm_area_struct *vma, +struct page *follow_page_mask(struct vm_area_struct *vma, unsigned long address, unsigned int flags, unsigned long *page_mask) { diff --git a/mm/mremap.c b/mm/mremap.c index 2be876a70cc0..eacfd844b9ad 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -1912,6 +1912,27 @@ static unsigned long remap_move(struct vma_remap_struct *vrm) return res; } +static void print_vma_info(struct vm_area_struct *vma, unsigned long address, char *prefix) +{ + /* + * address: you want to lookup page, the address is the mremap()'s first + * argument. + */ + struct page *page; + unsigned long page_mask = 0; + + page = follow_page_mask(vma, address, FOLL_GET, &page_mask); + if (!page) { + pr_err("mremap you pass in an error address(no page) at %lx\n", address); + return; + } + + printk("%s vm_start:%lx vm_pgeff:%lx user's" + "given address: %lx page->index:%lx\n", prefix, vma->vm_start, vma->vm_pgoff, + address, folio_pgoff(page_folio(page))); + +} + static unsigned long do_mremap(struct vma_remap_struct *vrm) { struct mm_struct *mm = current->mm; @@ -1930,9 +1951,12 @@ static unsigned long do_mremap(struct vma_remap_struct *vrm) vrm->mmap_locked = true; if (vrm_move_only(vrm)) { + vrm->vma = vma_lookup(current->mm, vrm->addr); + print_vma_info(vrm->vma, vrm->addr, "Before meremap move_only"); res = remap_move(vrm); } else { vrm->vma = vma_lookup(current->mm, vrm->addr); + print_vma_info(vrm->vma, vrm->addr, "Before meremap "); res = check_prep_vma(vrm); if (res) goto out; @@ -1944,6 +1968,13 @@ static unsigned long do_mremap(struct vma_remap_struct *vrm) out: failed = IS_ERR_VALUE(res); + if (!failed) { + struct vm_area_struct *new_vma = vma_lookup(current->mm, vrm->new_addr); + print_vma_info(new_vma, vrm->new_addr, "After meremap new address"); + } else{ + pr_err("mremap failed\n"); + } + if (vrm->mmap_locked) mmap_write_unlock(mm);

实验结果:

【用户态打印】Before meremap region: 0x7f0f52e20000 【内核态】 [ 26.544965] Before meremap move_only vm_start:7f0f52e20000 vm_pgeff:7f0f52e20 user'sgiven address: 7f0f52e21000 page->index:7f0f52e21 【内核态】 [ 26.548166] After meremap new address vm_start:7f0f52e22000 vm_pgeff:7f0f52e21 user'sgiven address: 7f0f52e22000 page->index:7f0f52e21 【用户态】After meremap region: 0x7f0f52e22000
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/10 7:16:38

2026年合规敏感行业必看!新媒体矩阵安全高效运营,守住合规底线

在金融、医疗、教育等合规敏感行业,新媒体矩阵运营是品牌传播、用户触达的重要渠道,但同时也面临严苛的合规要求。这类行业的运营团队普遍深陷困境:内容合规把控难,敏感信息易疏漏;账号状态难监控,异常风险…

作者头像 李华
网站建设 2026/4/10 7:16:20

Wan2.2-I2V-A14B一文详解:从镜像拉取、环境验证到首条视频生成全流程

Wan2.2-I2V-A14B一文详解:从镜像拉取、环境验证到首条视频生成全流程 1. 镜像概述与核心特性 Wan2.2-I2V-A14B是一款专为文生视频任务优化的私有部署镜像,基于RTX 4090D 24GB显存显卡深度定制。这个镜像最大的特点是开箱即用,内置了完整的运…

作者头像 李华
网站建设 2026/4/10 7:16:18

域名中介交易流程:完整操作指南

域名中介交易的标准流程是:提交需求→域名评估→寻找交易对象→谈判价格→确认交易→资金与域名交割→完成过户。相比自行交易,中介流程更规范、成交率更高,尤其适用于高价值或复杂域名交易。一、什么是域名中介交易?域名中介交易…

作者头像 李华
网站建设 2026/4/10 7:15:22

2026年中国API安全产品综合排名:AI驱动、可溯源、权威成为选型关键

一、市场背景:API安全成为数字时代必答题提示:随着API经济的爆发,API安全已从附加功能转变为数字业务的核心防线。在数字化转型浪潮中,应用程序编程接口(API)已成为连接业务系统、驱动数据流通的核心通道。…

作者头像 李华
网站建设 2026/4/10 7:15:17

华轩阳电子:用务实的创新,点亮“中国芯”的征途

2016年,深圳。 这座以效率和创新闻名的城市,见证了一个朴素而坚定的梦想诞生。彼时,赖柱光先生看到,在功率器件这一关键领域,从消费电器到工业设备,从通信基站到新能源汽车,核心元器件几乎被欧美…

作者头像 李华