Skip to content

Commit 1f6540e

Browse files
keithbuschaxboe
authored andcommitted
ublk: zc register/unregister bvec
Provide new operations for the user to request mapping an active request to an io uring instance's buf_table. The user has to provide the index it wants to install the buffer. A reference count is taken on the request to ensure it can't be completed while it is active in a ring's buf_table. Signed-off-by: Keith Busch <kbusch@kernel.org> Link: https://lore.kernel.org/r/20250227223916.143006-6-kbusch@meta.com Reviewed-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 27cb27b commit 1f6540e

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

drivers/block/ublk_drv.c

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
/* private ioctl command mirror */
5252
#define UBLK_CMD_DEL_DEV_ASYNC _IOC_NR(UBLK_U_CMD_DEL_DEV_ASYNC)
5353

54+
#define UBLK_IO_REGISTER_IO_BUF _IOC_NR(UBLK_U_IO_REGISTER_IO_BUF)
55+
#define UBLK_IO_UNREGISTER_IO_BUF _IOC_NR(UBLK_U_IO_UNREGISTER_IO_BUF)
56+
5457
/* All UBLK_F_* have to be included into UBLK_F_ALL */
5558
#define UBLK_F_ALL (UBLK_F_SUPPORT_ZERO_COPY \
5659
| UBLK_F_URING_CMD_COMP_IN_TASK \
@@ -196,12 +199,14 @@ struct ublk_params_header {
196199

197200
static bool ublk_abort_requests(struct ublk_device *ub, struct ublk_queue *ubq);
198201

202+
static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
203+
struct ublk_queue *ubq, int tag, size_t offset);
199204
static inline unsigned int ublk_req_build_flags(struct request *req);
200205
static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq,
201206
int tag);
202207
static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub)
203208
{
204-
return ub->dev_info.flags & UBLK_F_USER_COPY;
209+
return ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
205210
}
206211

207212
static inline bool ublk_dev_is_zoned(const struct ublk_device *ub)
@@ -581,7 +586,7 @@ static void ublk_apply_params(struct ublk_device *ub)
581586

582587
static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
583588
{
584-
return ubq->flags & UBLK_F_USER_COPY;
589+
return ubq->flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY);
585590
}
586591

587592
static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
@@ -1747,6 +1752,45 @@ static inline void ublk_prep_cancel(struct io_uring_cmd *cmd,
17471752
io_uring_cmd_mark_cancelable(cmd, issue_flags);
17481753
}
17491754

1755+
static void ublk_io_release(void *priv)
1756+
{
1757+
struct request *rq = priv;
1758+
struct ublk_queue *ubq = rq->mq_hctx->driver_data;
1759+
1760+
ublk_put_req_ref(ubq, rq);
1761+
}
1762+
1763+
static int ublk_register_io_buf(struct io_uring_cmd *cmd,
1764+
struct ublk_queue *ubq, unsigned int tag,
1765+
const struct ublksrv_io_cmd *ub_cmd,
1766+
unsigned int issue_flags)
1767+
{
1768+
struct ublk_device *ub = cmd->file->private_data;
1769+
int index = (int)ub_cmd->addr, ret;
1770+
struct request *req;
1771+
1772+
req = __ublk_check_and_get_req(ub, ubq, tag, 0);
1773+
if (!req)
1774+
return -EINVAL;
1775+
1776+
ret = io_buffer_register_bvec(cmd, req, ublk_io_release, index,
1777+
issue_flags);
1778+
if (ret) {
1779+
ublk_put_req_ref(ubq, req);
1780+
return ret;
1781+
}
1782+
1783+
return 0;
1784+
}
1785+
1786+
static int ublk_unregister_io_buf(struct io_uring_cmd *cmd,
1787+
const struct ublksrv_io_cmd *ub_cmd,
1788+
unsigned int issue_flags)
1789+
{
1790+
io_buffer_unregister_bvec(cmd, ub_cmd->addr, issue_flags);
1791+
return 0;
1792+
}
1793+
17501794
static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
17511795
unsigned int issue_flags,
17521796
const struct ublksrv_io_cmd *ub_cmd)
@@ -1798,6 +1842,10 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
17981842

17991843
ret = -EINVAL;
18001844
switch (_IOC_NR(cmd_op)) {
1845+
case UBLK_IO_REGISTER_IO_BUF:
1846+
return ublk_register_io_buf(cmd, ubq, tag, ub_cmd, issue_flags);
1847+
case UBLK_IO_UNREGISTER_IO_BUF:
1848+
return ublk_unregister_io_buf(cmd, ub_cmd, issue_flags);
18011849
case UBLK_IO_FETCH_REQ:
18021850
/* UBLK_IO_FETCH_REQ is only allowed before queue is setup */
18031851
if (ublk_queue_ready(ubq)) {
@@ -2459,7 +2507,7 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
24592507
* buffer by pwrite() to ublk char device, which can't be
24602508
* used for unprivileged device
24612509
*/
2462-
if (info.flags & UBLK_F_USER_COPY)
2510+
if (info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY))
24632511
return -EINVAL;
24642512
}
24652513

@@ -2527,9 +2575,6 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
25272575
goto out_free_dev_number;
25282576
}
25292577

2530-
/* We are not ready to support zero copy */
2531-
ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY;
2532-
25332578
ub->dev_info.nr_hw_queues = min_t(unsigned int,
25342579
ub->dev_info.nr_hw_queues, nr_cpu_ids);
25352580
ublk_align_max_io_size(ub);
@@ -2860,7 +2905,7 @@ static int ublk_ctrl_get_features(struct io_uring_cmd *cmd)
28602905
{
28612906
const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe);
28622907
void __user *argp = (void __user *)(unsigned long)header->addr;
2863-
u64 features = UBLK_F_ALL & ~UBLK_F_SUPPORT_ZERO_COPY;
2908+
u64 features = UBLK_F_ALL;
28642909

28652910
if (header->len != UBLK_FEATURES_LEN || !header->addr)
28662911
return -EINVAL;

include/uapi/linux/ublk_cmd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@
9494
_IOWR('u', UBLK_IO_COMMIT_AND_FETCH_REQ, struct ublksrv_io_cmd)
9595
#define UBLK_U_IO_NEED_GET_DATA \
9696
_IOWR('u', UBLK_IO_NEED_GET_DATA, struct ublksrv_io_cmd)
97+
#define UBLK_U_IO_REGISTER_IO_BUF \
98+
_IOWR('u', 0x23, struct ublksrv_io_cmd)
99+
#define UBLK_U_IO_UNREGISTER_IO_BUF \
100+
_IOWR('u', 0x24, struct ublksrv_io_cmd)
97101

98102
/* only ABORT means that no re-fetch */
99103
#define UBLK_IO_RES_OK 0

0 commit comments

Comments
 (0)