嵌入式linux中文站向咱们介绍一种从 Linux 内核到用户空间的高效数据传输技能relay。经过用户界说的 relay 通道,内核空间的程序能够高效、牢靠、快捷地将数据传输到用户空间。Relay 特别适用于内核空间有许多数据需求传输到用户空间的景象,现在现已广泛应用在内核调试东西如 SystemTap中。本文介绍了 Relay 的前史和原理,并且用一个简略的实例介绍了 Relay 的详细用法。
Relay 要处理的问题
关于任何在内核作业的程序而言,怎么把许多的调试信息从内核空间传输到用户空间都是一个大费事,关于运转中的内核更是如此。特别是关于哪些用于调试内核功能的东西,更是如此。
关于这种许多数据需求在内核中缓存并传输到用户空间需求,许多传统的办法都已抵达了极限,例如内核程序员很熟悉的 printk() 调用。此外,假如不同的内核子体系都开发自己的缓存和传输代码,形成很大的代码冗余,并且也带来保护上的困难。
这些,都要求开发一套能够高效牢靠地将数据从内核空间转发到用户空间的体系,并且这个体系应该独立于各个调试子体系。这样就诞生了 RelayFS。
Relay的开展前史
Relay 的前身是 RelayFS,即作为 Linux 的一个新式文件体系。2003年3月,RelayFS的第一个版别的代码被开发出来,在7月14日,第一个针对2.6内核的版别也开端供给下载。经过广泛的试用和改善,直到2005年9月,RelayFS才被参加mainline内核(2.6.14)。一起,RelayFS也被移植到2.4内核中。在 2006年2月,从2.6.17开端,RelayFS不再作为独自的文件体系存在,而是成为内核的一部分。它的源码也从fs/目录下转移到 kernel/relay.c中,称号中也从RelayFS改成了Relay。
RelayFS现在现已被越来越多的内核东西运用,包含内核调试东西SystemTap、LTT,以及一些特别的文件体系例如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缓冲区(kbuf0到kbuf3)组成,别离对应于体系中的cpu0到cpu1。每个CPU上的代码调用relay_write()的时分将数据写入自己对应的relay缓冲区内。每个relay缓冲区称一个relay文件,即/cpu0到 /cpu3。当文件体系被mount到/mnt/今后,这个relay文件就被映射成映射到用户空间的地址空间。一旦数据可用,用户程序就能够把它的数据读出来写入到硬盘上的文件中,即cpu0.out到cpu3.out。
Relay的首要API
前面说到的 relay_write() 便是 relay API 之一。除此以外,Relay 还供给了更多的 API来支撑用户程序完好的运用 relay。这些 API,首要依照面向用户空间和面向内核空间分为两大类,下面咱们来别离进行介绍。
面向用户空间的 API
这些 Relay 编程接口向用户空间程序供给了拜访 relay 通道缓冲区数据的根本操作的进口,包含:
●open() – 答应用户翻开一个现已存在的通道缓冲区。
●mmap() – 使通道缓冲区被映射到坐落用户空间的调用者的地址空间。要特别注意的是,咱们不能仅对部分区域进行映射。也便是说,有必要映射整个缓冲区文件,其巨细是 CPU的个数和单个 CPU 缓冲区巨细的乘积。
●read() – 读取通道缓冲区的内容。这些数据一旦被读出,就意味着他们被用户空间的程序消费掉了,也就不能被之后的读操作看到。
●sendfile() – 将数据从通道缓冲区传输到一个输出文件描述符。其间或许的填充字符会被主动去掉,不会被用户看到。
●poll() – 支撑 POLLIN/POLLRDNORM/POLLERR 信号。每次子缓冲区的鸿沟被越过期,等待着的用户空间程序会得到告诉。
●close() – 将通道缓冲区的引证数减1。当引证数减为0时,标明没有进程或许内核用户需求翻开它,然后这个通道缓冲区被开释。