Skip to content

Commit cc90bc3

Browse files
YuKuai-huaweikawasaki
authored andcommitted
block, bfq: don't grab queue_lock from io path
Currently issue io can grab queue_lock three times from bfq_bio_merge(), bfq_limit_depth() and bfq_prepare_request(), the queue_lock is not necessary if icq is already created: - queue_usage_counter is already grabbed and queue won't exist; - current thread won't exist; - if other thread is allocating and inserting new icq to ioc->icq_tree, rcu can be used to protect lookup icq from the raidx tree, it's safe to use extracted icq until queue or current thread exit; If ioc or icq is not created, then bfq_prepare_request() will create it, which means the task is issuing io to queue the first time, this can consider a slow path and queue_lock will still be held to protect inserting allocated icq to ioc->icq_tree. Signed-off-by: Yu Kuai <[email protected]>
1 parent 3c8e29e commit cc90bc3

3 files changed

Lines changed: 46 additions & 23 deletions

File tree

block/bfq-iosched.c

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -454,17 +454,13 @@ static struct bfq_io_cq *icq_to_bic(struct io_cq *icq)
454454
*/
455455
static struct bfq_io_cq *bfq_bic_lookup(struct request_queue *q)
456456
{
457-
struct bfq_io_cq *icq;
458-
unsigned long flags;
459-
460-
if (!current->io_context)
461-
return NULL;
457+
struct io_cq *icq;
462458

463-
spin_lock_irqsave(&q->queue_lock, flags);
464-
icq = icq_to_bic(ioc_lookup_icq(q));
465-
spin_unlock_irqrestore(&q->queue_lock, flags);
459+
rcu_read_lock();
460+
icq = ioc_lookup_icq_rcu(q);
461+
rcu_read_unlock();
466462

467-
return icq;
463+
return icq_to_bic(icq);
468464
}
469465

470466
/*
@@ -2456,16 +2452,10 @@ static void bfq_remove_request(struct request_queue *q,
24562452
static bool bfq_bio_merge(struct request_queue *q, struct bio *bio,
24572453
unsigned int nr_segs)
24582454
{
2455+
/* bic will not be freed until current or elevator exit */
2456+
struct bfq_io_cq *bic = bfq_bic_lookup(q);
24592457
struct bfq_data *bfqd = q->elevator->elevator_data;
24602458
struct request *free = NULL;
2461-
/*
2462-
* bfq_bic_lookup grabs the queue_lock: invoke it now and
2463-
* store its return value for later use, to avoid nesting
2464-
* queue_lock inside the bfqd->lock. We assume that the bic
2465-
* returned by bfq_bic_lookup does not go away before
2466-
* bfqd->lock is taken.
2467-
*/
2468-
struct bfq_io_cq *bic = bfq_bic_lookup(q);
24692459
bool ret;
24702460

24712461
spin_lock_irq(&bfqd->lock);

block/blk-ioc.c

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ int __copy_io(unsigned long clone_flags, struct task_struct *tsk)
314314
* Look up io_cq associated with @ioc - @q pair from @ioc. Must be called
315315
* with @q->queue_lock held.
316316
*/
317-
struct io_cq *ioc_lookup_icq(struct request_queue *q)
317+
static struct io_cq *ioc_lookup_icq(struct request_queue *q)
318318
{
319319
struct io_context *ioc = current->io_context;
320320
struct io_cq *icq;
@@ -341,7 +341,40 @@ struct io_cq *ioc_lookup_icq(struct request_queue *q)
341341
rcu_read_unlock();
342342
return icq;
343343
}
344-
EXPORT_SYMBOL(ioc_lookup_icq);
344+
345+
/**
346+
* ioc_lookup_icq_rcu - lookup io_cq from ioc in io path
347+
* @q: the associated request_queue
348+
*
349+
* Look up io_cq associated with @ioc - @q pair from @ioc. Must be called
350+
* from io path, either return NULL if current issue io to @q for the first
351+
* time, or return a valid icq.
352+
*/
353+
struct io_cq *ioc_lookup_icq_rcu(struct request_queue *q)
354+
{
355+
struct io_context *ioc = current->io_context;
356+
struct io_cq *icq;
357+
358+
WARN_ON_ONCE(percpu_ref_is_zero(&q->q_usage_counter));
359+
360+
if (!ioc)
361+
return NULL;
362+
363+
icq = rcu_dereference(ioc->icq_hint);
364+
if (icq && icq->q == q)
365+
return icq;
366+
367+
icq = radix_tree_lookup(&ioc->icq_tree, q->id);
368+
if (!icq)
369+
return NULL;
370+
371+
if (WARN_ON_ONCE(icq->q != q))
372+
return NULL;
373+
374+
rcu_assign_pointer(ioc->icq_hint, icq);
375+
return icq;
376+
}
377+
EXPORT_SYMBOL(ioc_lookup_icq_rcu);
345378

346379
/**
347380
* ioc_create_icq - create and link io_cq
@@ -420,9 +453,9 @@ struct io_cq *ioc_find_get_icq(struct request_queue *q)
420453
} else {
421454
get_io_context(ioc);
422455

423-
spin_lock_irq(&q->queue_lock);
424-
icq = ioc_lookup_icq(q);
425-
spin_unlock_irq(&q->queue_lock);
456+
rcu_read_lock();
457+
icq = ioc_lookup_icq_rcu(q);
458+
rcu_read_unlock();
426459
}
427460

428461
if (!icq) {

block/blk.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ static inline void req_set_nomerge(struct request_queue *q, struct request *req)
451451
* Internal io_context interface
452452
*/
453453
struct io_cq *ioc_find_get_icq(struct request_queue *q);
454-
struct io_cq *ioc_lookup_icq(struct request_queue *q);
454+
struct io_cq *ioc_lookup_icq_rcu(struct request_queue *q);
455455
#ifdef CONFIG_BLK_ICQ
456456
void ioc_clear_queue(struct request_queue *q);
457457
#else

0 commit comments

Comments
 (0)