Add two commands to set/get parameters generically. Both generic block device parameters and feature related parameters can be covered with this way, then it becomes quite easy to extend in future. Meantime this way provides mechanism to simulate any kind of generic block device from userspace easily. Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> --- drivers/block/ublk_drv.c | 87 +++++++++++++++++++++++++++++++++++ include/uapi/linux/ublk_cmd.h | 2 + 2 files changed, 89 insertions(+) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index e185bdb165de..83fd65d8a205 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -1674,6 +1674,87 @@ static int ublk_ctrl_get_dev_info(struct io_uring_cmd *cmd) return ret; } +static int ublk_ctrl_get_para(struct io_uring_cmd *cmd) +{ + struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + void __user *argp = (void __user *)(unsigned long)header->addr; + struct ublk_device *ub; + struct ublk_para_header ph; + struct ublk_para_header *para = NULL; + int ret = 0; + + if (header->len <= sizeof(ph) || !header->addr) + return -EINVAL; + + ub = ublk_get_device_from_id(header->dev_id); + if (!ub) + return -EINVAL; + + ret = -EFAULT; + if (copy_from_user(&ph, argp, sizeof(ph))) + goto out_put; + + ret = ublk_validate_para_header(ub, &ph); + if (ret) + goto out_put; + + mutex_lock(&ub->mutex); + para = xa_load(&ub->paras, ph.type); + mutex_unlock(&ub->mutex); + if (!para) + ret = -EINVAL; + else if (copy_to_user(argp, para, ph.len)) + ret = -EFAULT; +out_put: + ublk_put_device(ub); + return ret; +} + +static int ublk_ctrl_set_para(struct io_uring_cmd *cmd) +{ + struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd; + void __user *argp = (void __user *)(unsigned long)header->addr; + struct ublk_device *ub; + struct ublk_para_header ph; + struct ublk_para_header *para = NULL; + int ret = -EFAULT; + + if (header->len <= sizeof(ph) || !header->addr) + return -EINVAL; + + ub = ublk_get_device_from_id(header->dev_id); + if (!ub) + return -EINVAL; + + if (copy_from_user(&ph, argp, sizeof(ph))) + goto out_put; + + ret = ublk_validate_para_header(ub, &ph); + if (ret) + goto out_put; + + para = kmalloc(ph.len, GFP_KERNEL); + if (!para) { + ret = -ENOMEM; + } else if (copy_from_user(para, argp, ph.len)) { + ret = -EFAULT; + } else { + /* parameters can only be changed when device isn't live */ + mutex_lock(&ub->mutex); + if (ub->dev_info.state != UBLK_S_DEV_LIVE) + ret = ublk_install_para(ub, para); + else + ret = -EACCES; + mutex_unlock(&ub->mutex); + } +out_put: + ublk_put_device(ub); + if (ret) + kfree(para); + + return ret; +} + static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) { @@ -1709,6 +1790,12 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, case UBLK_CMD_GET_QUEUE_AFFINITY: ret = ublk_ctrl_get_queue_affinity(cmd); break; + case UBLK_CMD_GET_PARA: + ret = ublk_ctrl_get_para(cmd); + break; + case UBLK_CMD_SET_PARA: + ret = ublk_ctrl_set_para(cmd); + break; default: break; } diff --git a/include/uapi/linux/ublk_cmd.h b/include/uapi/linux/ublk_cmd.h index 99f81a1e9a95..0f7be7398755 100644 --- a/include/uapi/linux/ublk_cmd.h +++ b/include/uapi/linux/ublk_cmd.h @@ -15,6 +15,8 @@ #define UBLK_CMD_DEL_DEV 0x05 #define UBLK_CMD_START_DEV 0x06 #define UBLK_CMD_STOP_DEV 0x07 +#define UBLK_CMD_SET_PARA 0x08 +#define UBLK_CMD_GET_PARA 0x09 /* * IO commands, issued by ublk server, and handled by ublk driver. -- 2.31.1