最近工作中经常遇见get_user_pages和get_user_pages_fast,虽然知道他们都是用来pin住一个页的,但是依然没搞明白后者是如何实现fast的,两者的区别具体在哪。刚好利用周末时间研究一下。本文的分析基于linux 4.19.195.
先看看get_user_pages_fast函数的定义

/*** get_user_pages_fast() - pin user pages in memory* @start:  starting user address* @nr_pages:  number of pages from start to pin* @write: whether pages will be written to* @pages:  array that receives pointers to the pages pinned.*      Should be at least nr_pages long.** Attempt to pin user pages in memory without taking mm->mmap_sem.   尝试不获取锁就pin memory* If not successful, it will fall back to taking the lock and* calling get_user_pages().** Returns number of pages pinned. This may be fewer than the number* requested. If nr_pages is 0 or negative, returns 0. If no pages* were pinned, returns -errno.*/
int get_user_pages_fast(unsigned long start, int nr_pages, int write,struct page **pages)

get_user_pages的定义

/** This is the same as get_user_pages_remote(), just with a* less-flexible calling convention where we assume that the task* and mm being operated on are the current task's and don't allow* passing of a locked parameter.  We also obviously don't pass* FOLL_REMOTE in here.*/
long get_user_pages(unsigned long start, unsigned long nr_pages,unsigned int gup_flags, struct page **pages,struct vm_area_struct **vmas)
{return __get_user_pages_locked(current, current->mm, start, nr_pages,pages, vmas, NULL,gup_flags | FOLL_TOUCH);
}
EXPORT_SYMBOL(get_user_pages);static __always_inline long __get_user_pages_locked(struct task_struct *tsk,struct mm_struct *mm,unsigned long start,unsigned long nr_pages,struct page **pages,struct vm_area_struct **vmas,int *locked,unsigned int flags)

可以看到,get_user_pages_fast函数的传参更少,get_user_pages函数只是__get_user_pages_locked函数的一个封装,而且参数也多了一些。先分析get_user_pages_fast函数。

