]> www.infradead.org Git - nvme.git/commitdiff
ublk: Add UBLK_U_CMD_UPDATE_SIZE
authorOmri Mann <omri@nvidia.com>
Mon, 21 Apr 2025 10:59:50 +0000 (13:59 +0300)
committerJens Axboe <axboe@kernel.dk>
Mon, 21 Apr 2025 15:25:41 +0000 (09:25 -0600)
Currently ublk only allows the size of the ublkb block device to be
set via UBLK_CMD_SET_PARAMS before UBLK_CMD_START_DEV is triggered.

This does not provide support for extendable user-space block devices
without having to stop and restart the underlying ublkb block device
causing IO interruption.

This patch adds a new ublk command UBLK_U_CMD_UPDATE_SIZE to allow the
ublk block device to be resized on-the-fly.

Feature flag UBLK_F_UPDATE_SIZE is also added to indicate support.

Signed-off-by: Omri Mann <omri@nvidia.com>
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/2a370ab1-d85b-409d-b762-f9f3f6bdf705@nvidia.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/ublk_drv.c
include/uapi/linux/ublk_cmd.h

index 2de7b2bd409ddfdc1e9bad68cd942ec0bca7af07..03653bd7a1dfd69f5545a580dbc74de9d850c0ae 100644 (file)
@@ -50,6 +50,7 @@
 
 /* private ioctl command mirror */
 #define UBLK_CMD_DEL_DEV_ASYNC _IOC_NR(UBLK_U_CMD_DEL_DEV_ASYNC)
+#define UBLK_CMD_UPDATE_SIZE   _IOC_NR(UBLK_U_CMD_UPDATE_SIZE)
 
 #define UBLK_IO_REGISTER_IO_BUF                _IOC_NR(UBLK_U_IO_REGISTER_IO_BUF)
 #define UBLK_IO_UNREGISTER_IO_BUF      _IOC_NR(UBLK_U_IO_UNREGISTER_IO_BUF)
@@ -64,7 +65,8 @@
                | UBLK_F_CMD_IOCTL_ENCODE \
                | UBLK_F_USER_COPY \
                | UBLK_F_ZONED \
-               | UBLK_F_USER_RECOVERY_FAIL_IO)
+               | UBLK_F_USER_RECOVERY_FAIL_IO \
+               | UBLK_F_UPDATE_SIZE)
 
 #define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \
                | UBLK_F_USER_RECOVERY_REISSUE \
@@ -3075,6 +3077,16 @@ static int ublk_ctrl_get_features(const struct ublksrv_ctrl_cmd *header)
        return 0;
 }
 
+static void ublk_ctrl_set_size(struct ublk_device *ub, const struct ublksrv_ctrl_cmd *header)
+{
+       struct ublk_param_basic *p = &ub->params.basic;
+       u64 new_size = header->data[0];
+
+       mutex_lock(&ub->mutex);
+       p->dev_sectors = new_size;
+       set_capacity_and_notify(ub->ub_disk, p->dev_sectors);
+       mutex_unlock(&ub->mutex);
+}
 /*
  * All control commands are sent via /dev/ublk-control, so we have to check
  * the destination device's permission
@@ -3160,6 +3172,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 UBLK_CMD_UPDATE_SIZE:
                mask = MAY_READ | MAY_WRITE;
                break;
        default:
@@ -3251,6 +3264,10 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
        case UBLK_CMD_END_USER_RECOVERY:
                ret = ublk_ctrl_end_recovery(ub, header);
                break;
+       case UBLK_CMD_UPDATE_SIZE:
+               ublk_ctrl_set_size(ub, header);
+               ret = 0;
+               break;
        default:
                ret = -EOPNOTSUPP;
                break;
index 583b86681c93de4b0b0d501b5bee8b8d1ec9ecc9..be5c6c6b16e098838a2bf790e588b79656defdda 100644 (file)
@@ -51,6 +51,8 @@
        _IOR('u', 0x13, struct ublksrv_ctrl_cmd)
 #define UBLK_U_CMD_DEL_DEV_ASYNC       \
        _IOR('u', 0x14, 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
  */
 #define UBLK_F_USER_RECOVERY_FAIL_IO (1ULL << 9)
 
+/*
+ * 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