ublk: set_params: properly check if parameters can be applied
authorUday Shankar <ushankar@purestorage.com>
Tue, 4 Mar 2025 21:34:26 +0000 (14:34 -0700)
committerJens Axboe <axboe@kernel.dk>
Wed, 5 Mar 2025 14:38:26 +0000 (07:38 -0700)
The parameters set by the set_params call are only applied to the block
device in the start_dev call. So if a device has already been started, a
subsequently issued set_params on that device will not have the desired
effect, and should return an error. There is an existing check for this
- set_params fails on devices in the LIVE state. But this check is not
sufficient to cover the recovery case. In this case, the device will be
in the QUIESCED or FAIL_IO states, so set_params will succeed. But this
success is misleading, because the parameters will not be applied, since
the device has already been started (by a previous ublk server). The bit
UB_STATE_USED is set on completion of the start_dev; use it to detect
and fail set_params commands which arrive too late to be applied (after
start_dev).

Signed-off-by: Uday Shankar <ushankar@purestorage.com>
Fixes: 0aa73170eba5 ("ublk_drv: add SET_PARAMS/GET_PARAMS control command")
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250304-set_params-v1-1-17b5e0887606@purestorage.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/ublk_drv.c

index 529085181f355026bf81c07dfe38d042054a5c61..ca9a67b5b537ac0f8b18a54abb2aafbb7e5742f3 100644 (file)
@@ -2715,9 +2715,12 @@ static int ublk_ctrl_set_params(struct ublk_device *ub,
        if (ph.len > sizeof(struct ublk_params))
                ph.len = sizeof(struct ublk_params);
 
-       /* parameters can only be changed when device isn't live */
        mutex_lock(&ub->mutex);
-       if (ub->dev_info.state == UBLK_S_DEV_LIVE) {
+       if (test_bit(UB_STATE_USED, &ub->state)) {
+               /*
+                * Parameters can only be changed when device hasn't
+                * been started yet
+                */
                ret = -EACCES;
        } else if (copy_from_user(&ub->params, argp, ph.len)) {
                ret = -EFAULT;