/* SPDX-License-Identifier: MIT */
/*
* Description: uring_cmd based ublk
*/
#include "kublk.h"
unsigned int ublk_dbg_mask = UBLK_LOG;
static const struct ublk_tgt_ops *tgt_ops_list[] = {
&null_tgt_ops,
&loop_tgt_ops,
&stripe_tgt_ops,
};
static const struct ublk_tgt_ops *ublk_find_tgt(const char *name)
{
const struct ublk_tgt_ops *ops;
int i;
if (name == NULL)
return NULL;
for (i = 0; sizeof(tgt_ops_list) / sizeof(ops); i++)
if (strcmp(tgt_ops_list[i]->name, name) == 0)
return tgt_ops_list[i];
return NULL;
}
static inline int ublk_setup_ring(struct io_uring *r, int depth,
int cq_depth, unsigned flags)
{
struct io_uring_params p;
memset(&p, 0, sizeof(p));
p.flags = flags | IORING_SETUP_CQSIZE;
p.cq_entries = cq_depth;
return io_uring_queue_init_params(depth, r, &p);
}
static void ublk_ctrl_init_cmd(struct ublk_dev *dev,
struct io_uring_sqe *sqe,
struct ublk_ctrl_cmd_data *data)
{
struct ublksrv_ctrl_dev_info *info = &dev->dev_info;
struct ublksrv_ctrl_cmd *cmd = (struct ublksrv_ctrl_cmd *)ublk_get_sqe_cmd(sqe);
sqe->fd = dev->ctrl_fd;
sqe->opcode = IORING_OP_URING_CMD;
sqe->ioprio = 0;
if (data->flags & CTRL_CMD_HAS_BUF) {
cmd->addr = data->addr;
cmd->len = data->len;
}
if (data->flags & CTRL_CMD_HAS_DATA)
cmd->data[0] = data->data[0];
cmd->dev_id = info->dev_id;
cmd->queue_id = -1;
ublk_set_sqe_cmd_op(sqe, data->cmd_op);
io_uring_sqe_set_data(sqe, cmd);
}
static int __ublk_ctrl_cmd(struct ublk_dev *dev,
struct ublk_ctrl_cmd_data *data)
{
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
int ret = -EINVAL;
sqe = io_uring_get_sqe(&dev->ring);
if (!sqe) {
ublk_err("%s: can't get sqe ret %d\n", __func__, ret);
return ret;
}
ublk_ctrl_init_cmd(dev, sqe, data);
ret = io_uring_submit(&dev->ring);
if (ret < 0) {
ublk_err("uring submit ret %d\n", ret);
return ret;
}
ret = io_uring_wait_cqe(&dev->ring, &cqe);
if (ret < 0) {
ublk_err("wait cqe: %s\n", strerror(-ret));
return ret;
}
io_uring_cqe_seen(&dev->ring, cqe);
return cqe->res;
}
static int ublk_ctrl_stop_dev(struct ublk_dev *dev)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_STOP_DEV,
};
return __ublk_ctrl_cmd(dev, &data);
}
static int ublk_ctrl_start_dev(struct ublk_dev *dev,
int daemon_pid)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_START_DEV,
.flags = CTRL_CMD_HAS_DATA,
};
dev->dev_info.ublksrv_pid = data.data[0] = daemon_pid;
return __ublk_ctrl_cmd(dev, &data);
}
static int ublk_ctrl_add_dev(struct ublk_dev *dev)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_ADD_DEV,
.flags = CTRL_CMD_HAS_BUF,
.addr = (__u64) (uintptr_t) &dev->dev_info,
.len = sizeof(struct ublksrv_ctrl_dev_info),
};
return __ublk_ctrl_cmd(dev, &data);
}
static int ublk_ctrl_del_dev(struct ublk_dev *dev)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_DEL_DEV,
.flags = 0,
};
return __ublk_ctrl_cmd(dev, &