【问题标题】:Disk write does not work with malloc in C磁盘写入不适用于 C 中的 malloc
【发布时间】:2023-03-10 23:09:01
【问题描述】:

我确实使用 C 代码写入磁盘。

首先我尝试了malloc,发现write不起作用(write返回-1):

fd = open('/dev/sdb', O_DIRECT | O_SYNC | O_RDWR);
void *buff = malloc(512);
lseek(fd, 0, SEEK_SET);
write(fd, buff, 512);

然后我用这个更改了第二行并且它起作用了:

void *buff;
posix_memalign(&buff,512,512);

但是,当我将 lseek 偏移量更改为 1:lseek(fd, 1, SEEK_SET); 时,写入不再起作用。

首先,为什么 malloc 不起作用?

然后,我知道在我的情况下,posix_memalign 保证内存对齐的起始地址必须是 512 的倍数。但是,内存对齐和写入不应该是一个单独的过程吗?那么为什么我不能写入任何我想要的偏移量呢?

【问题讨论】:

  • 你检查mallocwrite的返回了吗??
  • 当我说write没有工作时,这意味着retval = -1。而且我检查了 malloc 没有返回 null。 @ameyCU
  • linux中以/dev开头的名字是特殊的块设备。如果你指定一个实际的文件会发生什么?
  • @Vincentius:那么你应该检查errno
  • 这是一个完整的例子吗?因为一个新的malloc()ed 缓冲区具有未初始化的字节,如果您尝试从它读取而之前没有写入它,则行为是未定义的。因此,特别是,可以将任何内容或任何内容都写入文件。也许您想使用calloc 来获得一个充满零字节的缓冲区?

标签: c io disk


【解决方案1】:

也许文档没有说,但很有可能需要对齐块设备的写入和读取,并且整个块才能成功(这可以解释为什么您在第一个和最后一个情况下会失败但不是在第二个)。如果您使用 linux,则 open(2) 的文档基本上是这样说的:

O_DIRECT 标志可能会对长度和 用户空间缓冲区的地址和 I/O 的文件偏移量。在 Linux 中 对齐限制因文件系统和内核版本而异 可能完全不存在。然而有电流- 几乎没有独立于文件系统的接口供应用程序发现给定文件或文件系统的这些限制。一些 文件系统为此提供了自己的接口,例如 xfsctl(3) 中的 XFS_IOC_DIOINFO 操作。

您的代码显示缺乏错误处理。代码中的每一行都包含可能失败的函数,openlseekwrite 也报告了errno 中的错误原因。因此,通过某种错误处理,它将是:

fd = open('/dev/sdb', O_DIRECT | O_SYNC | O_RDWR);

if( fd == -1 ) {
    perror("open failed");
    return;
}

void *buff = malloc(512);

if( !buff ) {
    printf("malloc failed");
    return;
}

if( lseek(fd, 0, SEEK_SET) == (off_t)-1 ) {
    perror("lseek failed");
    free(buff);
    return;
}

if( write(fd, buff, 512) == -1 ) {
    perror("write failed");
    free(buff);
    return;
}

在这种情况下,您至少可以更详细地说明问题所在。在这种情况下,我怀疑您从 write 调用中获得了 EIO(输入/输出错误)。

请注意,上述可能不是完整的错误处理,因为 perrorprintf 本身可能会失败(您可能想对这种可能性做点什么)。

【讨论】:

  • 感谢您的想法。实际上我在代码中确实有类似的错误处理,我只是展示了重要部分并避免长篇大论。
  • @Vincentius 如果你有这样的错误处理,它可能会告诉你更多关于发生了什么。 perror() 告诉你什么?
【解决方案2】:

来自 open(2) 的 Linux 手册页:

O_DIRECT 标志可能对长度施加对齐限制 和用户空间缓冲区的地址和 I/O 的文件偏移量。

还有:

Linux 2.4下,传输大小,以及用户的对齐方式 缓冲区和文件偏移量必须都是逻辑块的倍数 文件系统的大小。 Linux 2.6下,对齐到512字节 边界就足够了。

O_DIRECT 的意思是“尽量减少进出这个文件的 I/O 的缓存效应”,如果我理解正确,这意味着内核应该直接从用户空间缓冲区复制,因此也许需要更严格的数据对齐。

【讨论】:

  • 啊,太好了,它回答了大部分问题。顺便说一句,我仍然不清楚的是,为什么 posix_memalign 工作而不是 malloc
  • 呃,因为它给了你这种对齐的记忆? :o
  • posix_memalign 类似于malloc,只是它分配的内存是对齐的。也就是说,它从一个内存地址开始,该地址是第二个参数的倍数。
  • 好的,就像这个答案的第二个引用中所说的那样,然后 malloc 不起作用,因为它的分配可以不存在于“逻辑块大小的倍数 - 偏移量”中,而 posix_memalign 将保证这个条件。对吗?
  • @Vincentius:是的,这是正确的。 malloc 只能保证以允许您存储和访问任何数据类型的方式对齐内存,这在不同的处理器架构上可能意味着 4 或 8 的倍数,甚至没有。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
  • 1970-01-01
  • 2013-01-02
  • 2011-10-21
  • 1970-01-01
相关资源
最近更新 更多