免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1649 | 回复: 8
打印 上一主题 下一主题

有用过relayfs在内核与用户空间传输数据的没,怎没用户空间进程读不出数据呢 ? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-07-13 21:04 |只看该作者 |倒序浏览
听说relayfs能在内核和用户空见快速传递大量数据 ,所以想要试一试
重编译了一下2.6.15内核 ,让它支持relayfs虚拟文件系统
又写了一个内核模块,里边定义了一个channel(比如名字叫info),
并且内核运行中relay_open("info",..),打开这个channel,
并且利用relay_write写数据到channel
mount过relayfs,终端处cat相应channel是可以看到内核写入的数据的
现在问题是有一个用户进程,本来可以用open("/mnt/relay/file",fd),
                                 read(fd,buf,sizeof(buf))这样的用户空间API来访问数据到用户空间缓冲区buf
但怎莫读出的buf数据为空呢

有人用过吗,要不就是我使用的用户空间语句有误??
或者谁知道对于relayfs的API:read,write,mmap等等具体的参数火使用方法,我找到的资料都没详细介绍

论坛徽章:
0
2 [报告]
发表于 2006-07-13 21:06 |只看该作者
忘了,先致谢!!!

论坛徽章:
0
3 [报告]
发表于 2006-07-13 21:53 |只看该作者
这么重要的技术lwn.net居然没有提到。

把你的代码贴出来吧,大家一起分析一下。

论坛徽章:
0
4 [报告]
发表于 2006-07-14 09:09 |只看该作者

简单介绍

转自 http://www-128.ibm.com/developerworks/cn/linux/l-kerns-usrs2/

relayfs是一个快速的转发(relay)数据的文件系统,它以其功能而得名。它为那些需要从内核空间转发大量数据到用户空间的工具和应用提供了快速有效的转发机制。

Channel是relayfs文件系统定义的一个主要概念,每一个channel由一组内核缓存组成,每一个CPU有一个对应于该channel的内核缓存,每一个内核缓存用一个在relayfs文件系统中的文件文件表示,内核使用relayfs提供的写函数把需要转发给用户空间的数据快速地写入当前CPU上的channel内核缓存,用户空间应用通过标准的文件I/O函数在对应的channel文件中可以快速地取得这些被转发出的数据mmap来。写入到channel中的数据的格式完全取决于内核中创建channel的模块或子系统。

relayfs的用户空间API:

relayfs实现了四个标准的文件I/O函数,open、mmap、poll和close

open(),打开一个channel在某一个CPU上的缓存对应的文件。
mmap(),把打开的channel缓存映射到调用者进程的内存空间。
read(),读取channel缓存,随后的读操作将看不到被该函数消耗的字节,如果channel的操作模式为非覆盖写,那么用户空间应用在有内核模块写时仍可以读取,但是如果channel的操作模式为覆盖式,那么在读操作期间如果有内核模块进行写,结果将无法预知,因此对于覆盖式写的channel,用户应当在确认在channel的写完全结束后再进行读。
poll(),用于通知用户空间应用转发数据跨越了子缓存的边界,支持的轮询标志有POLLIN、POLLRDNORM和POLLERR。
close(),关闭open函数返回的文件描述符,如果没有进程或内核模块打开该channel缓存,close函数将释放该channel缓存。
注意:用户态应用在使用上述API时必须保证已经挂载了relayfs文件系统,但内核在创建和使用channel时不需要relayfs已经挂载。下面命令将把relayfs文件系统挂载到/mnt/relay。

mount -t relayfs relayfs /mnt/relay

relayfs内核API:

relayfs提供给内核的API包括四类:channel管理、写函数、回调函数和辅助函数。

Channel管理函数包括:

relay_open(base_filename, parent, subbuf_size, n_subbufs, overwrite, callbacks)
relay_close(chan)
relay_flush(chan)
relay_reset(chan)
relayfs_create_dir(name, parent)
relayfs_remove_dir(dentry)
relay_commit(buf, reserved, count)
relay_subbufs_consumed(chan, cpu, subbufs_consumed)
写函数包括:

relay_write(chan, data, length)
__relay_write(chan, data, length)
relay_reserve(chan, length)
回调函数包括:

subbuf_start(buf, subbuf, prev_subbuf_idx, prev_subbuf)
buf_mapped(buf, filp)
buf_unmapped(buf, filp)
辅助函数包括:

relay_buf_full(buf)
subbuf_start_reserve(buf, length)
前面已经讲过,每一个channel由一组channel缓存组成,每个CPU对应一个该channel的缓存,每一个缓存又由一个或多个子缓存组成,每一个缓存是子缓存组成的一个环型缓存。

