如何拼接/ dev / mem?

时间:2016-02-15 22:30:12

标签: c linux splice

我有一个外部FPGA器件,它通过PCIe将大量数据转储到保留的(使用引导加载程序参数)连续内存区域。该内存区域始终在同一位置启动。

我现在想尽快通过UDP转储该数据。我不关心检查这些数据,因此不需要将其带入用户空间。因此,我的研究表明使用零拷贝是最快/最好的方法。

我正在尝试int memFd = open("/dev/mem", O_RDONLY);,然后在memFdsendfile函数调用中使用splice,但这些都失败了。

花了几天时间,但我终于在sendfile源中看到输入文件描述符必须是一个常规文件(据我所知,这个详细信息遗留在手册页中),以及/dev/mem不是常规文件。无论如何,我再看了一遍,现在我有信心splice是我想要使用的电话。

然而,这也失败了14-EFAULT的错误,这意味着“坏地址”(再次令人沮丧的是,splice手册页中未提及此错误代码)。我查看了splice的源代码,并且可以看到几次返回EFAULT,但我只是看不到我传递的参数是如何导致问题的。

我的简化,非错误检查代码如下;

 int filedes[2];
 int memFd = open("/dev/mem", O_RDONLY);
 int fileFd = open("myTestFile.txt", O_RDONLY);
 loff_t offset = START_OF_MEM_REGION;
 int sockFd = ConfigureMySocket();

 pipe(filedes);  // this returns 0, so the pipes are good

 int ret = splice(memFd, &offset, filedes[1], NULL, 128, SPLICE_F_MOVE); // this fails with EFAULT
 //int ret = splice(memFd, NULL, filedes[1], NULL, 128, 0); // this also fails with EFAULT
 //int ret = splice(fileFd, NULL, filedes[1], NULL, 128, 0); // this works just fine

 // this is never reached because the splice call above hangs. If I run the
 // fileFd splice call instead this works just fine
 ret = splice(filedes[0], NULL, sockFd, NULL, 128, 0);

我的系统信息:

  • 在ARM体系结构上运行linux 3.1.10的嵌入式设备
  • 以root用户身份运行
  • 内核未使用CONFIG_STRICT_DEVMEM
  • 进行编译

其他有趣的事实:

  • 我有一个2.6 linux的CentOS虚拟机,这个代码可以正常工作到大约1MB的偏移量。但是,这个内核是用CONFIG_STRICT_DEVMEM编译的,所以我将1MB的限制归结为。{/ li>
  • 我可以mmap到内存区域就好了,看看FPGA正在写的数据。

我的问题是:

  1. 正在使用splice正确的方法吗?有人认为有更好的方法吗?
  2. 如果splice是对的,任何人都知道这里会发生什么?是否有内核编译器标志阻止它工作?我正在阅读splice.c的源代码,但它不是3.1.10版本,所以也许有些东西发生了变化?无论哪种方式,在虚拟机中看到这项工作都很好,但在嵌入式环境中却不行,这是一件令人失望的事。
  3. 编辑:我已经从kernal.org下载了3.1.10源码,遗憾的是看不出我在free-electrons.com上看到的与其他版本有什么重大差异。看起来我所有的拼接代码都在/fs/splice.c中。 do_splice(...)必须是执行的代码。我第一次打电话给splice(使用memFdfiledes[1])应该是if (opipe) { ...这里你可以看到EFAULT如果{ {1}}或copy_from_user失败了......这些怎么会失败?我的copy_to_user变量不会出现任何问题,因为如果&offset我得到同样的错误,或者如果我用NULL代替fileFd则没有错误。也感兴趣,如果我用0替换128(要写入的字节数),没有错误。返回memFd的地方,我只是看不到文件描述符如何影响该逻辑,除非EFAULT被更深层的函数调用返回...

    这些是来自EFAULT

    的摘录
    splice.c

1 个答案:

答案 0 :(得分:1)

mmap内存区域,然后使用常规writevmsplice