Skip to content

Commit d796cea

Browse files
Ming Leiaxboe
authored andcommitted
ublk: implement ->queue_rqs()
Implement ->queue_rqs() for improving perf in case of MQ. In this way, we just need to call io_uring_cmd_complete_in_task() once for whole IO batch, then both io_uring and ublk server can get exact batch from ublk frontend. Follows IOPS improvement: - tests tools/testing/selftests/ublk/kublk add -t null -q 2 [-z] fio/t/io_uring -p0 /dev/ublkb0 - results: more than 10% IOPS boost observed Pass all ublk selftests, especially the io dispatch order test. Cc: Uday Shankar <ushankar@purestorage.com> Signed-off-by: Ming Lei <ming.lei@redhat.com> Link: https://lore.kernel.org/r/20250327095123.179113-9-ming.lei@redhat.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 1797020 commit d796cea

File tree

1 file changed

+111
-20
lines changed

1 file changed

+111
-20
lines changed

drivers/block/ublk_drv.c

Lines changed: 111 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,20 @@ struct ublk_rq_data {
8181
};
8282

8383
struct ublk_uring_cmd_pdu {
84+
/*
85+
* Store requests in same batch temporarily for queuing them to
86+
* daemon context.
87+
*
88+
* It should have been stored to request payload, but we do want
89+
* to avoid extra pre-allocation, and uring_cmd payload is always
90+
* free for us
91+
*/
92+
struct request *req_list;
93+
94+
/*
95+
* The following two are valid in this cmd whole lifetime, and
96+
* setup in ublk uring_cmd handler
97+
*/
8498
struct ublk_queue *ubq;
8599
u16 tag;
86100
};
@@ -1170,14 +1184,12 @@ static inline void __ublk_abort_rq(struct ublk_queue *ubq,
11701184
blk_mq_end_request(rq, BLK_STS_IOERR);
11711185
}
11721186

1173-
static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd,
1174-
unsigned int issue_flags)
1187+
static void ublk_dispatch_req(struct ublk_queue *ubq,
1188+
struct io_uring_cmd *cmd,
1189+
struct request *req,
1190+
unsigned int issue_flags)
11751191
{
1176-
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
1177-
struct ublk_queue *ubq = pdu->ubq;
1178-
int tag = pdu->tag;
1179-
struct request *req = blk_mq_tag_to_rq(
1180-
ubq->dev->tag_set.tags[ubq->q_id], tag);
1192+
int tag = req->tag;
11811193
struct ublk_io *io = &ubq->ios[tag];
11821194
unsigned int mapped_bytes;
11831195

@@ -1252,13 +1264,54 @@ static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd,
12521264
ubq_complete_io_cmd(io, UBLK_IO_RES_OK, issue_flags);
12531265
}
12541266

1267+
static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd,
1268+
unsigned int issue_flags)
1269+
{
1270+
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
1271+
struct ublk_queue *ubq = pdu->ubq;
1272+
int tag = pdu->tag;
1273+
struct request *req = blk_mq_tag_to_rq(
1274+
ubq->dev->tag_set.tags[ubq->q_id], tag);
1275+
1276+
ublk_dispatch_req(ubq, cmd, req, issue_flags);
1277+
}
1278+
12551279
static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq)
12561280
{
12571281
struct ublk_io *io = &ubq->ios[rq->tag];
12581282

12591283
io_uring_cmd_complete_in_task(io->cmd, ublk_rq_task_work_cb);
12601284
}
12611285

1286+
static void ublk_cmd_list_tw_cb(struct io_uring_cmd *cmd,
1287+
unsigned int issue_flags)
1288+
{
1289+
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
1290+
struct request *rq = pdu->req_list;
1291+
struct ublk_queue *ubq = rq->mq_hctx->driver_data;
1292+
struct request *next;
1293+
1294+
while (rq) {
1295+
struct ublk_io *io = &ubq->ios[rq->tag];
1296+
1297+
next = rq->rq_next;
1298+
rq->rq_next = NULL;
1299+
ublk_dispatch_req(ubq, io->cmd, rq, issue_flags);
1300+
rq = next;
1301+
}
1302+
}
1303+
1304+
static void ublk_queue_cmd_list(struct ublk_queue *ubq, struct rq_list *l)
1305+
{
1306+
struct request *rq = rq_list_peek(l);
1307+
struct ublk_io *io = &ubq->ios[rq->tag];
1308+
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(io->cmd);
1309+
1310+
pdu->req_list = rq;
1311+
rq_list_init(l);
1312+
io_uring_cmd_complete_in_task(io->cmd, ublk_cmd_list_tw_cb);
1313+
}
1314+
12621315
static enum blk_eh_timer_return ublk_timeout(struct request *rq)
12631316
{
12641317
struct ublk_queue *ubq = rq->mq_hctx->driver_data;
@@ -1297,21 +1350,12 @@ static enum blk_eh_timer_return ublk_timeout(struct request *rq)
12971350
return BLK_EH_RESET_TIMER;
12981351
}
12991352

