首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用IORING_OP_READ_FIXED?

如何使用IORING_OP_READ_FIXED?
EN

Stack Overflow用户
提问于 2021-01-04 10:08:11
回答 1查看 531关注 0票数 0

在下面的页面上https://lwn.net/Articles/810414/

IORING_OP_READ_FIXED IORING_OP_WRITE_FIXED这些操作代码也提交I/O操作,但是它们使用已经映射到内核的“注册”缓冲区,减少了总开销的数量。

然而,我在网上找不到一个关于如何使用它的例子。在io_uring_enter中,它说

在提交队列条目的操作码字段中指定了

EFAULT IORING_OP_READ_FIXED或IORING_OP_WRITE_FIXED,但是没有为该io_uring实例注册缓冲区,或者addr和len描述的地址范围不适合在buf_index注册的缓冲区中。

在我看来,我应该选择一个内存地址并阻止它使用,但是使用像0x555555500000和len as 4096这样的地址会导致同样的错误。

IORING_OP_READ_FIXED是如何工作的?下面是IORING_OP_READ的一个工作示例

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <linux/io_uring.h>

#define read_barrier()  __asm__ __volatile__("":::"memory")
#define write_barrier() __asm__ __volatile__("":::"memory")

int main(int argc, char *argv[])
{
    struct io_uring_params uring;
    memset(&uring, 0, sizeof(uring));
    auto queue_size = 5;
    auto ring_fd = syscall(__NR_io_uring_setup, queue_size, &uring);

    auto*uring_ptr = (char*)mmap(0, uring.sq_off.array + uring.sq_entries * 4, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, ring_fd, IORING_OFF_SQ_RING);
    auto*submit_entries = (io_uring_sqe*)mmap(0, uring.sq_entries * sizeof(struct io_uring_sqe), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, ring_fd, IORING_OFF_SQES);

    unsigned &sqHead = *(unsigned*)(uring_ptr + uring.sq_off.head);
    unsigned &sqTail = *(unsigned*)(uring_ptr + uring.sq_off.tail);
    unsigned &sqMask = *(unsigned*)(uring_ptr + uring.sq_off.ring_mask);
    unsigned &sqFlags = *(unsigned*)(uring_ptr + uring.sq_off.flags);
    unsigned *sqArray = (unsigned*)(uring_ptr + uring.sq_off.array);

    unsigned &cqHead = *(unsigned*)(uring_ptr + uring.cq_off.head);
    unsigned &cqTail = *(unsigned*)(uring_ptr + uring.cq_off.tail);
    unsigned &cqMask = *(unsigned*)(uring_ptr + uring.cq_off.ring_mask);
    io_uring_cqe *cqes = (io_uring_cqe*)(uring_ptr + uring.cq_off.cqes);


    int fd[2];
    fd[0] = open(argv[1], O_RDONLY);
    

    struct stat stat;
    if (fstat(fd[0], &stat) < 0) {
        perror("fstat");
        return -1;
    }

    int size_aligned = (stat.st_size & ~63) + (stat.st_size & 63 ? 64 : 0);

    auto*fileBuf = (unsigned char*)malloc(size_aligned*2);

    for(int i=0; i<1; i++)
    {
        io_uring_sqe&sqe = submit_entries[sqTail & sqMask];
        sqe.fd = fd[i];
        sqe.flags = 0;
        sqe.opcode = IORING_OP_READ;
        sqe.addr = (unsigned long long)fileBuf+i*size_aligned;
        sqe.len = size_aligned;
        sqe.user_data = (unsigned long long)fileBuf+i*size_aligned;
        sqArray[sqTail&sqMask] = sqTail&sqMask;
        sqTail++;
    }
    write_barrier();

    //int ret =  syscall(__NR_io_uring_enter, ring_fd, 2, 2, IORING_ENTER_GETEVENTS, 0);
    int ret =  syscall(__NR_io_uring_enter, ring_fd, 1, 1, IORING_ENTER_GETEVENTS, 0);
    //int ret =  syscall(__NR_io_uring_enter, ring_fd, 1, 0, IORING_ENTER_GETEVENTS, 0);
    //sleep(1);
    read_barrier();
    while (cqHead != cqTail)
    {
        unsigned long long a = cqHead;
        unsigned long long b = cqTail;
        unsigned long long c = cqMask;
        auto index=cqHead & cqMask;
        io_uring_cqe&cqe = cqes[index];
        auto u=cqe.user_data;
        auto f=cqe.flags;
        auto r=cqe.res;
        puts((const char*)u);
        cqHead++;
    }
    int a=0;
    return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-02 00:42:15

您需要使用__NR_io_uring_register系统调用注册(和取消注册)缓冲区。使用您的示例,您可以将缓冲区应用于iovec,并将iovec传递到syscall:

代码语言:javascript
运行
复制
struct iovec iov = { .iov_base = (void *)fileBuf, .iov_len = (size_aligned*2) };

int rc = syscall(__NR_io_uring_register, ring_fd, IORING_REGISTER_BUFFERS, 
                 (void *)&iov, 1 /* number of iovs */);

要使用已注册的缓冲区,需要在sqe中提供缓冲区的数组偏移量。在这个例子中,这个值总是'0‘,因为只有一个iovec已经注册了。在代码中,需要设置sqe.opcode = IORING_OP_READ_FIXEDsqe.buf_index = 0

您还可以考虑使用liburing.h中的初始化助手函数:

代码语言:javascript
运行
复制
static inline void io_uring_prep_read_fixed(struct io_uring_sqe *sqe, int fd,
                                            void *buf, unsigned nbytes,
                                            off_t offset, int buf_index)
{
        io_uring_prep_rw(IORING_OP_READ_FIXED, sqe, fd, buf, nbytes, offset);
        sqe->buf_index = buf_index;
}

我建议查看liburing它恰当地处理了许多繁琐的初始化细节,以及为缓冲区取消注册提供包装。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65560823

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档