您好、欢迎来到现金彩票网!
当前位置:一品彩票app下载 > 共享页表 >

从 Linux 内核访问用户空间内存

发布时间:2019-06-07 02:58 来源:未知 编辑:admin

  developerWorks 中国 正在向 IBM Developer 过渡。 我们将为您呈现一个全新的界面和更新的主题领域,并一如既往地提供您希望获得的精彩内容。

  在 Linux 中,用户内存和内核内存是独立的,在各自的地址空间实现。地址空间是虚拟的,就是说地址是从物理内存中抽象出来的(通过一个简短描述的过程)。由于地址空间是虚拟的,所以可以存在很多。事实上,内核本身驻留在一个地址空间中,每个进程驻留在自己的地址空间。这些地址空间由虚拟内存地址组成,允许一些带有独立地址空间的进程指向一个相对较小的物理地址空间(在机器的物理内存中)。不仅仅是方便,而且更安全。因为每个地址空间是独立且隔离的,因此很安全。

  但是与安全性相关联的成本很高。因为每个进程(和内核)会有相同地址指向不同的物理内存区域,不可能立即共享内存。幸运的是,有一些解决方案。用户进程可以通过 Portable Operating System Interface for UNIX (POSIX) 共享的内存机制(shmem)共享内存,但有一点要说明,每个进程可能有一个指向相同物理内存区域的不同虚拟地址。

  虚拟内存到物理内存的映射通过页表完成,这是在底层软件中实现的(见图 1)。硬件本身提供映射,但是内核管理表及其配置。注意这里的显示,进程可能有一个大的地址空间,但是很少见,就是说小的地址空间的区域(页面)通过页表指向物理内存。这允许进程仅为随时需要的网页指定大的地址空间。

  由于缺乏为进程定义内存的能力,底层物理内存被过度使用。通过一个称为paging(然而,在 Linux 中通常称为swap)的进程,很少使用的页面将自动移到一个速度较慢的存储设备(比如磁盘),来容纳需要被访问的其它页面(见图 2 )。这一行为允许,在将很少使用的页面迁移到磁盘来提高物理内存使用的同时,计算机中的物理内存为应用程序更容易需要的页面提供服务。注意,一些页面可以指向文件,在这种情况下,如果页面是脏(dirty)的,数据将被冲洗,如果页面是干净的 (clean),直接丢掉。

  不是所有的处理器都有 MMU。因此,uClinux 发行版(微控制器 Linux)支持操作的一个地址空间。该架构缺乏 MMU 提供的保护,但是允许 Linux 运行另一类处理器。关于 uClinux 的详细信息见参考资料。

  选择一个页面来交换存储的过程被称为一个页面置换算法,可以通过使用许多算法(至少是最近使用的)来实现。该进程在请求存储位置时发生,存储位置的页面不在存储器中(在存储器管理单元 [MMU] 中无映射)。这个事件被称为一个页面错误并被硬件(MMU)删除,出现页面错误中断后该事件由防火墙管理。该栈的详细说明见图 3。

  Linux 提供一个有趣的交换实现,该实现提供许多有用的特性。Linux 交换系统允许创建和使用多个交换分区和优先权,这支持存储设备上的交换层次结构,这些存储设备提供不同的性能参数(例如,固态磁盘 [SSD] 上的一级交换和速度较慢的存储设备上的较大的二级交换)。为 SSD 交换附加一个更高的优先级使其可以使用直至耗尽;直到那时,页面才能被写入优先级较低的交换分区。

  并不是所有的页面都适合交换。考虑到响应中断的内核代码或者管理页表和交换逻辑的代码,显然,这些页面决不能被换出,因此它们是固定的,或者是永久地驻留在内存中。尽管内核页面不需要进行交换,然而用户页面需要,但是它们可以被固定,通过mlock(或mlockall)函数来锁定页面。这就是用户空间内存访问函数的目的。如果内核假设一个用户传递的地址是有效的且是可访问的,最终可能会出现内核严重错误(kernel panic)(例如,因为用户页面被换出,而导致内核中的页面错误)。该应用程序编程接口(API)确保这些边界情况被妥善处理。

  现在,让我们来研究一下用户操作用户内存的内核 API。请注意,这涉及内核和用户空间接口,而下一部分将研究其他的一些内存 API。用户空间内存访问函数在表 1 中列出。

  当数据移动函数的规则涉及到复制调用的类型时(简单 VS. 聚集),这些函数的作用如图 4 所示。

  您可以使用access_ok函数在您想要访问的用户空间检查指针的有效性。调用函数提供指向数据块的开始的指针、块大小和访问类型(无论这个区域是用来读还是写的)。函数原型定义如下:

  type参数可以被指定为VERIFY_READ或VERIFY_WRITE。VERIFY_WRITE也可以识别内存区域是否可读以及可写(尽管访问仍然会生成-EFAULT)。该函数简单检查地址可能是在用户空间,而不是内核。

  要从用户空间读取一个简单变量,可以使用get_user函数,该函数适用于简单数据类型,比如,char和int,但是像结构体这类较大的数据类型,必须使用copy_from_user函数。该原型接受一个变量(存储数据)和一个用户空间地址来进行 Read 操作:

  get_user函数将映射到两个内部函数其中的一个。在系统内部,这个函数决定被访问变量的大小(根据提供的变量存储结果)并通过__get_user_x形成一个内部调用。成功时该函数返回 0,一般情况下,get_user和put_user函数比它们的块复制副本 要快一些,如果是小类型被移动的话,应该用它们。

  您可以使用put_user函数来将一个简单变量从内核写入用户空间。和get_user一样,它接受一个变量(包含要写的值)和一个用户空间地址作为写目标:

  clear_user函数被用于将用户空间的内存块清零。该函数采用一个指针(用户空间中)和一个型号进行清零,这是以字节定义的:

  在内部,clear_user函数首先检查用户空间指针是否可写(通过access_ok),然后调用内部函数(通过内联组装方式编码)来执行 Clear 操作。使用带有 repeat 前缀的字符串指令将该函数优化成一个非常紧密的循环。它将返回不可清除的字节数,如果操作成功,则返回 0。

  copy_to_user函数将数据块从内核复制到用户空间。该函数接受一个指向用户空间缓冲区的指针、一个指向内存缓冲区的指针、以及一个以字节定义的长度。该函数在成功时,返回 0,否则返回一个非零数,指出不能发送的字节数。

  检查了向用户缓冲区写入的功能之后(通过access_ok),内部函数__copy_to_user被调用,它反过来调用__copy_from_user_inatomic(在 ./linux/arch/x86/include/asm/uaccess_XX.h 中。其中XX是 32 或者 64 ,具体取决于架构。)在确定了是否执行 1、2 或 4 字节复制之后,该函数调用__copy_to_user_ll,这就是实际工作进行的地方。在损坏的硬件中(在 i486 之前,WP 位在管理模式下不可用),页表可以随时替换,需要将想要的页面固定到内存,使它们在处理时不被换出。i486 之后,该过程只不过是一个优化的副本。

  copy_from_user函数将数据块从用户空间复制到内核缓冲区。它接受一个目的缓冲区(在内核空间)、一个源缓冲区(从用户空间)和一个以字节定义的长度。和copy_to_user一样,该函数在成功时,返回 0 ,否则返回一个非零数,指出不能复制的字节数。

  该函数首先检查从用户空间源缓冲区读取的能力(通过access_ok),然后调用__copy_from_user,最后调用__copy_from_user_ll。从此开始,根据构架,为执行从用户缓冲区到内核缓冲区的零拷贝(不可用字节)而进行一个调用。优化组装函数包含管理功能。

  strnlen_user函数也能像strnlen那样使用,但前提是缓冲区在用户空间可用。strnlen_user函数带有两个参数:用户空间缓冲区地址和要检查的最大长度。

  strncpy_from_user函数将一个字符串从用户空间复制到一个内核缓冲区,给定一个用户空间源地址和最大长度。

  上面部分探讨了在内核和用户空间之间移动数据的方法(使用内核初始化操作)。Linux 还提供一些其他的方法,用于在内核和用户空间中移动数据。尽管这些方法未必能够提供与用户空间内存访问函数相同的功能,但是它们在地址空间之间映射内存的功能是相似的。

  在用户空间,注意,由于用户进程出现在单独的地址空间,在它们之间移动数据必须经过某种进程间通信机制。Linux 提供各种模式(比如,消息队列),但是最著名的是 POSIX 共享内存(shmem)。该机制允许进程创建一个内存区域,然后同一个或多个进程共享该区域。注意,每个进程可能在其各自的地址空间中映射共享内存区域到不同地址。因此需要相对的寻址偏移(offset addressing)。

  mmap函数允许一个用户空间应用程序在虚拟地址空间中创建一个映射,该功能在某个设备驱动程序类中是常见的,允许将物理设备内存映射到进程的虚拟地址空间。在一个驱动程序中,mmap函数通过remap_pfn_range内核函数实现,它提供设备内存到用户地址空间的线性映射。

  本文讨论了 Linux 中的内存管理主题,然后讨论了使用这些概念的用户空间内存访问函数。在用户空间和内核空间之间移动数据并没有表面上看起来那么简单,但是 Linux 包含一个简单的 API 集合,跨平台为您管理这个复杂的任务。

  Red Hats Linux System Administration Primer提供一个很好的虚拟内存总结。

  关于 Linux 交换空间的一切讨论了交换的目的、交换驻留的地方、以及用于管理交换空间的各种命令。

  为了提高缓存性能,制定了一个压缩缓存模式。在这个模式中,交换磁盘事实上是一个快速内存磁盘,页面根据词条进行压缩来提高存储效率。

  Linux 内存管理的一个最好的来源是设备驱动程序宝典:Linux Device Drivers,第 3 版。

  内核和用户空间页面 的一个不同是,内核在内存中是永久的,而用户空间页面可以被换出到一个存储设备。通过使用

  并不是所有的处理器都有一个 MMU。Linux 通过 uClinux 发行版来支持这些构架。uClinux是一个关注这些没有 MMU 的架构的项目,比如微控制器。

  关于内存管理主题,维基百科提供了很多有用的资源,其中包括虚拟内存、分页、页表、以及页面置换算法。

  在developerWorks Linux 专区寻找为 Linux 开发人员(包括Linux 新手入门)准备的更多参考资料,查阅我们最受欢迎的文章和教程。

  在 developerWorks 上查阅所有Linux 技巧和Linux 教程。

  以最适合您的方式IBM 产品评估试用版软件:下载产品试用版,在线试用产品,在云环境下试用产品,或者在IBM SOA Sandbox for People中花费几个小时来学习如何高效实现面向服务架构。

  在 Twitter 上关注 developerWorks,或者订阅Linux tweets on developerWorks的提要。

http://styleinch.com/gongxiangyebiao/362.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有