Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions drivers/block/ublk_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#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_CMD_QUIESCE_DEV _IOC_NR(UBLK_U_CMD_QUIESCE_DEV)
#define UBLK_CMD_TRY_STOP_DEV _IOC_NR(UBLK_U_CMD_TRY_STOP_DEV)

#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)
Expand All @@ -73,7 +74,8 @@
| UBLK_F_AUTO_BUF_REG \
| UBLK_F_QUIESCE \
| UBLK_F_PER_IO_DAEMON \
| UBLK_F_BUF_REG_OFF_DAEMON)
| UBLK_F_BUF_REG_OFF_DAEMON \
| UBLK_F_SAFE_STOP_DEV)

#define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \
| UBLK_F_USER_RECOVERY_REISSUE \
Expand Down Expand Up @@ -239,6 +241,8 @@ struct ublk_device {
struct delayed_work exit_work;
struct work_struct partition_scan_work;

bool block_open; /* protected by open_mutex */

struct ublk_queue *queues[];
};

Expand Down Expand Up @@ -919,6 +923,9 @@ static int ublk_open(struct gendisk *disk, blk_mode_t mode)
return -EPERM;
}

if (ub->block_open)
return -EBUSY;

return 0;
}

Expand Down Expand Up @@ -3188,7 +3195,8 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE |
UBLK_F_URING_CMD_COMP_IN_TASK |
UBLK_F_PER_IO_DAEMON |
UBLK_F_BUF_REG_OFF_DAEMON;
UBLK_F_BUF_REG_OFF_DAEMON |
UBLK_F_SAFE_STOP_DEV;

/* GET_DATA isn't needed any more with USER_COPY or ZERO COPY */
if (ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY |
Expand Down Expand Up @@ -3304,10 +3312,37 @@ static inline void ublk_ctrl_cmd_dump(struct io_uring_cmd *cmd)
header->data[0], header->addr, header->len);
}

static int ublk_ctrl_stop_dev(struct ublk_device *ub)
static void ublk_ctrl_stop_dev(struct ublk_device *ub)
{
ublk_stop_dev(ub);
return 0;
}

static int ublk_ctrl_try_stop_dev(struct ublk_device *ub)
{
struct gendisk *disk;
int ret = 0;

disk = ublk_get_disk(ub);
if (!disk)
return -ENODEV;

mutex_lock(&disk->open_mutex);
if (disk_openers(disk) > 0) {
ret = -EBUSY;
goto unlock;
}
ub->block_open = true;
/* release open_mutex as del_gendisk() will reacquire it */
mutex_unlock(&disk->open_mutex);

ublk_ctrl_stop_dev(ub);
goto out;

unlock:
mutex_unlock(&disk->open_mutex);
out:
ublk_put_disk(disk);
return ret;
}

static int ublk_ctrl_get_dev_info(struct ublk_device *ub,
Expand Down Expand Up @@ -3705,6 +3740,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub,
case UBLK_CMD_END_USER_RECOVERY:
case UBLK_CMD_UPDATE_SIZE:
case UBLK_CMD_QUIESCE_DEV:
case UBLK_CMD_TRY_STOP_DEV:
mask = MAY_READ | MAY_WRITE;
break;
default:
Expand Down Expand Up @@ -3780,7 +3816,8 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
ret = ublk_ctrl_start_dev(ub, header);
break;
case UBLK_CMD_STOP_DEV:
ret = ublk_ctrl_stop_dev(ub);
ublk_ctrl_stop_dev(ub);
ret = 0;
break;
case UBLK_CMD_GET_DEV_INFO:
case UBLK_CMD_GET_DEV_INFO2:
Expand Down Expand Up @@ -3817,6 +3854,9 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
case UBLK_CMD_QUIESCE_DEV:
ret = ublk_ctrl_quiesce_dev(ub, header);
break;
case UBLK_CMD_TRY_STOP_DEV:
ret = ublk_ctrl_try_stop_dev(ub);
break;
default:
ret = -EOPNOTSUPP;
break;
Expand Down
9 changes: 8 additions & 1 deletion include/uapi/linux/ublk_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@
_IOWR('u', 0x15, struct ublksrv_ctrl_cmd)
#define UBLK_U_CMD_QUIESCE_DEV \
_IOWR('u', 0x16, struct ublksrv_ctrl_cmd)

#define UBLK_U_CMD_TRY_STOP_DEV \
_IOWR('u', 0x17, struct ublksrv_ctrl_cmd)
/*
* 64bits are enough now, and it should be easy to extend in case of
* running out of feature flags
Expand Down Expand Up @@ -311,6 +312,12 @@
*/
#define UBLK_F_BUF_REG_OFF_DAEMON (1ULL << 14)

/*
* The device supports the UBLK_CMD_TRY_STOP_DEV command, which
* allows stopping the device only if there are no openers.
*/
#define UBLK_F_SAFE_STOP_DEV (1ULL << 17)

/* device state */
#define UBLK_S_DEV_DEAD 0
#define UBLK_S_DEV_LIVE 1
Expand Down
1 change: 1 addition & 0 deletions tools/testing/selftests/ublk/kublk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1454,6 +1454,7 @@ static int cmd_dev_get_features(void)
FEAT_NAME(UBLK_F_QUIESCE),
FEAT_NAME(UBLK_F_PER_IO_DAEMON),
FEAT_NAME(UBLK_F_BUF_REG_OFF_DAEMON),
FEAT_NAME(UBLK_F_SAFE_STOP_DEV),
};
struct ublk_dev *dev;
__u64 features = 0;
Expand Down
Loading