快捷搜索:

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

Relay 是一种从 Linux 内核到用户空间的高效数据传输技巧。经由过程用户定义的 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,主要按照面向用户空间和面向内核空间分为两大年夜类,下面我们来分手进行先容。

Relay的例子

我们用一个最简单的例子来先容怎么应用Relay。这个例子由两部分组成:一部分是位于内核空间将数据写入relay文件的法度榜样,应用时必要作为一个内核模块被加载;另一部分是位于用户空间从relay文件中读取数据的法度榜样,应用时作为通俗用户态法度榜样运行。

内核空间的法度榜样主要操作是:

加载模块时,打开一个relay通道,并且往打开的relay通道中写入消息;

卸载模块时,关闭relay通道。

法度榜样内容:

/*

* hello-mod.c

* a kernel-space client example of relayfs filesystem

*/

#include

#include

static struct rchan *hello_rchan;

int init_module(void)

{

const char *msg="Hello world

";

hello_rchan = relay_open("cpu", NULL, 8192, 2, NULL);

if(!hello_rchan){

printk("relay_open() failed.

");

return -ENOMEM;

}

relay_write(hello_rchan, msg, strlen(msg));

return 0;

}

void cleanup_module(void)

{

if(hello_rchan) {

relay_close(hello_rchan);

hello_rchan = NULL;

}

return;

}

MODULE_LICENSE ("GPL");

MODULE_DESCRIPTION ("Simple example of Relay");  用户空间的函数主要操作是:

●假如relayfs文件系统还没有被mount,则将其mount到目录/mnt/relay上;

您可能还会对下面的文章感兴趣: