写入 io_uring 不会提前文件偏移量

问题描述 投票:0回答:1

我正在使用

io_uring
将一些数据写入磁盘,并注意到发出写入请求后文件偏移量不会自动增加。因此,如果我通过
liburing
发出两个写入请求,第二个请求将覆盖第一个请求,因为两个请求都试图写入文件的开头。单独使用这些 posix api(
write
writev
)不会导致任何问题,但通过
liburing
使用它们永远不会提前文件偏移量。
liburing
的手册页说将
offset
设置为 -1 将自动推进文件偏移量,但情况似乎并非如此。

下面是一个小例子。预期行为是将 4096 字节的 0 到 1023 数字写入文件,后跟 4096 字节的 0。然而,该文件仅包含 4096 字节的 0。如果我删除行

write_buffer_to_file(2)
,它现在包含 4096 字节的数字,因此第二次调用似乎覆盖了第一个调用的内容。
lseek
始终返回 0 的事实证实了文件偏移量永远不会改变。

代码片段使用 gcc 编译并在内核 5.14 的 RHEL 9.3 上运行。

#include <cstring>
#include <iostream>
#include <liburing.h>
#include <unistd.h>

// a small macro to check for errors
#define SYSCALL(expr) if ((expr) < 0) { \
    perror("System call error");        \
}

const int WRITE_SIZE = 4096; // satisfy alignment requirement of O_DIRECT
int fd; // file descriptor
int *buffer; // write buffer
struct io_uring ring;

// write the content of the buffer to fd; the data argument sets user_data in the sqe, which shouldn't affect the result
void write_buffer_to_file(int data) {
    struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
    io_uring_sqe_set_data(sqe, (void*)(intptr_t)data);
    // according to the documentation, setting offset to -1 will advance the offset
    // neither 0 nor -1 work in my testing
    io_uring_prep_write(sqe, fd, buffer, WRITE_SIZE, -1);
    SYSCALL(io_uring_submit(&ring))
    std::cout << "Submitted " << sqe->user_data << std::endl;

    // now wait for it to complete
    struct io_uring_cqe *cqe;
    SYSCALL(io_uring_wait_cqe(&ring, &cqe));
    if (cqe->res < 0) {
        perror("cqe res less than 0");
        std::cerr << std::strerror(-cqe->res) << std::endl;
    }
    io_uring_cqe_seen(&ring, cqe);
    std::cout << "Reaped " << io_uring_cqe_get_data(cqe) << std::endl;
    // this line always prints 0 even though it's supposed to advanced 4096 bytes
    std::cout << "Current offset: " << lseek(fd, 0, SEEK_CUR) << std::endl;
}

int main() {
    // set up the file and the write buffer
    fd = open("test_file", O_CREAT | O_WRONLY | O_DIRECT, 0744);
    SYSCALL(fd);
    // O_DIRECT has stricter memory alignment requirements
    posix_memalign((void**)&buffer, 512, WRITE_SIZE);
    for (int i = 0; i < WRITE_SIZE / sizeof(int); i++) {
        buffer[i] = i;
    }
    
    io_uring_queue_init(5, &ring, 0);
    write_buffer_to_file(1);

    // set everything in the buffer to 0 and then write again
    memset(buffer, 0, WRITE_SIZE);
    write_buffer_to_file(2);

    io_uring_queue_exit(&ring);

    close(fd);
    return 0;
}
linux io io-uring
1个回答
0
投票

原来这是旧内核版本的问题。在 Ubuntu 22.04(内核 6.2)上尝试相同的代码不会导致任何问题。

请参阅此 GitHub 问题。最好能确定修复此错误的提交,但修复发生在很久以前,因此很难找到。

© www.soinside.com 2019 - 2024. All rights reserved.