From 3daa19ddb4b2b0fb782ba7f694da002a93f86ada Mon Sep 17 00:00:00 2001 From: nashzhou Date: Thu, 8 Oct 2026 15:47:03 +0800 Subject: [PATCH] ublk: support to update size of ublk device Backport the UBLK_U_CMD_UPDATE_SIZE feature from upstream (merged in v6.16), which allows the ublk server to resize a started ublk block device. The ublk server issues UBLK_U_CMD_UPDATE_SIZE via /dev/ublk-control with the new size (in units of sectors) passed in cmd->data[0]. The driver updates ublk_params.basic.dev_sectors and applies the new capacity via set_capacity_and_notify(), which also emits a RESIZE uevent to udev. The new UBLK_F_UPDATE_SIZE feature flag is reported via UBLK_U_CMD_GET_FEATURES so that userspace can probe for the capability. The backport includes the upstream fix for a NULL pointer dereference in ublk_ctrl_set_size() (CVE-2026-43364): the command is rejected with -ENODEV when the device hasn't been started yet (ub_disk is NULL). Documentation for the new control command is added to Documentation/block/ublk.rst. Signed-off-by: nashzhou --- Documentation/block/ublk.rst | 7 +++++++ drivers/block/ublk_drv.c | 27 ++++++++++++++++++++++++++- include/uapi/linux/ublk_cmd.h | 8 ++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Documentation/block/ublk.rst b/Documentation/block/ublk.rst index ff74b3ec4a98..4c3c5f1dd24e 100644 --- a/Documentation/block/ublk.rst +++ b/Documentation/block/ublk.rst @@ -197,6 +197,13 @@ managing and controlling ublk devices with help of several control commands: returns, ublk device is unquiesced and new I/O requests are passed to the new process. +- ``UBLK_CMD_UPDATE_SIZE`` + + Update size of the ublk block device (``/dev/ublkb*``). The new size is + passed in ``data[0]`` of ``ublksrv_ctrl_cmd`` and is in units of sectors. + This command is accepted after the device is started, and a RESIZE uevent + is sent to udev if the capacity is changed. + - user recovery feature description Two new features are added for user recovery: ``UBLK_F_USER_RECOVERY`` and diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index fce1d7c80d19..2fca3737a1e6 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -57,7 +57,8 @@ | UBLK_F_UNPRIVILEGED_DEV \ | UBLK_F_CMD_IOCTL_ENCODE \ | UBLK_F_USER_COPY \ - | UBLK_F_ZONED) + | UBLK_F_ZONED \ + | UBLK_F_UPDATE_SIZE) /* All UBLK_PARAM_TYPE_* should be included here */ #define UBLK_PARAM_TYPE_ALL \ @@ -2792,6 +2793,26 @@ static int ublk_ctrl_get_features(struct io_uring_cmd *cmd) return 0; } +static int ublk_ctrl_set_size(struct ublk_device *ub, + struct io_uring_cmd *cmd) +{ + const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); + struct ublk_param_basic *p = &ub->params.basic; + u64 new_size = header->data[0]; + int ret = 0; + + mutex_lock(&ub->mutex); + if (!ub->ub_disk) { + ret = -ENODEV; + goto out; + } + p->dev_sectors = new_size; + set_capacity_and_notify(ub->ub_disk, p->dev_sectors); +out: + mutex_unlock(&ub->mutex); + return ret; +} + /* * All control commands are sent via /dev/ublk-control, so we have to check * the destination device's permission @@ -2877,6 +2898,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub, case UBLK_CMD_SET_PARAMS: case UBLK_CMD_START_USER_RECOVERY: case UBLK_CMD_END_USER_RECOVERY: + case (_IOC_NR(UBLK_U_CMD_UPDATE_SIZE)): mask = MAY_READ | MAY_WRITE; break; default: @@ -2965,6 +2987,9 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, case UBLK_CMD_END_USER_RECOVERY: ret = ublk_ctrl_end_recovery(ub, cmd); break; + case (_IOC_NR(UBLK_U_CMD_UPDATE_SIZE)): + ret = ublk_ctrl_set_size(ub, cmd); + break; default: ret = -EOPNOTSUPP; break; diff --git a/include/uapi/linux/ublk_cmd.h b/include/uapi/linux/ublk_cmd.h index 3830b428ecf1..7b2c63ab6d44 100644 --- a/include/uapi/linux/ublk_cmd.h +++ b/include/uapi/linux/ublk_cmd.h @@ -49,6 +49,8 @@ _IOR('u', UBLK_CMD_GET_DEV_INFO2, struct ublksrv_ctrl_cmd) #define UBLK_U_CMD_GET_FEATURES \ _IOR('u', 0x13, struct ublksrv_ctrl_cmd) +#define UBLK_U_CMD_UPDATE_SIZE \ + _IOWR('u', 0x15, struct ublksrv_ctrl_cmd) /* * 64bits are enough now, and it should be easy to extend in case of @@ -188,6 +190,12 @@ */ #define UBLK_F_ZONED (1ULL << 8) +/* + * Resizing a block device is possible with UBLK_U_CMD_UPDATE_SIZE + * New size is passed in cmd->data[0] and is in units of sectors + */ +#define UBLK_F_UPDATE_SIZE (1ULL << 10) + /* device state */ #define UBLK_S_DEV_DEAD 0 #define UBLK_S_DEV_LIVE 1 -- 2.43.0