Skip to content

Commit d701cb4

Browse files
yoavcohkawasaki
authored andcommitted
ublk: add UBLK_CMD_TRY_STOP_DEV command
This command is similar to UBLK_CMD_STOP_DEV, but it only stops the device if there are no active openers for the ublk block device. If the device is busy, the command returns -EBUSY instead of disrupting active clients. This allows safe, non-destructive stopping. Advertise UBLK_CMD_TRY_STOP_DEV support via UBLK_F_SAFE_STOP_DEV feature flag. Signed-off-by: Yoav Cohen <[email protected]> Reviewed-by: Ming Lei <[email protected]> Signed-off-by: Ming Lei <[email protected]>
1 parent 5d09d20 commit d701cb4

File tree

3 files changed

+51
-3
lines changed

3 files changed

+51
-3
lines changed

drivers/block/ublk_drv.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#define UBLK_CMD_DEL_DEV_ASYNC _IOC_NR(UBLK_U_CMD_DEL_DEV_ASYNC)
5555
#define UBLK_CMD_UPDATE_SIZE _IOC_NR(UBLK_U_CMD_UPDATE_SIZE)
5656
#define UBLK_CMD_QUIESCE_DEV _IOC_NR(UBLK_U_CMD_QUIESCE_DEV)
57+
#define UBLK_CMD_TRY_STOP_DEV _IOC_NR(UBLK_U_CMD_TRY_STOP_DEV)
5758

5859
#define UBLK_IO_REGISTER_IO_BUF _IOC_NR(UBLK_U_IO_REGISTER_IO_BUF)
5960
#define UBLK_IO_UNREGISTER_IO_BUF _IOC_NR(UBLK_U_IO_UNREGISTER_IO_BUF)
@@ -73,7 +74,8 @@
7374
| UBLK_F_AUTO_BUF_REG \
7475
| UBLK_F_QUIESCE \
7576
| UBLK_F_PER_IO_DAEMON \
76-
| UBLK_F_BUF_REG_OFF_DAEMON)
77+
| UBLK_F_BUF_REG_OFF_DAEMON \
78+
| UBLK_F_SAFE_STOP_DEV)
7779

7880
#define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \
7981
| UBLK_F_USER_RECOVERY_REISSUE \
@@ -239,6 +241,8 @@ struct ublk_device {
239241
struct delayed_work exit_work;
240242
struct work_struct partition_scan_work;
241243

244+
bool block_open; /* protected by open_mutex */
245+
242246
struct ublk_queue *queues[];
243247
};
244248

@@ -919,6 +923,9 @@ static int ublk_open(struct gendisk *disk, blk_mode_t mode)
919923
return -EPERM;
920924
}
921925

926+
if (ub->block_open)
927+
return -EBUSY;
928+
922929
return 0;
923930
}
924931

@@ -3188,7 +3195,8 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
31883195
ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE |
31893196
UBLK_F_URING_CMD_COMP_IN_TASK |
31903197
UBLK_F_PER_IO_DAEMON |
3191-
UBLK_F_BUF_REG_OFF_DAEMON;
3198+
UBLK_F_BUF_REG_OFF_DAEMON |
3199+
UBLK_F_SAFE_STOP_DEV;
31923200

31933201
/* GET_DATA isn't needed any more with USER_COPY or ZERO COPY */
31943202
if (ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY |
@@ -3309,6 +3317,34 @@ static void ublk_ctrl_stop_dev(struct ublk_device *ub)
33093317
ublk_stop_dev(ub);
33103318
}
33113319

3320+
static int ublk_ctrl_try_stop_dev(struct ublk_device *ub)
3321+
{
3322+
struct gendisk *disk;
3323+
int ret = 0;
3324+
3325+
disk = ublk_get_disk(ub);
3326+
if (!disk)
3327+
return -ENODEV;
3328+
3329+
mutex_lock(&disk->open_mutex);
3330+
if (disk_openers(disk) > 0) {
3331+
ret = -EBUSY;
3332+
goto unlock;
3333+
}
3334+
ub->block_open = true;
3335+
/* release open_mutex as del_gendisk() will reacquire it */
3336+
mutex_unlock(&disk->open_mutex);
3337+
3338+
ublk_ctrl_stop_dev(ub);
3339+
goto out;
3340+
3341+
unlock:
3342+
mutex_unlock(&disk->open_mutex);
3343+
out:
3344+
ublk_put_disk(disk);
3345+
return ret;
3346+
}
3347+
33123348
static int ublk_ctrl_get_dev_info(struct ublk_device *ub,
33133349
const struct ublksrv_ctrl_cmd *header)
33143350
{
@@ -3704,6 +3740,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub,
37043740
case UBLK_CMD_END_USER_RECOVERY:
37053741
case UBLK_CMD_UPDATE_SIZE:
37063742
case UBLK_CMD_QUIESCE_DEV:
3743+
case UBLK_CMD_TRY_STOP_DEV:
37073744
mask = MAY_READ | MAY_WRITE;
37083745
break;
37093746
default:
@@ -3817,6 +3854,9 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
38173854
case UBLK_CMD_QUIESCE_DEV:
38183855
ret = ublk_ctrl_quiesce_dev(ub, header);
38193856
break;
3857+
case UBLK_CMD_TRY_STOP_DEV:
3858+
ret = ublk_ctrl_try_stop_dev(ub);
3859+
break;
38203860
default:
38213861
ret = -EOPNOTSUPP;
38223862
break;

include/uapi/linux/ublk_cmd.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
_IOWR('u', 0x15, struct ublksrv_ctrl_cmd)
5656
#define UBLK_U_CMD_QUIESCE_DEV \
5757
_IOWR('u', 0x16, struct ublksrv_ctrl_cmd)
58-
58+
#define UBLK_U_CMD_TRY_STOP_DEV \
59+
_IOWR('u', 0x17, struct ublksrv_ctrl_cmd)
5960
/*
6061
* 64bits are enough now, and it should be easy to extend in case of
6162
* running out of feature flags
@@ -311,6 +312,12 @@
311312
*/
312313
#define UBLK_F_BUF_REG_OFF_DAEMON (1ULL << 14)
313314

315+
/*
316+
* The device supports the UBLK_CMD_TRY_STOP_DEV command, which
317+
* allows stopping the device only if there are no openers.
318+
*/
319+
#define UBLK_F_SAFE_STOP_DEV (1ULL << 17)
320+
314321
/* device state */
315322
#define UBLK_S_DEV_DEAD 0
316323
#define UBLK_S_DEV_LIVE 1

tools/testing/selftests/ublk/kublk.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,7 @@ static int cmd_dev_get_features(void)
14541454
FEAT_NAME(UBLK_F_QUIESCE),
14551455
FEAT_NAME(UBLK_F_PER_IO_DAEMON),
14561456
FEAT_NAME(UBLK_F_BUF_REG_OFF_DAEMON),
1457+
FEAT_NAME(UBLK_F_SAFE_STOP_DEV),
14571458
};
14581459
struct ublk_dev *dev;
14591460
__u64 features = 0;

0 commit comments

Comments
 (0)