当前位置: 首页 > news >正文

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
http://www.jsqmd.com/news/616953/

相关文章:

  • 2026年口碑好的滚塑加工箱体/慈溪来样滚塑加工/浮标滚塑加工厂家真实测评 - 品牌宣传支持者
  • Android 隐藏桌面应用,指定应用显示;暗码输入显示所有应用,以及暗码方式触发
  • Node.js后端服务开发:调用cv_resnet101人脸检测API的实战教程
  • 【高并发金融支付调试核武器】:基于Xdebug+OpenTelemetry+自研TraceID链路追踪的实时支付流诊断方案(仅限持牌机构内部流出)
  • typora破解
  • Wan2.2-I2V-A14B Java面试热点:如何设计高并发视频生成任务系统?
  • 13.2软件架构风格
  • 端到端测试(E2E)的维护成本之困与破局
  • OpenClaw多账户管理:千问3.5-9B区分个人/工作模式
  • JMS, ActiveMQ 学习一则萄
  • RobotStudio 实战:3 步搞定活塞机械装置建模与运动仿真
  • 13.3补充-层次风格-SOA
  • 【零基础入门】本地LLM聊天机器人保姆级教程|Windows+Mac通用
  • sam3: RuntimeError: mat1 and mat2 must have the same dtype, but got BFloat16 and Float
  • 5分钟上手Qwen-Image-Edit-2511:免配置AI图像编辑神器实测
  • 龙芯k - 久久派开发环境搭建及内核升级(下)突
  • 面向 LLM 的程序设计 7:工具描述的工程化——name、description、parameters 怎么写才少误用
  • 医学大模型的体系化人工智能框架构建与应用
  • GLM-4.1V-9B-Base与Proteus联调:可视化电路仿真结果分析
  • AIGlasses_for_navigation 赋能 .NET 应用:Windows 平台下的智能监控系统开发
  • WSL2本地开发环境配置:在Windows上无缝调试忍者像素绘卷
  • ms-swift微调框架深度体验:支持Megatron并行技术,训练加速效果明显
  • CHORD-X模型在.NET技术栈中的集成应用:为C#项目添加智能报告功能
  • 13.4架构复用-DSSA-ABSD
  • Stable Diffusion写实神器Realistic Vision V5.1:零基础入门教程,手把手教你生成高清人像
  • BepInEx完整指南:5分钟掌握Unity游戏插件开发框架
  • 使用cv_unet_image-colorization处理VMware虚拟机中的历史图像
  • 忍者像素绘卷:天界画坊软件测试实战:API接口自动化测试与压测
  • vue3+element-plus 实现动态菜单和动态路由的渲染
  • 手把手教你用Face Analysis WebUI:上传图片秒得人脸分析报告