Skip to content

Commit 3fccb24

Browse files
YuKuai-huaweikawasaki
authored andcommitted
blk-mq-sched: support request batch dispatching for sq elevator
For dispatch_request method, current behavior is dispatching one request at a time. In the case of multiple dispatching contexts, This behavior, on the one hand, introduce intense lock contention: t1: t2: t3: lock lock lock // grab lock ops.dispatch_request unlock // grab lock ops.dispatch_request unlock // grab lock ops.dispatch_request unlock on the other hand, messing up the requests dispatching order: t1: lock rq1 = ops.dispatch_request unlock t2: lock rq2 = ops.dispatch_request unlock lock rq3 = ops.dispatch_request unlock lock rq4 = ops.dispatch_request unlock //rq1,rq3 issue to disk // rq2, rq4 issue to disk In this case, the elevator dispatch order is rq 1-2-3-4, however, such order in disk is rq 1-3-2-4, the order for rq2 and rq3 is inversed. Fix those problems by introducing elevator_dispatch_requests(), this helper will grab the lock and dispatch a batch of requests while holding the lock. Signed-off-by: Yu Kuai <[email protected]>
1 parent 585bc36 commit 3fccb24

2 files changed

Lines changed: 78 additions & 4 deletions

File tree

block/blk-mq-sched.c

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,55 @@ static bool elevator_can_dispatch(struct sched_dispatch_ctx *ctx)
101101
return true;
102102
}
103103

104+
static void elevator_dispatch_requests(struct sched_dispatch_ctx *ctx)
105+
{
106+
bool has_get_budget = ctx->q->mq_ops->get_budget != NULL;
107+
int budget_token[BUDGET_TOKEN_BATCH];
108+
int count = ctx->q->nr_requests;
109+
int i;
110+
111+
while (true) {
112+
if (!elevator_can_dispatch(ctx))
113+
return;
114+
115+
if (has_get_budget) {
116+
count = blk_mq_get_dispatch_budgets(ctx->q, budget_token);
117+
if (count <= 0)
118+
return;
119+
}
120+
121+
spin_lock_irq(&ctx->e->lock);
122+
for (i = 0; i < count; ++i) {
123+
struct request *rq =
124+
ctx->e->type->ops.dispatch_request(ctx->hctx);
125+
126+
if (!rq) {
127+
ctx->run_queue = true;
128+
goto err_free_budgets;
129+
}
130+
131+
if (has_get_budget)
132+
blk_mq_set_rq_budget_token(rq, budget_token[i]);
133+
list_add_tail(&rq->queuelist, &ctx->rq_list);
134+
ctx->count++;
135+
if (rq->mq_hctx != ctx->hctx)
136+
ctx->multi_hctxs = true;
137+
138+
if (!blk_mq_get_driver_tag(rq)) {
139+
i++;
140+
goto err_free_budgets;
141+
}
142+
}
143+
spin_unlock_irq(&ctx->e->lock);
144+
}
145+
146+
err_free_budgets:
147+
spin_unlock_irq(&ctx->e->lock);
148+
if (has_get_budget)
149+
for (; i < count; ++i)
150+
blk_mq_put_dispatch_budget(ctx->q, budget_token[i]);
151+
}
152+
104153
static bool elevator_dispatch_one_request(struct sched_dispatch_ctx *ctx)
105154
{
106155
bool sq_sched = blk_queue_sq_sched(ctx->q);
@@ -213,10 +262,14 @@ static int __blk_mq_do_dispatch_sched(struct blk_mq_hw_ctx *hctx)
213262
else
214263
max_dispatch = hctx->queue->nr_requests;
215264

216-
do {
217-
if (!elevator_dispatch_one_request(&ctx))
218-
break;
219-
} while (ctx.count < max_dispatch);
265+
if (!hctx->dispatch_busy && blk_queue_sq_sched(ctx.q))
266+
elevator_dispatch_requests(&ctx);
267+
else {
268+
do {
269+
if (!elevator_dispatch_one_request(&ctx))
270+
break;
271+
} while (ctx.count < max_dispatch);
272+
}
220273

221274
return elevator_finish_dispatch(&ctx);
222275
}

block/blk-mq.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ enum {
3737
};
3838

3939
#define BLK_MQ_CPU_WORK_BATCH (8)
40+
#define BUDGET_TOKEN_BATCH (8)
4041

4142
typedef unsigned int __bitwise blk_insert_t;
4243
#define BLK_MQ_INSERT_AT_HEAD ((__force blk_insert_t)0x01)
@@ -262,6 +263,26 @@ static inline int blk_mq_get_dispatch_budget(struct request_queue *q)
262263
return 0;
263264
}
264265

266+
static inline int blk_mq_get_dispatch_budgets(struct request_queue *q,
267+
int *budget_token)
268+
{
269+
int count = 0;
270+
271+
while (count < BUDGET_TOKEN_BATCH) {
272+
int token = 0;
273+
274+
if (q->mq_ops->get_budget)
275+
token = q->mq_ops->get_budget(q);
276+
277+
if (token < 0)
278+
return count;
279+
280+
budget_token[count++] = token;
281+
}
282+
283+
return count;
284+
}
285+
265286
static inline void blk_mq_set_rq_budget_token(struct request *rq, int token)
266287
{
267288
if (token < 0)

0 commit comments

Comments
 (0)