• Xiaoguang Wang's avatar
    io_uring: reset -EBUSY error when io sq thread is waken up · d4ae271d
    Xiaoguang Wang authored
    In io_sq_thread(), currently if we get an -EBUSY error and go to sleep,
    we will won't clear it again, which will result in io_sq_thread() will
    never have a chance to submit sqes again. Below test program test.c
    can reveal this bug:
    
    int main(int argc, char *argv[])
    {
            struct io_uring ring;
            int i, fd, ret;
            struct io_uring_sqe *sqe;
            struct io_uring_cqe *cqe;
            struct iovec *iovecs;
            void *buf;
            struct io_uring_params p;
    
            if (argc < 2) {
                    printf("%s: file\n", argv[0]);
                    return 1;
            }
    
            memset(&p, 0, sizeof(p));
            p.flags = IORING_SETUP_SQPOLL;
            ret = io_uring_queue_init_params(4, &ring, &p);
            if (ret < 0) {
                    fprintf(stderr, "queue_init: %s\n", strerror(-ret));
                    return 1;
            }
    
            fd = open(argv[1], O_RDONLY | O_DIRECT);
            if (fd < 0) {
                    perror("open");
                    return 1;
            }
    
            iovecs = calloc(10, sizeof(struct iovec));
            for (i = 0; i < 10; i++) {
                    if (posix_memalign(&buf, 4096, 4096))
                            return 1;
                    iovecs[i].iov_base = buf;
                    iovecs[i].iov_len = 4096;
            }
    
            ret = io_uring_register_files(&ring, &fd, 1);
            if (ret < 0) {
                    fprintf(stderr, "%s: register %d\n", __FUNCTION__, ret);
                    return ret;
            }
    
            for (i = 0; i < 10; i++) {
                    sqe = io_uring_get_sqe(&ring);
                    if (!sqe)
                            break;
    
                    io_uring_prep_readv(sqe, 0, &iovecs[i], 1, 0);
                    sqe->flags |= IOSQE_FIXED_FILE;
    
                    ret = io_uring_submit(&ring);
                    sleep(1);
                    printf("submit %d\n", i);
            }
    
            for (i = 0; i < 10; i++) {
                    io_uring_wait_cqe(&ring, &cqe);
                    printf("receive: %d\n", i);
                    if (cqe->res != 4096) {
                            fprintf(stderr, "ret=%d, wanted 4096\n", cqe->res);
                            ret = 1;
                    }
                    io_uring_cqe_seen(&ring, cqe);
            }
    
            close(fd);
            io_uring_queue_exit(&ring);
            return 0;
    }
    sudo ./test testfile
    above command will hang on the tenth request, to fix this bug, when io
    sq_thread is waken up, we reset the variable 'ret' to be zero.
    Suggested-by: default avatarJens Axboe <axboe@kernel.dk>
    Signed-off-by: default avatarXiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
    Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
    d4ae271d
io_uring.c 191 KB