int get_user_pages_fast(unsigned long start, int nr_pages, int write,struct page **pages)
{***/** The FAST_GUP case requires FOLL_WRITE even for pure reads,* because get_user_pages() may need to cause an early COW in* order to avoid confusing the normal COW routines. So only* targets that are already writable are safe to do by just* looking at the page tables.*/if (gup_fast_permitted(start, nr_pages, write)) {local_irq_disable();gup_pgd_range(addr, end, 1, pages, &nr);local_irq_enable();ret = nr;}if (nr < nr_pages) { //如果gup_pgd_rang没有获取到足够多的page数量,重来;原因可关注gup_pte_range函数,里面有对pte_value的并发判断/* Try to get the remaining pages with get_user_pages */start += nr << PAGE_SHIFT;pages += nr;ret = get_user_pages_unlocked(start, nr_pages - nr, pages,write ? FOLL_WRITE : 0); //最终调用__get_user_pages_locked完成/* Have to be a bit careful with return values */if (nr > 0) {if (ret < 0)ret = nr;elseret += nr;}}return ret;
}

可以看到,get_user_pages_fast函数先调用了gup_pgd_range,这个函数就是gup的快速路径,如果这个函数失败了,会走慢速路径,也就是get_user_pages_unlocked,并最终调用到了__get_user_pages_locked。那么,快速路径是在什么情况下能够快的呢?
走进gup_pgd_range函数的实现里,我们能够看到,gup_pgd_range就是在关中断的情况下(这样在多核的情况下无法做到并发安全),遍历一下页表,这个函数展开太长了就不贴了。拿简单的pin一个4k页举例,如果每一级页表都做了映射,且相关页都被分配了的话,最终会走入到函数gup_pte_range中,增加了相关的page引用计数后,便将页记录在pages数组里,计数加一,便可退出了。
可见,fast路径是简历在页表以及实际物理页都被分配了的基础上,方可成功执行。
但凡其中一个页的页表或者物理页没有分配好,就会走到慢速路径。
我们可以看到,慢速路径就和get_user_pages基本一样了(几个传参的区别请忽略,因为并不影响函数实现的本质),除了get_user_pages需要调用者自己在函数外拿一下mm->mmap_sem的读锁。
我们看看__get_user_pages_locked的原理,一个无限循环调用__get_user_pages函数,直到所有要求的页都被pin住或者错误发生。那__get_user_pages函数和上述快速路径有什么区别呢?
本质上,两者都是通过查询页表找到的page结构体,但是若是页表或者物理页尚未创建成功,那么,__get_user_pages会通过faultin_page模拟一个缺页中断,完成相关物理页及页表建立,这个流程是快速路径没有做的。
可能还有些细节上的差异,因为没有实际问题的触发,就没有深入研究下去了。
总结一下,大体上,get_user_pages和get_user_pages_fast,都是通过查询页表实现pin page的效果;两者的区别是,get_user_pages_fast只能pin住页表和物理页都建立好的page,而get_user_pages在相关页表或物理页尚未建立的情况下,能够主动的去创建,然后再执行pin的动作。
指的一提的是,get_user_pages_fast的快速路径是通过try_get_compound_head函数增加相关page结构体的引用计数的,而get_user_pages是通过FOLL_TOUCH这个标志位来给相关page结构体做引用计数的加一操作。也就是说,通过适当的传参,gup函数并不一定能pin住页,pin住页只是他的其中一项功能罢了。

get_user_pages和get_user_pages_fast的区别相关推荐

  1. AMD GPU内存管理(1):概览

    参考内核版本:Linux-6.1.8 HMM 待更新...... dumb buffer create/map 在AMDGPU的Graphics业务中,用到了GEM(Graphics Executio ...

  2. RPC 笔记(01)— RPC概念、调用流程、RPC 与 Restful API 区别

    1. 基本概念 PRC 远程过程调用 Remote Procedure Call,其就是一个节点请求另外一个节点提供的服务.当两个物理分离的子系统需要建立逻辑上的关联时,RPC 是牵线搭桥的常见技术手 ...

  3. C++ 笔记(28)— C++ 中 NULL和 nullptr 的区别

    最近看公司代码的时候发现在判断指针是否为空的时候,有的时候用的是 NULL, 有的时候用的是 nullptr 感觉很奇怪,好奇心驱使我查了下两者的区别,发现还是有很多细节需要学习的. 1. NULL ...

  4. gcc 和 g++ 的联系和区别,使用 gcc 编译 c++

    GCC 编译器已经为我们提供了调用它的接口,对于 C 语言或者 C++ 程序,可以通过执行 gcc 或者 g++ 指令来调用 GCC 编译器. 实际使用中我们更习惯使用 gcc 指令编译 C 语言程序 ...

  5. Python2 与 Python3 区别

    Python2.x 与 Python3.x 区别 1. print 函数 Python2 中 print 是语句(statement),Python3 中 print 则变成了函数.在 Python3 ...

  6. Docker 入门系列(1)- 初识容器,镜像、容器、仓库的区别

    Docker 简介 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发 ...

  7. HTTP 协议入门 — (TCP/IP协议族、通信传输流、URI 与 URL 的区别、Cookie 状态管理、HTTP 支持的方法、状态码类别、HTTP 首部字段)

    TCP/IP协议族 在介绍 HTTP 协议之前,我们先对 TCP/IP 协议族有个大概的了解,TCP/IP 协议从上到下主要分为应用层.传输层.网络层和数据链路层,各层的主要功能如下表所示: 协议层 ...

  8. python二进制打开(rb)和文本格式打开(r)什么区别?

    使用 open() 函数以文本格式打开文件和以二进制格式打开文件,唯一的区别是对文件中换行符的处理不同. 在 Windows 系统中,文件中用 "\r\n" 作为行末标识符(即换行 ...

  9. python中__dict__与dir()区别

    前言 Python下一切皆对象,每个对象都有多个属性(attribute),Python对属性有一套统一的管理方案. __dict__与dir()的区别: dir()是一个函数,返回的是list: _ ...

最新文章

  1. ubuntu 安装mysql ,postgresql (转)
  2. 微服务网关 Kong 科普
  3. Redhat 打开防火墙某个端口
  4. Oracle:时间字段模糊查询
  5. ImportError: cannot import name ‘joblib‘
  6. 哈佛大学教授:排名前5%学生的秘诀就3个字,这比勤奋更重要!
  7. 如何给新固态硬盘安装系统
  8. charles windows版使用教程
  9. 【SSM分布式架构电商项目-14】后台CMS内容管理系统管理前台首页广告
  10. matlab使用xlsread报错,matlab的IO操作复习
  11. php青蛙跳井代码,初八葬一青蛙跳井怪穴------行龙点劲!
  12. 常用谷歌地址和常用搜索引擎
  13. RVDS-RealView Development Suite 4 0 Professional软件
  14. 国产内存真的来了:紫光可提供DDR3、DDR4内存芯片
  15. html学习笔记,好好学习,天天向上
  16. 「镁客早报」特斯拉标准版Model3正式上市,售价3.5万美元;百度被爆搜索小学和幼儿园会导向色情网站...
  17. Linux下使用GPIO模拟I2C IIC驱动(PCF8563)
  18. GALAXY S8+ SM-G955N 韩版改G955F双卡多国系统G955NKSU3CRI3 dual sim card
  19. PS讲堂 画框 与 透明 矩形
  20. 计算机应用基础模拟试卷十二,计算机应用基础试卷十二

热门文章

  1. mp3格式怎么转换?这3种方法轻松帮你搞定!
  2. Kafka,Dubbed,ZooKeeper,GIT直白解释
  3. 解决引用MICROSOFT.OFFICE.CORE
  4. 米奇诺娃,让我读到了历史的真相。
  5. Android N 多窗口分析之freeform流程分析一(界面功能介绍)
  6. 论文阅读笔记---Recent development in CNC machining of freeform surfaces: A state-of-the-art review
  7. 进水的MP3播放器修理记
  8. php mq死信队列,【RabbitMQ 实战指南】一 死信队列
  9. Ansible自动化剧本
  10. React入门实战——腾讯掌上道聚城主页组件开发