writev(或pwritev)会与c中的O_DIRECT冲突吗?

writev(or pwritev) will conflict with O_DIRECT in c?

我尝试将 writevdirect IO 结合使用。但是我和他们结合的时候失败了

下面的代码有效,但如果我在 open()

时添加 O_DIRECT 则失败

我总是在失败时得到 "Invalid arguments"。

int main(){
    char *str0 = "hello ";
    char *str1 = "world\n";
    struct iovec iov[2];
    ssize_t nwritten;

    iov[0].iov_base = str0;
    iov[0].iov_len = strlen(str0);
    iov[1].iov_base = str1;
    iov[1].iov_len = strlen(str1);

    int fd = open("./foo",O_RDWR|O_CREAT);// will fail if add O_DIRECT
    nwritten = writev(fd, iov, 2);
    printf("num:%ld,%s\n", nwritten, strerror(errno));

    close(fd);
    return 0;
}

所以我认为这可能是内存对齐问题,所以我将它们调整为如下所示的内存对齐缓冲区:

#define BLOCKSIZE 512
int main(){
    char *str0 = "hello ";
    char *str1 = "world\n";
    struct iovec iov[2];
    ssize_t nwritten;

    void *buffer, *buffer1;
    posix_memalign(&buffer, BLOCKSIZE, BLOCKSIZE);
    memcpy(buffer, str0, strlen(str0));
    posix_memalign(&buffer1, BLOCKSIZE, BLOCKSIZE);
    memcpy(buffer1, str1, strlen(str1));

    iov[0].iov_base = buffer;
    iov[0].iov_len = strlen(buffer);
    iov[1].iov_base = buffer1;
    iov[1].iov_len = strlen(buffer1);

    int fd = open("./foo",O_RDWR|O_CREAT|O_DIRECT);
    nwritten = writev(fd, iov, 2);
    printf("num:%ld,%s\n", nwritten, strerror(errno));

    close(fd);
    free(buffer);
    return 0;
}

但还是失败了

有办法解决吗?

您应该尝试将两者 iov_len 设置为 BLOCKSIZE,但文件大小不会是 strlen(str0) + strlen(str1)。

对于 DIRECT_IO,您写入 from/read 的缓冲区有对齐和大小限制。

这意味着您的写入缓冲区必须与设备的物理块大小正确对齐并且其大小必须可以被设备的物理块大小整除。

而设备的物理块大小可以通过 /sysfs 查找,通常为 512 或 4k 字节。因此,使用 4k 将是一个 'safe' 的选择。

您的 strlen(buffer)strlen(buffer1) 大小肯定不能被物理块大小整除。