在Linux上禁用特定文件的缓存/缓冲区

6
我目前在进行Yocto Linux构建,并尝试与FPGA上的硬件块进行接口。该块模拟带有FAT16文件系统的SD卡; 包含一个单一的文件(cam.raw)。该文件表示FPGA和Linux系统之间的共享内存空间。因此,我想能够从Linux系统向此内存中写入数据,并获得FPGA可能进行的任何更改(当前,FPGA仅从内存空间获取部分数据,并将32位字的LSB加6,例如我写入0x40302010,如果我读回数据,则应该得到0x40302016)。但是,由于某些缓存存在,虽然我可以将数据写入FPGA,但我无法立即获得结果。
我目前正在做类似这样的事情(使用Python因为它很容易):
% mount /dev/mmcblk1 /memstick
% python
>> import mmap
>> import os
>> f = os.open("/memstick/cam.raw", os.O_RDWR | os.O_DIRECT)
>> m = mmap.mmap(f, 0)
>> for i in xrange(1024):
...  m[i] = chr(i % 256)
...
>> m.flush() # Make sure data goes from linux to FPGA
>> hex(ord(m[0])) # Should be 0x6
'0x0'

我可以确认使用SignalTap/ChipScope工具对FPGA进行检测时,数据确实已更改(尽管我经常遇到缓冲问题)。在这种情况下,第一个32位字是0x03020106。然而,无论是Python还是Linux(或者两者都有)都会缓存文件并且不会从“SD卡”(FPGA)读取文件,而是将文件数据存储在内存中。我需要彻底关闭这一点,使得所有的读操作都来自于FPGA;但我不确定缓冲正在哪里发生或如何做到这一点。
非常感谢任何想法!(注意,我可以使用mmap.flush()将我从Python编写的任何数据转储到FPGA上,但我需要一种相反的刷新或某种方式来重新读取mmap中的文件数据!)
更新:
正如评论中建议的那样,mmap方法可能不是实现我所需的最佳方法。然而,我现在已经尝试了Python和C语言的基本I/O函数(在Python中使用os.read/write,在C中使用read/write),并使用了O_DIRECT标志。在大多数情况下,我最终得到了errno 22。仍在研究中...

1
我认为“O_DIRECT”不会影响“mmap()”。 - Dietrich Epp
嗯,知道了。那么,处理读写操作有更好的方法吗?(虽然我真的很喜欢 mmap 接口....) - Unn
1
你在这里做了一些奇怪的事情:你有一个在文件系统上正常挂载的文件,但底层块设备的内容正在改变,而没有人告诉内核块设备内容已经改变。通常,当您将驱动器插入系统时,对驱动器的所有更改都会首先通过内核进行,以便它可以使所有缓存(谁知道有多少层缓存?)全部失效。您可以尝试在/dev/mmcblk1上使用mmap(),自己解析文件系统,或者向内核专家寻求帮助。 - Dietrich Epp
1
O_DIRECT 不能使用的原因是,O_DIRECT 基本上是一个绕过页面缓存的指令,而 mmap() 是一个用于将页面缓存公开给程序的函数,因此它们在逻辑上不兼容。 - Dietrich Epp
mmap.flush 方法强制将内存缓冲区与实际磁盘同步。但我不确定这对您的问题是否足够——如果任何内存页面是脏的,它们会覆盖磁盘上的任何内容,而不是相反。 - abarnert
@DietrichEpp 感谢您提供的所有有用信息。我认为我遇到了一些缓存问题,但是我不确定如何告诉内核:“这是一个易失性文件,请不要缓存。”我可以尝试直接读写而不使用mmap,但是我还没有成功过(os.read和os.write都出现了错误)。 - Unn
1个回答

2

经过一番搜索,我发现在使用O_DIRECT标志时犯了错误。在我的C和Python版本中,我没有使用memalign来创建缓冲区,也没有进行块读/写。这篇文章有一个很好的解释:

如何在Linux上使用read()和O_DIRECT读取文件?

因此,为了实现我所做的事情,这个C程序作为一个基本示例:

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

#define BLKSIZE 512

int main() {
  int fd;
  int x;
  char* buf;

  fd = open("/home/root/sd/fpga/cam.raw", O_RDWR | O_SYNC | O_DIRECT);
  if (!fd) {
    printf("Oh noes, no file!\n");
    return -1;
  }

  printf("%d %d\n", fd, errno);

  buf = (char*) memalign(BLKSIZE, BLKSIZE*2);

  if (!buf) {
    printf("Oh noes, no buf!\n");
    return -1;
  }

  x = read(fd, buf, BLKSIZE);
  printf("%d %d %x %x %x %x\n", x, errno, buf[0], buf[1], buf[2], buf[3]);

  lseek(fd, 0, 0);

  buf[0] = '1';
  buf[1] = '2';
  buf[2] = '3';
  buf[3] = '4';
  x = write(fd, buf, BLKSIZE);

  printf("%d %d\n", fd, errno);

  lseek(fd, 0, 0);

  x = read(fd, buf, BLKSIZE);
  printf("%d %d %x %x %x %x\n", x,errno, buf[0], buf[1], buf[2], buf[3]);

  return 0;
}

这对我的目的来说可以运行,我没有查看如何正确地进行内存对齐以类似的方式使用Python的os.read/os.write函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接