c-读写mmap的参数无效



由于某种原因,我得到了-EINVAL,我不清楚为什么。以下是我打开并尝试mmap文件的位置:

if ((fd = open(argv[1], O_RDWR)) < 0)
{
    fprintf(stderr, "Failed to open %s: %sn", argv[1], strerror(errno));
    return 1;
}
struct stat statbuf;
if (fstat(fd, &statbuf))
{
    fprintf(stderr, "stat filed: %sn", strerror(errno));
    return 1;
}
char* fbase = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (fbase == MAP_FAILED)
{
    fprintf(stderr, "mmap failed: %sn", strerror(errno));
    return 1;
}

编辑:我应该补充一下,错误发生在mmap中。

事实证明,将MAP_SHARED更改为MAP_PRIVATE可以成功

失败的原因很微妙:我的代码在VirtualBox虚拟机中运行,而我尝试mmap的文件位于主机上的共享目录中。VirtualBox虚拟文件系统显然没有在系统管理程序的边界上使用MAP_SHARED选项来实现mmap

如果您阅读jxh对我的问题和他的回答的有用评论,就会发现这段代码对他有效,因为他可能试图将主机文件系统文件mmap写入主机内存。

我观察到从MAP_SHARED切换到MAP_PRIVATE也与此一致:由于私有映射的内存对其他进程是不可见的,因此虚拟文件系统驱动程序可能不会反对映射内存。

解决方案是将我想要映射的文件移动到客户的硬盘驱动器中,并从那里进行操作。

您的statbuf.st_size就是0。如果length参数为0,则mmap()将失败。

列出了EINVAL错误mmap()的3个原因:

void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);

  • 我们不喜欢addrlengthoffset(例如,它们太大,或者没有在页面边界上对齐)
  • (从Linux 2.6.12开始)length为0
  • flags不包含MAP_PRIVATEMAP_SHARED,或者同时包含这两个值

编辑grub以添加iomem=relaxed并重新启动,确保cat /proc/cmdline在启动后显示iomem=relaxed的条目,重新运行程序并检查

[root@fedora ~]# cat /proc/cmdline 
BOOT_IMAGE=(hd0,gpt2)/vmlinuz-5.18.19-200.fc36.x86_64 root=/dev/mapper/fedora_fedora-root ro rd.lvm.lv=fedora_fedora/root iomem=relaxed rhgb quiet

相关内容

最新更新