On Wed, Feb 26, 2025 at 11:58:38PM +0800, Ming Lei wrote: > + struct io_uring_sqe *reg; > + struct io_uring_sqe *rw; > + struct io_uring_sqe *ureg; > + > + if (!zc) { > + rw = ublk_queue_alloc_sqe(q); > + if (!rw) > + return -ENOMEM; > + > + io_uring_prep_rw(op, rw, 1 /*fds[1]*/, > + (void *)iod->addr, > + iod->nr_sectors << 9, > + iod->start_sector << 9); > + io_uring_sqe_set_flags(rw, IOSQE_FIXED_FILE); > + q->io_inflight++; > + /* bit63 marks us as tgt io */ > + rw->user_data = build_user_data(tag, op, UBLK_IO_TGT_NORMAL, 1); > + return 0; > + } > + > + ublk_queue_alloc_sqe3(q, ®, &rw, &ureg); > + > + io_uring_prep_buf_register(reg, 0, tag, q->q_id, tag); > + reg->user_data = build_user_data(tag, 0xfe, 1, 1); > + reg->flags |= IOSQE_CQE_SKIP_SUCCESS; > + reg->flags |= IOSQE_IO_LINK; > + > + io_uring_prep_rw(op, rw, 1 /*fds[1]*/, 0, > + iod->nr_sectors << 9, > + iod->start_sector << 9); > + rw->buf_index = tag; > + rw->flags |= IOSQE_FIXED_FILE; > + rw->flags |= IOSQE_IO_LINK; > + rw->user_data = build_user_data(tag, op, UBLK_IO_TGT_ZC_OP, 1); > + q->io_inflight++; > + > + io_uring_prep_buf_unregister(ureg, 0, tag, q->q_id, tag); > + ureg->user_data = build_user_data(tag, 0xff, UBLK_IO_TGT_ZC_BUF, 1); You don't have anything handling the unregister command's completion so I think you want the IOSQE_CQE_SKIP_SUCCESS flag on it otherwise you get an unexpected CQE for it.