函数relay_open用于创建一个channel并分配对应于每一个CPU的缓存,用户空间应用通过在relayfs文件系统中对应的文件可以访问channel缓存,参数base_filename用于指定channel的文件名,relay_open函数将在relayfs文件系统中创建base_filename0..base_filenameN-1,即每一个CPU对应一个channel文件,其中N为CPU数,缺省情况下,这些文件将建立在relayfs文件系统的根目录下,但如果参数parent非空,该函数将把channel文件创建于parent目录下,parent目录使用函数relay_create_dir创建,函数relay_remove_dir用于删除由函数relay_create_dir创建的目录,谁创建的目录,谁就负责在不用时负责删除。参数subbuf_size用于指定channel缓存中每一个子缓存的大小,参数n_subbufs用于指定channel缓存包含的子缓存数,因此实际的channel缓存大小为(subbuf_size x n_subbufs),参数overwrite用于指定该channel的操作模式,relayfs提供了两种写模式,一种是覆盖式写,另一种是非覆盖式写。使用哪一种模式完全取决于函数subbuf_start的实现,覆盖写将在缓存已满的情况下无条件地继续从缓存的开始写数据,而不管这些数据是否已经被用户应用读取,因此写操作决不失败。在非覆盖写模式下,如果缓存满了,写将失败,但内核将在用户空间应用读取缓存数据时通过函数relay_subbufs_consumed()通知relayfs。如果用户空间应用没来得及消耗缓存中的数据或缓存已满,两种模式都将导致数据丢失,唯一的区别是,前者丢失数据在缓存开头,而后者丢失数据在缓存末尾。一旦内核再次调用函数relay_subbufs_consumed(),已满的缓存将不再满,因而可以继续写该缓存。当缓存满了以后,relayfs将调用回调函数buf_full()来通知内核模块或子系统。当新的数据太大无法写入当前子缓存剩余的空间时,relayfs将调用回调函数subbuf_start()来通知内核模块或子系统将需要使用新的子缓存。

论坛徽章:
0
5 [报告]
发表于 2006-07-14 09:28 |只看该作者

利用下面这个例子说我得问题

例子从http://relayfs.sourceforge.net/examples.html得到
直接使用relayfs,
In init/main.c:


#include <linux/relayfs_fs.h>
#define SUBBUF_SIZE 262144
#define N_SUBBUFS 4
struct rchan *kleak_chan = NULL;

static void __init do_basic_setup(void)
{
        /* drivers will send hotplug events */
        init_workqueues();
        usermodehelper_init();
        driver_init();

#ifdef CONFIG_SYSCTL
        sysctl_init();
#endif

        /* Networking initialization needs a process context */
        sock_init();

        do_initcalls();

        kleak_chan = relay_open("kleak", NULL, SUBBUF_SIZE,
                                  N_SUBBUFS, 1, NULL);---------------打开channel
        if (!kleak_chan)
                printk("kleak channel creation failed\n");
        else
                printk("kleak channel ready\n");

}

In mm/slab.c:


#include <linux/relayfs_fs.h>
extern struct rchan *kleak_chan;

void *__kmalloc(size_t size, unsigned int __nocast flags)
{
        kmem_cache_t *cachep;
        void *a;

        cachep = __find_general_cachep(size, flags);
        if (unlikely(cachep == NULL))
                return NULL;
        a = __cache_alloc(cachep, flags);


        if (kleak_chan) {
                char buf[64];
                int size = sprintf(buf, "kmalloc: addr %p caller %p, size %d\n",
                                   a, __builtin_return_address(0), size);
                relay_write(kleak_chan, buf, size);-------------------------往channel里写数据
        }
       
        return a;
}

void kfree(const void *objp)
{
        kmem_cache_t *c;
        unsigned long flags;

        if (unlikely(!objp))
                return;


        if (kleak_chan) {
                char buf[64];
                int size = sprintf(buf, "kfree: addr %p caller %p, size %d\n",
                                   objp, __builtin_return_address(0), ksize(objp));
                relay_write(kleak_chan, buf, size);-----------------写数据
        }

        local_irq_save(flags);
        kfree_debugcheck(objp);
        c = GET_PAGE_CACHE(virt_to_page(objp));
        __cache_free(c, (void*)objp);
        local_irq_restore(flags);
}

重编译内核挂载mount -t relayfs relayfs /mnt/relay
/mnt/relay目录下 cat kleak能看到数据
我的问题是,现在写个用户程序
代码:

我在别的资料上看到的用法是
fd=open("/mnt/relay/kleak",...);
while(1){
n=read(fd,buf,sizeof(buf));
if(n<0){
close(fd);
break;
}
}
就应该能读出数据了,但这样得出buf得数据是空的
有兴趣的同志试试好了
觉得重编译内核麻烦的话,在模块里定义
channel也是可以的,但你的内核若不支持relayfs就非得重编译了

论坛徽章:
0
6 [报告]
发表于 2006-07-14 15:46 |只看该作者
查了一下资料。从2.6.17内核开始,relayfs被整合成了一个kernel API。主要文件是kernel/relay.c和include/linux/relay.h。不再有单独的文件系统,而是通过sysfs跟用户通讯。除此之外,兼容原来的接口。

论坛徽章:
0
7 [报告]
发表于 2006-07-14 16:19 |只看该作者
虽然relayfs很早就引入了内核,但在内核的其他部分似乎一直没有用这项技术。直到2.6.17内核中,才在block/blktrace.c中用到。大家如果想了解这项技术的话,可以参考一下这个。

[ 本帖最后由 richardhesidu 于 2006-7-14 16:25 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2006-07-14 20:40 |只看该作者
我用的内核是2。6。15的,要了解的话要在下一个新内核了

谢谢楼下的大哥!!!

论坛徽章:
0
9 [报告]
发表于 2006-07-14 20:42 |只看该作者
写错了

汗汗汗我
谢楼上大哥!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP