磁盘写入不适用于 C 中的 malloc

Disk write does not work with malloc in C

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

首先我尝试使用 malloc,发现写入无效(写入返回 -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的倍数。但是,内存对齐和写入不应该是一个单独的过程吗?那么为什么我不能写入我想要的任何偏移量?

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

The O_DIRECT flag may impose alignment restrictions on the length and address of user-space buffers and the file offset of I/Os. In Linux alignment restrictions vary by file system and kernel version and might be absent entirely. However there is cur‐ rently no file system-independent interface for an application to discover these restrictions for a given file or file system. Some file systems provide their own interfaces for doing so, for example the XFS_IOC_DIOINFO operation in xfsctl(3).

您的代码显示缺少错误处理。代码中的每一行都包含可能会失败的函数,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(Input/output 错误)。

请注意,上述可能不是完整的错误处理,因为 perrorprintf 本身可能会失败(您可能想针对这种可能性采取一些措施)。

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

The O_DIRECT flag may impose alignment restrictions on the length and address of user-space buffers and the file offset of I/Os.

并且:

Under Linux 2.4, transfer sizes, and the alignment of the user buffer and the file offset must all be multiples of the logical block size of the filesystem. Under Linux 2.6, alignment to 512-byte boundaries suffices.

O_DIRECT的意思是"try to minimize cache effects of the I/O to and from this file",如果我没理解错的话就是内核应该直接从user-space缓冲区copy,所以可能要求更严格数据对齐。