1300-
static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
1301-
const struct blk_mq_queue_data *bd)
1353+
static blk_status_t ublk_prep_req(struct ublk_queue *ubq, struct request *rq)
13021354
{
1303-
struct ublk_queue *ubq = hctx->driver_data;
1304-
struct request *rq = bd->rq;
13051355
blk_status_t res;
13061356

1307-
if (unlikely(ubq->fail_io)) {
1357+
if (unlikely(ubq->fail_io))
13081358
return BLK_STS_TARGET;
1309-
}
1310-
1311-
/* fill iod to slot in io cmd buffer */
1312-
res = ublk_setup_iod(ubq, rq);
1313-
if (unlikely(res != BLK_STS_OK))
1314-
return BLK_STS_IOERR;
13151359

13161360
/* With recovery feature enabled, force_abort is set in
13171361
* ublk_stop_dev() before calling del_gendisk(). We have to
@@ -1325,6 +1369,29 @@ static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
13251369
if (ublk_nosrv_should_queue_io(ubq) && unlikely(ubq->force_abort))
13261370
return BLK_STS_IOERR;
13271371

1372+
if (unlikely(ubq->canceling))
1373+
return BLK_STS_IOERR;
1374+
1375+
/* fill iod to slot in io cmd buffer */
1376+
res = ublk_setup_iod(ubq, rq);
1377+
if (unlikely(res != BLK_STS_OK))
1378+
return BLK_STS_IOERR;
1379+
1380+
blk_mq_start_request(rq);
1381+
return BLK_STS_OK;
1382+
}
1383+
1384+
static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
1385+
const struct blk_mq_queue_data *bd)
1386+
{
1387+
struct ublk_queue *ubq = hctx->driver_data;
1388+
struct request *rq = bd->rq;
1389+
blk_status_t res;
1390+
1391+
res = ublk_prep_req(ubq, rq);
1392+
if (res != BLK_STS_OK)
1393+
return res;
1394+
13281395
/*
13291396
* ->canceling has to be handled after ->force_abort and ->fail_io
13301397
* is dealt with, otherwise this request may not be failed in case
@@ -1335,12 +1402,35 @@ static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
13351402
return BLK_STS_OK;
13361403
}
13371404

1338-
blk_mq_start_request(bd->rq);
13391405
ublk_queue_cmd(ubq, rq);
1340-
13411406
return BLK_STS_OK;
13421407
}
13431408

1409+
static void ublk_queue_rqs(struct rq_list *rqlist)
1410+
{
1411+
struct rq_list requeue_list = { };
1412+
struct rq_list submit_list = { };
1413+
struct ublk_queue *ubq = NULL;
1414+
struct request *req;
1415+
1416+
while ((req = rq_list_pop(rqlist))) {
1417+
struct ublk_queue *this_q = req->mq_hctx->driver_data;
1418+
1419+
if (ubq && ubq != this_q && !rq_list_empty(&submit_list))
1420+
ublk_queue_cmd_list(ubq, &submit_list);
1421+
ubq = this_q;
1422+
1423+
if (ublk_prep_req(ubq, req) == BLK_STS_OK)
1424+
rq_list_add_tail(&submit_list, req);
1425+
else
1426+
rq_list_add_tail(&requeue_list, req);
1427+
}
1428+
1429+
if (ubq && !rq_list_empty(&submit_list))
1430+
ublk_queue_cmd_list(ubq, &submit_list);
1431+
*rqlist = requeue_list;
1432+
}
1433+
13441434
static int ublk_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
13451435
unsigned int hctx_idx)
13461436
{
@@ -1353,6 +1443,7 @@ static int ublk_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
13531443

13541444
static const struct blk_mq_ops ublk_mq_ops = {
13551445
.queue_rq = ublk_queue_rq,
1446+
.queue_rqs = ublk_queue_rqs,
13561447
.init_hctx = ublk_init_hctx,
13571448
.timeout = ublk_timeout,
13581449
};

0 commit comments

Comments
 (0)