Linux的高效的数据传输技术-Relay[1]

Relay 是一种从 Linux 内核到用户空间的高效数据传输技术通过用户定义的 relay 通道内核空间的程序能够高效可靠便捷地将数据传输到用户空间Relay 特别适用于内核空间有大量数据需要传输到用户空间的情形目前已经广泛应用在内核调试工具如 SystemTap中   本文介绍了 Relay 的历史和原理并且用一个简单的实例介绍了 Relay 的具体用法

  Relay 要解决的问题

  对于任何在内核工作的程序而言如何把大量的调试信息从内核空间传输到用户空间都是一个大麻烦对于运行中的内核更是如此特别是对于哪些用于调试内核性能的工具更是如此

  对于这种大量数据需要在内核中缓存并传输到用户空间需求很多传统的方法都已到达了极限例如内核程序员很熟悉的 printk() 调用此外如果不同的内核子系统都开发自己的缓存和传输代码造成很大的代码冗余而且也带来维护上的困难

  这些都要求开发一套能够高效可靠地将数据从内核空间转发到用户空间的系统而且这个系统应该独立于各个调试子系统这样就诞生了 RelayFS

  Relay的发展历史

  Relay 的前身是 RelayFS即作为 Linux 的一个新型文件系统年月RelayFS的第一个版本的代码被开发出来在月日第一个针对内核的版本也开始提供下载经过广泛的试用和改进直到年月RelayFS才被加入mainline内核()同时RelayFS也被移植到内核中在 年月从开始RelayFS不再作为单独的文件系统存在而是成为内核的一部分它的源码也从fs/目录下转移到 kernel/relayc中名称中也从RelayFS改成了Relay

  RelayFS目前已经被越来越多的内核工具使用包括内核调试工具SystemTapLTT以及一些特殊的文件系统例如DebugFS

  Relay的基本原理

  总的说来Relay提供了一种机制使得内核空间的程序能够通过用户定义的relay通道(channel)将大量数据高效的传输到用户空间

  一个relay通道由一组和CPU一一对应的内核缓冲区组成这些缓冲区又被称为relay缓冲区(buffer)其中的每一个在用户空间都用一个常规文件来表示这被叫做relay文件(file)内核空间的用户可以利用relay提供的API接口来写入数据这些数据会被自动的写入当前的 CPU id对应的那个relay缓冲区同时这些缓冲区从用户空间看来是一组普通文件可以直接使用read()进行读取也可以使用mmap()进行映射Relay并不关心数据的格式和内容这些完全依赖于使用relay的用户程序Relay的目的是提供一个足够简单的接口从而使得基本操作尽可能的高效

  Relay将数据的读和写分离使得突发性大量数据写入的时候不需要受限于用户空间相对较慢的读取速度从而大大提高了效率Relay作为写入和读取的桥梁也就是将内核用户写入的数据缓存并转发给用户空间的程序这种转发机制也正是Relay这个名称的由来

  这里的relay通道由四个relay缓冲区(kbuf到kbuf)组成分别对应于系统中的cpu到cpu每个CPU上的代码调用relay_write()的时候将数据写入自己对应的relay缓冲区内每个relay缓冲区称一个relay文件即/cpu到 /cpu当文件系统被mount到/mnt/以后这个relay文件就被映射成映射到用户空间的地址空间一旦数据可用用户程序就可以把它的数据读出来写入到硬盘上的文件中即cpuout到cpuout

  Relay的主要API

  前面提到的 relay_write() 就是 relay API 之一除此以外Relay 还提供了更多的 API来支持用户程序完整的使用 relay这些 API主要按照面向用户空间和面向内核空间分为两大类下面我们来分别进行介绍

  面向用户空间的 API

  这些 Relay 编程接口向用户空间程序提供了访问 relay 通道缓冲区数据的基本操作的入口包括

  ●open() 允许用户打开一个已经存在的通道缓冲区

  ●mmap() 使通道缓冲区被映射到位于用户空间的调用者的地址空间要特别注意的是我们不能仅对局部区域进行映射也就是说必须映射整个缓冲区文件其大小是 CPU的个数和单个 CPU 缓冲区大小的乘积

  ●read() 读取通道缓冲区的内容这些数据一旦被读出就意味着他们被用户空间的程序消费掉了也就不能被之后的读操作看到

  ●sendfile() 将数据从通道缓冲区传输到一个输出文件描述符其中可能的填充字符会被自动去掉不会被用户看到

  ●poll() 支持 POLLIN/POLLRDNORM/POLLERR 信号每次子缓冲区的边界被越过时等待着的用户空间程序会得到通知

  ●close() 将通道缓冲区的引用数减当引用数减为时表明没有进程或者内核用户需要打开它从而这个通道缓冲区被释放 面向内核空间的 API   这些API接口向位于内核空间的用户提供了管理relay通道数据写入等功能下面介绍其中主要的部分完整的API接口列表请参见这里

  ●relay_open() 创建一个relay通道包括创建每个CPU对应的relay缓冲区

  ●relay_close() 关闭一个relay通道包括释放所有的relay缓冲区在此之前会调用relay_switch()来处理这些relay缓冲区以保证已读取但是未满的数据不会丢失

  ●relay_write() 将数据写入到当前CPU对应的relay缓冲区内由于它使用了local_irqsave()保护因此也可以在中断上下文中使用

  ●relay_reserve() 在relay通道中保留一块连续的区域来留给未来的写入操作这通常用于那些希望直接写入到relay缓冲区的用户考虑到性能或者其它因素这些用户不希望先把数据写到一个临时缓冲区中然后再通过relay_write()进行写入

[] []

但我想说,我做了一个善良的平凡女子,并且一直在爱,

Linux的高效的数据传输技术-Relay[1]

相关文章:

你感兴趣的文章:

标签云: