• Xiaoguang Wang's avatar
    io_uring: export cq overflow status to userspace · 6d5f9049
    Xiaoguang Wang authored
    For those applications which are not willing to use io_uring_enter()
    to reap and handle cqes, they may completely rely on liburing's
    io_uring_peek_cqe(), but if cq ring has overflowed, currently because
    io_uring_peek_cqe() is not aware of this overflow, it won't enter
    kernel to flush cqes, below test program can reveal this bug:
    
    static void test_cq_overflow(struct io_uring *ring)
    {
            struct io_uring_cqe *cqe;
            struct io_uring_sqe *sqe;
            int issued = 0;
            int ret = 0;
    
            do {
                    sqe = io_uring_get_sqe(ring);
                    if (!sqe) {
                            fprintf(stderr, "get sqe failed\n");
                            break;;
                    }
                    ret = io_uring_submit(ring);
                    if (ret <= 0) {
                            if (ret != -EBUSY)
                                    fprintf(stderr, "sqe submit failed: %d\n", ret);
                            break;
                    }
                    issued++;
            } while (ret > 0);
            assert(ret == -EBUSY);
    
            printf("issued requests: %d\n", issued);
    
            while (issued) {
                    ret = io_uring_peek_cqe(ring, &cqe);
                    if (ret) {
                            if (ret != -EAGAIN) {
                                    fprintf(stderr, "peek completion failed: %s\n",
                                            strerror(ret));
                                    break;
                            }
                            printf("left requets: %d\n", issued);
                            continue;
                    }
                    io_uring_cqe_seen(ring, cqe);
                    issued--;
                    printf("left requets: %d\n", issued);
            }
    }
    
    int main(int argc, char *argv[])
    {
            int ret;
            struct io_uring ring;
    
            ret = io_uring_queue_init(16, &ring, 0);
            if (ret) {
                    fprintf(stderr, "ring setup failed: %d\n", ret);
                    return 1;
            }
    
            test_cq_overflow(&ring);
            return 0;
    }
    
    To fix this issue, export cq overflow status to userspace by adding new
    IORING_SQ_CQ_OVERFLOW flag, then helper functions() in liburing, such as
    io_uring_peek_cqe, can be aware of this cq overflow and do flush accordingly.
    Signed-off-by: default avatarXiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
    Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
    6d5f9049
io_uring.c 195 KB