blob: 53d54799f909768d2bfe93f689311564a860dbea [file] [edit]
// SPDX-License-Identifier: GPL-2.0
/* ublk control commands, shared by kublk and ublk_cancel_ready */
#include "kublk.h"
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);
}
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;
}
void ublk_ctrl_deinit(struct ublk_dev *dev)
{
io_uring_queue_exit(&dev->ring);
close(dev->ctrl_fd);
free(dev);
}
struct ublk_dev *ublk_ctrl_init(void)
{
struct ublk_dev *dev = (struct ublk_dev *)calloc(1, sizeof(*dev));
struct ublksrv_ctrl_dev_info *info;
int ret;
if (!dev)
return NULL;
info = &dev->dev_info;
dev->ctrl_fd = open(CTRL_DEV, O_RDWR);
if (dev->ctrl_fd < 0) {
free(dev);
return NULL;
}
info->max_io_buf_bytes = UBLK_IO_MAX_BYTES;
ret = ublk_setup_ring(&dev->ring, UBLK_CTRL_RING_DEPTH,
UBLK_CTRL_RING_DEPTH, IORING_SETUP_SQE128);
if (ret < 0) {
ublk_err("queue_init: %s\n", strerror(-ret));
close(dev->ctrl_fd);
free(dev);
return NULL;
}
dev->nr_fds = 1;
return dev;
}
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);
}
int ublk_ctrl_try_stop_dev(struct ublk_dev *dev)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_TRY_STOP_DEV,
};
return __ublk_ctrl_cmd(dev, &data);
}
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);
}
int ublk_ctrl_start_user_recovery(struct ublk_dev *dev)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_START_USER_RECOVERY,
};
return __ublk_ctrl_cmd(dev, &data);
}
int ublk_ctrl_end_user_recovery(struct ublk_dev *dev, int daemon_pid)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_END_USER_RECOVERY,
.flags = CTRL_CMD_HAS_DATA,
};
dev->dev_info.ublksrv_pid = data.data[0] = daemon_pid;
return __ublk_ctrl_cmd(dev, &data);
}
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);
}
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, &data);
}
int ublk_ctrl_get_info(struct ublk_dev *dev)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_GET_DEV_INFO,
.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);
}
int ublk_ctrl_set_params(struct ublk_dev *dev,
struct ublk_params *params)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_SET_PARAMS,
.flags = CTRL_CMD_HAS_BUF,
.addr = (__u64) (uintptr_t) params,
.len = sizeof(*params),
};
params->len = sizeof(*params);
return __ublk_ctrl_cmd(dev, &data);
}
int ublk_ctrl_get_params(struct ublk_dev *dev,
struct ublk_params *params)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_GET_PARAMS,
.flags = CTRL_CMD_HAS_BUF,
.addr = (__u64)params,
.len = sizeof(*params),
};
params->len = sizeof(*params);
return __ublk_ctrl_cmd(dev, &data);
}
int ublk_ctrl_get_features(struct ublk_dev *dev,
__u64 *features)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_GET_FEATURES,
.flags = CTRL_CMD_HAS_BUF,
.addr = (__u64) (uintptr_t) features,
.len = sizeof(*features),
};
return __ublk_ctrl_cmd(dev, &data);
}
int ublk_ctrl_update_size(struct ublk_dev *dev,
__u64 nr_sects)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_UPDATE_SIZE,
.flags = CTRL_CMD_HAS_DATA,
};
data.data[0] = nr_sects;
return __ublk_ctrl_cmd(dev, &data);
}
int ublk_ctrl_quiesce_dev(struct ublk_dev *dev, unsigned int timeout_ms)
{
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_QUIESCE_DEV,
.flags = CTRL_CMD_HAS_DATA,
};
data.data[0] = timeout_ms;
return __ublk_ctrl_cmd(dev, &data);
}
int ublk_ctrl_reg_buf(struct ublk_dev *dev, void *addr, size_t size,
__u32 flags)
{
struct ublk_shmem_buf_reg buf_reg = {
.addr = (unsigned long)addr,
.len = size,
.flags = flags,
};
struct ublk_ctrl_cmd_data data = {
.cmd_op = UBLK_U_CMD_REG_BUF,
.flags = CTRL_CMD_HAS_BUF,
.addr = (unsigned long)&buf_reg,
.len = sizeof(buf_reg),
};
return __ublk_ctrl_cmd(dev, &data);
}