Skip to content

Commit 5700f69

Browse files
damien-lemoalaxboe
authored andcommitted
mq-deadline: Introduce zone locking support
Introduce zone write locking to avoid write request reordering with zoned block devices. This is achieved using a finer selection of the next request to dispatch: 1) Any non-write request is always allowed to proceed. 2) Any write to a conventional zone is always allowed to proceed. 3) For a write to a sequential zone, the zone lock is first checked. a) If the zone is not locked, the write is allowed to proceed after its target zone is locked. b) If the zone is locked, the write request is skipped and the next request in the dispatch queue tested (back to step 1). For a write request that has locked its target zone, the zone is unlocked either when the request completes with a call to the method deadline_request_completed() or when the request is requeued using dd_insert_request(). Requests targeting a locked zone are always left in the scheduler queue to preserve the lba ordering for write requests. If no write request can be dispatched, allow reads to be dispatched even if the write batch is not done. If the device used is not a zoned block device, or if zoned block device support is disabled, this patch does not modify mq-deadline behavior. Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent bf09ce5 commit 5700f69

File tree

1 file changed

+86
-3
lines changed

1 file changed

+86
-3
lines changed

block/mq-deadline.c

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ struct deadline_data {
5959
int front_merges;
6060

6161
spinlock_t lock;
62+
spinlock_t zone_lock;
6263
struct list_head dispatch;
6364
};
6465

@@ -198,13 +199,33 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
198199
static struct request *
199200
deadline_fifo_request(struct deadline_data *dd, int data_dir)
200201
{
202+
struct request *rq;
203+
unsigned long flags;
204+
201205
if (WARN_ON_ONCE(data_dir != READ && data_dir != WRITE))
202206
return NULL;
203207

204208
if (list_empty(&dd->fifo_list[data_dir]))
205209
return NULL;
206210

207-
return rq_entry_fifo(dd->fifo_list[data_dir].next);
211+
rq = rq_entry_fifo(dd->fifo_list[data_dir].next);
212+
if (data_dir == READ || !blk_queue_is_zoned(rq->q))
213+
return rq;
214+
215+
/*
216+
* Look for a write request that can be dispatched, that is one with
217+
* an unlocked target zone.
218+
*/
219+
spin_lock_irqsave(&dd->zone_lock, flags);
220+
list_for_each_entry(rq, &dd->fifo_list[WRITE], queuelist) {
221+
if (blk_req_can_dispatch_to_zone(rq))
222+
goto out;
223+
}
224+
rq = NULL;
225+
out:
226+
spin_unlock_irqrestore(&dd->zone_lock, flags);
227+
228+
return rq;
208229
}
209230

210231
/*
@@ -214,10 +235,32 @@ deadline_fifo_request(struct deadline_data *dd, int data_dir)
214235
static struct request *
215236
deadline_next_request(struct deadline_data *dd, int data_dir)
216237
{
238+
struct request *rq;
239+
unsigned long flags;
240+
217241
if (WARN_ON_ONCE(data_dir != READ && data_dir != WRITE))
218242
return NULL;
219243

220-
return dd->next_rq[data_dir];
244+
rq = dd->next_rq[data_dir];
245+
if (!rq)
246+
return NULL;
247+
248+
if (data_dir == READ || !blk_queue_is_zoned(rq->q))
249+
return rq;
250+
251+
/*
252+
* Look for a write request that can be dispatched, that is one with
253+
* an unlocked target zone.
254+
*/
255+
spin_lock_irqsave(&dd->zone_lock, flags);
256+
while (rq) {
257+
if (blk_req_can_dispatch_to_zone(rq))
258+
break;
259+
rq = deadline_latter_request(rq);
260+
}
261+
spin_unlock_irqrestore(&dd->zone_lock, flags);
262+
263+
return rq;
221264
}
222265

223266
/*
@@ -259,7 +302,8 @@ static struct request *__dd_dispatch_request(struct blk_mq_hw_ctx *hctx)
259302
if (reads) {
260303
BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[READ]));
261304

262-
if (writes && (dd->starved++ >= dd->writes_starved))
305+
if (deadline_fifo_request(dd, WRITE) &&
306+
(dd->starved++ >= dd->writes_starved))
263307
goto dispatch_writes;
264308

265309
data_dir = READ;
@@ -304,6 +348,13 @@ static struct request *__dd_dispatch_request(struct blk_mq_hw_ctx *hctx)
304348
rq = next_rq;
305349
}
306350

351+
/*
352+
* For a zoned block device, if we only have writes queued and none of
353+
* them can be dispatched, rq will be NULL.
354+
*/
355+
if (!rq)
356+
return NULL;
357+
307358
dd->batching = 0;
308359

309360
dispatch_request:
@@ -313,6 +364,10 @@ static struct request *__dd_dispatch_request(struct blk_mq_hw_ctx *hctx)
313364
dd->batching++;
314365
deadline_move_request(dd, rq);
315366
done:
367+
/*
368+
* If the request needs its target zone locked, do it.
369+
*/
370+
blk_req_zone_write_lock(rq);
316371
rq->rq_flags |= RQF_STARTED;
317372
return rq;
318373
}
@@ -368,6 +423,7 @@ static int dd_init_queue(struct request_queue *q, struct elevator_type *e)
368423
dd->front_merges = 1;
369424
dd->fifo_batch = fifo_batch;
370425
spin_lock_init(&dd->lock);
426+
spin_lock_init(&dd->zone_lock);
371427
INIT_LIST_HEAD(&dd->dispatch);
372428

373429
q->elevator = eq;
@@ -424,6 +480,12 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
424480
struct deadline_data *dd = q->elevator->elevator_data;
425481
const int data_dir = rq_data_dir(rq);
426482

483+
/*
484+
* This may be a requeue of a write request that has locked its
485+
* target zone. If it is the case, this releases the zone lock.
486+
*/
487+
blk_req_zone_write_unlock(rq);
488+
427489
if (blk_mq_sched_try_insert_merge(q, rq))
428490
return;
429491

@@ -468,6 +530,26 @@ static void dd_insert_requests(struct blk_mq_hw_ctx *hctx,
468530
spin_unlock(&dd->lock);
469531
}
470532

533+
/*
534+
* For zoned block devices, write unlock the target zone of
535+
* completed write requests. Do this while holding the zone lock
536+
* spinlock so that the zone is never unlocked while deadline_fifo_request()
537+
* while deadline_next_request() are executing.
538+
*/
539+
static void dd_completed_request(struct request *rq)
540+
{
541+
struct request_queue *q = rq->q;
542+
543+
if (blk_queue_is_zoned(q)) {
544+
struct deadline_data *dd = q->elevator->elevator_data;
545+
unsigned long flags;
546+
547+
spin_lock_irqsave(&dd->zone_lock, flags);
548+
blk_req_zone_write_unlock(rq);
549+
spin_unlock_irqrestore(&dd->zone_lock, flags);
550+
}
551+
}
552+
471553
static bool dd_has_work(struct blk_mq_hw_ctx *hctx)
472554
{
473555
struct deadline_data *dd = hctx->queue->elevator->elevator_data;
@@ -669,6 +751,7 @@ static struct elevator_type mq_deadline = {
669751
.ops.mq = {
670752
.insert_requests = dd_insert_requests,
671753
.dispatch_request = dd_dispatch_request,
754+
.completed_request = dd_completed_request,
672755
.next_request = elv_rb_latter_request,
673756
.former_request = elv_rb_former_request,
674757
.bio_merge = dd_bio_merge,

0 commit comments

Comments
 (0)