summaryrefslogtreecommitdiffstats
path: root/block/bfq-iosched.c
diff options
context:
space:
mode:
authorPaolo Valente <paolo.valente@linaro.org>2017-04-12 12:23:21 -0400
committerJens Axboe <axboe@fb.com>2017-04-19 10:30:26 -0400
commit6fa3e8d34204d532268ddb4dc5d2a904197c972d (patch)
tree8c94a1696e1f0cf46c69107caf1f936dc4695599 /block/bfq-iosched.c
parente1b2324dd065880a3200098fe3637ac171c296e6 (diff)
block, bfq: remove all get and put of I/O contexts
When a bfq queue is set in service and when it is merged, a reference to the I/O context associated with the queue is taken. This reference is then released when the queue is deselected from service or split. More precisely, the release of the reference is postponed to when the scheduler lock is released, to avoid nesting between the scheduler and the I/O-context lock. In fact, such nesting would lead to deadlocks, because of other code paths that take the same locks in the opposite order. This postponing of I/O-context releases does complicate code. This commit addresses these issue by modifying involved operations in such a way to not need to get the above I/O-context references any more. Then it also removes any get and release of these references. Signed-off-by: Paolo Valente <paolo.valente@linaro.org> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block/bfq-iosched.c')
-rw-r--r--block/bfq-iosched.c143
1 files changed, 23 insertions, 120 deletions
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index b7e3c8653414..30bb8f905733 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -538,8 +538,6 @@ struct bfq_data {
538 538
539 /* bfq_queue in service */ 539 /* bfq_queue in service */
540 struct bfq_queue *in_service_queue; 540 struct bfq_queue *in_service_queue;
541 /* bfq_io_cq (bic) associated with the @in_service_queue */
542 struct bfq_io_cq *in_service_bic;
543 541
544 /* on-disk position of the last served request */ 542 /* on-disk position of the last served request */
545 sector_t last_position; 543 sector_t last_position;
@@ -704,15 +702,6 @@ struct bfq_data {
704 struct bfq_io_cq *bio_bic; 702 struct bfq_io_cq *bio_bic;
705 /* bfqq associated with the task issuing current bio for merging */ 703 /* bfqq associated with the task issuing current bio for merging */
706 struct bfq_queue *bio_bfqq; 704 struct bfq_queue *bio_bfqq;
707
708 /*
709 * io context to put right after bfqd->lock is released. This
710 * filed is used to perform put_io_context, when needed, to
711 * after the scheduler lock has been released, and thus
712 * prevent an ioc->lock from being possibly taken while the
713 * scheduler lock is being held.
714 */
715 struct io_context *ioc_to_put;
716}; 705};
717 706
718enum bfqq_state_flags { 707enum bfqq_state_flags {
@@ -1148,34 +1137,6 @@ static void bfq_schedule_dispatch(struct bfq_data *bfqd)
1148 } 1137 }
1149} 1138}
1150 1139
1151/*
1152 * Next two functions release bfqd->lock and put the io context
1153 * pointed by bfqd->ioc_to_put. This delayed put is used to not risk
1154 * to take an ioc->lock while the scheduler lock is being held.
1155 */
1156static void bfq_unlock_put_ioc(struct bfq_data *bfqd)
1157{
1158 struct io_context *ioc_to_put = bfqd->ioc_to_put;
1159
1160 bfqd->ioc_to_put = NULL;
1161 spin_unlock_irq(&bfqd->lock);
1162
1163 if (ioc_to_put)
1164 put_io_context(ioc_to_put);
1165}
1166
1167static void bfq_unlock_put_ioc_restore(struct bfq_data *bfqd,
1168 unsigned long flags)
1169{
1170 struct io_context *ioc_to_put = bfqd->ioc_to_put;
1171
1172 bfqd->ioc_to_put = NULL;
1173 spin_unlock_irqrestore(&bfqd->lock, flags);
1174
1175 if (ioc_to_put)
1176 put_io_context(ioc_to_put);
1177}
1178
1179/** 1140/**
1180 * bfq_gt - compare two timestamps. 1141 * bfq_gt - compare two timestamps.
1181 * @a: first ts. 1142 * @a: first ts.
@@ -2684,18 +2645,6 @@ static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd)
2684 struct bfq_entity *in_serv_entity = &in_serv_bfqq->entity; 2645 struct bfq_entity *in_serv_entity = &in_serv_bfqq->entity;
2685 struct bfq_entity *entity = in_serv_entity; 2646 struct bfq_entity *entity = in_serv_entity;
2686 2647
2687 if (bfqd->in_service_bic) {
2688 /*
2689 * Schedule the release of a reference to
2690 * bfqd->in_service_bic->icq.ioc to right after the
2691 * scheduler lock is released. This ioc is not
2692 * released immediately, to not risk to possibly take
2693 * an ioc->lock while holding the scheduler lock.
2694 */
2695 bfqd->ioc_to_put = bfqd->in_service_bic->icq.ioc;
2696 bfqd->in_service_bic = NULL;
2697 }
2698
2699 bfq_clear_bfqq_wait_request(in_serv_bfqq); 2648 bfq_clear_bfqq_wait_request(in_serv_bfqq);
2700 hrtimer_try_to_cancel(&bfqd->idle_slice_timer); 2649 hrtimer_try_to_cancel(&bfqd->idle_slice_timer);
2701 bfqd->in_service_queue = NULL; 2650 bfqd->in_service_queue = NULL;
@@ -3495,7 +3444,7 @@ static void bfq_pd_offline(struct blkg_policy_data *pd)
3495 __bfq_deactivate_entity(entity, false); 3444 __bfq_deactivate_entity(entity, false);
3496 bfq_put_async_queues(bfqd, bfqg); 3445 bfq_put_async_queues(bfqd, bfqg);
3497 3446
3498 bfq_unlock_put_ioc_restore(bfqd, flags); 3447 spin_unlock_irqrestore(&bfqd->lock, flags);
3499 /* 3448 /*
3500 * @blkg is going offline and will be ignored by 3449 * @blkg is going offline and will be ignored by
3501 * blkg_[rw]stat_recursive_sum(). Transfer stats to the parent so 3450 * blkg_[rw]stat_recursive_sum(). Transfer stats to the parent so
@@ -5472,20 +5421,18 @@ bfq_setup_merge(struct bfq_queue *bfqq, struct bfq_queue *new_bfqq)
5472 * first time that the requests of some process are redirected to 5421 * first time that the requests of some process are redirected to
5473 * it. 5422 * it.
5474 * 5423 *
5475 * We redirect bfqq to new_bfqq and not the opposite, because we 5424 * We redirect bfqq to new_bfqq and not the opposite, because
5476 * are in the context of the process owning bfqq, hence we have 5425 * we are in the context of the process owning bfqq, thus we
5477 * the io_cq of this process. So we can immediately configure this 5426 * have the io_cq of this process. So we can immediately
5478 * io_cq to redirect the requests of the process to new_bfqq. 5427 * configure this io_cq to redirect the requests of the
5428 * process to new_bfqq. In contrast, the io_cq of new_bfqq is
5429 * not available any more (new_bfqq->bic == NULL).
5479 * 5430 *
5480 * NOTE, even if new_bfqq coincides with the in-service queue, the 5431 * Anyway, even in case new_bfqq coincides with the in-service
5481 * io_cq of new_bfqq is not available, because, if the in-service 5432 * queue, redirecting requests the in-service queue is the
5482 * queue is shared, bfqd->in_service_bic may not point to the 5433 * best option, as we feed the in-service queue with new
5483 * io_cq of the in-service queue. 5434 * requests close to the last request served and, by doing so,
5484 * Redirecting the requests of the process owning bfqq to the 5435 * are likely to increase the throughput.
5485 * currently in-service queue is in any case the best option, as
5486 * we feed the in-service queue with new requests close to the
5487 * last request served and, by doing so, hopefully increase the
5488 * throughput.
5489 */ 5436 */
5490 bfqq->new_bfqq = new_bfqq; 5437 bfqq->new_bfqq = new_bfqq;
5491 new_bfqq->ref += process_refs; 5438 new_bfqq->ref += process_refs;
@@ -5577,8 +5524,8 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq,
5577 5524
5578 in_service_bfqq = bfqd->in_service_queue; 5525 in_service_bfqq = bfqd->in_service_queue;
5579 5526
5580 if (!in_service_bfqq || in_service_bfqq == bfqq || 5527 if (!in_service_bfqq || in_service_bfqq == bfqq
5581 !bfqd->in_service_bic || wr_from_too_long(in_service_bfqq) || 5528 || wr_from_too_long(in_service_bfqq) ||
5582 unlikely(in_service_bfqq == &bfqd->oom_bfqq)) 5529 unlikely(in_service_bfqq == &bfqd->oom_bfqq))
5583 goto check_scheduled; 5530 goto check_scheduled;
5584 5531
@@ -5629,16 +5576,6 @@ static void bfq_bfqq_save_state(struct bfq_queue *bfqq)
5629 bic->saved_wr_cur_max_time = bfqq->wr_cur_max_time; 5576 bic->saved_wr_cur_max_time = bfqq->wr_cur_max_time;
5630} 5577}
5631 5578
5632static void bfq_get_bic_reference(struct bfq_queue *bfqq)
5633{
5634 /*
5635 * If bfqq->bic has a non-NULL value, the bic to which it belongs
5636 * is about to begin using a shared bfq_queue.
5637 */
5638 if (bfqq->bic)
5639 atomic_long_inc(&bfqq->bic->icq.ioc->refcount);
5640}
5641
5642static void 5579static void
5643bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic, 5580bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
5644 struct bfq_queue *bfqq, struct bfq_queue *new_bfqq) 5581 struct bfq_queue *bfqq, struct bfq_queue *new_bfqq)
@@ -5683,12 +5620,6 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
5683 bfqd->wr_busy_queues); 5620 bfqd->wr_busy_queues);
5684 5621
5685 /* 5622 /*
5686 * Grab a reference to the bic, to prevent it from being destroyed
5687 * before being possibly touched by a bfq_split_bfqq().
5688 */
5689 bfq_get_bic_reference(bfqq);
5690 bfq_get_bic_reference(new_bfqq);
5691 /*
5692 * Merge queues (that is, let bic redirect its requests to new_bfqq) 5623 * Merge queues (that is, let bic redirect its requests to new_bfqq)
5693 */ 5624 */
5694 bic_set_bfqq(bic, new_bfqq, 1); 5625 bic_set_bfqq(bic, new_bfqq, 1);
@@ -5853,14 +5784,8 @@ static struct bfq_queue *bfq_set_in_service_queue(struct bfq_data *bfqd)
5853static void bfq_arm_slice_timer(struct bfq_data *bfqd) 5784static void bfq_arm_slice_timer(struct bfq_data *bfqd)
5854{ 5785{
5855 struct bfq_queue *bfqq = bfqd->in_service_queue; 5786 struct bfq_queue *bfqq = bfqd->in_service_queue;
5856 struct bfq_io_cq *bic;
5857 u32 sl; 5787 u32 sl;
5858 5788
5859 /* Processes have exited, don't wait. */
5860 bic = bfqd->in_service_bic;
5861 if (!bic || atomic_read(&bic->icq.ioc->active_ref) == 0)
5862 return;
5863
5864 bfq_mark_bfqq_wait_request(bfqq); 5789 bfq_mark_bfqq_wait_request(bfqq);
5865 5790
5866 /* 5791 /*
@@ -7147,11 +7072,6 @@ static struct request *bfq_dispatch_rq_from_bfqq(struct bfq_data *bfqd,
7147 */ 7072 */
7148 bfq_update_wr_data(bfqd, bfqq); 7073 bfq_update_wr_data(bfqd, bfqq);
7149 7074
7150 if (!bfqd->in_service_bic) {
7151 atomic_long_inc(&RQ_BIC(rq)->icq.ioc->refcount);
7152 bfqd->in_service_bic = RQ_BIC(rq);
7153 }
7154
7155 /* 7075 /*
7156 * Expire bfqq, pretending that its budget expired, if bfqq 7076 * Expire bfqq, pretending that its budget expired, if bfqq
7157 * belongs to CLASS_IDLE and other queues are waiting for 7077 * belongs to CLASS_IDLE and other queues are waiting for
@@ -7272,7 +7192,7 @@ static struct request *bfq_dispatch_request(struct blk_mq_hw_ctx *hctx)
7272 spin_lock_irq(&bfqd->lock); 7192 spin_lock_irq(&bfqd->lock);
7273 7193
7274 rq = __bfq_dispatch_request(hctx); 7194 rq = __bfq_dispatch_request(hctx);
7275 bfq_unlock_put_ioc(bfqd); 7195 spin_unlock_irq(&bfqd->lock);
7276 7196
7277 return rq; 7197 return rq;
7278} 7198}
@@ -7360,20 +7280,9 @@ static void bfq_exit_icq_bfqq(struct bfq_io_cq *bic, bool is_sync)
7360 unsigned long flags; 7280 unsigned long flags;
7361 7281
7362 spin_lock_irqsave(&bfqd->lock, flags); 7282 spin_lock_irqsave(&bfqd->lock, flags);
7363 /*
7364 * If the bic is using a shared queue, put the
7365 * reference taken on the io_context when the bic
7366 * started using a shared bfq_queue. This put cannot
7367 * make ioc->ref_count reach 0, then no ioc->lock
7368 * risks to be taken (leading to possible deadlock
7369 * scenarios).
7370 */
7371 if (is_sync && bfq_bfqq_coop(bfqq))
7372 put_io_context(bic->icq.ioc);
7373
7374 bfq_exit_bfqq(bfqd, bfqq); 7283 bfq_exit_bfqq(bfqd, bfqq);
7375 bic_set_bfqq(bic, NULL, is_sync); 7284 bic_set_bfqq(bic, NULL, is_sync);
7376 bfq_unlock_put_ioc_restore(bfqd, flags); 7285 spin_unlock_irqrestore(&bfqd->lock, flags);
7377 } 7286 }
7378} 7287}
7379 7288
@@ -7808,7 +7717,7 @@ static void bfq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
7808 } 7717 }
7809 } 7718 }
7810 7719
7811 bfq_unlock_put_ioc(bfqd); 7720 spin_unlock_irq(&bfqd->lock);
7812} 7721}
7813 7722
7814static void bfq_insert_requests(struct blk_mq_hw_ctx *hctx, 7723static void bfq_insert_requests(struct blk_mq_hw_ctx *hctx,
@@ -7962,7 +7871,7 @@ static void bfq_put_rq_private(struct request_queue *q, struct request *rq)
7962 bfq_completed_request(bfqq, bfqd); 7871 bfq_completed_request(bfqq, bfqd);
7963 bfq_put_rq_priv_body(bfqq); 7872 bfq_put_rq_priv_body(bfqq);
7964 7873
7965 bfq_unlock_put_ioc_restore(bfqd, flags); 7874 spin_unlock_irqrestore(&bfqd->lock, flags);
7966 } else { 7875 } else {
7967 /* 7876 /*
7968 * Request rq may be still/already in the scheduler, 7877 * Request rq may be still/already in the scheduler,
@@ -8055,6 +7964,7 @@ static int bfq_get_rq_private(struct request_queue *q, struct request *rq,
8055 const int is_sync = rq_is_sync(rq); 7964 const int is_sync = rq_is_sync(rq);
8056 struct bfq_queue *bfqq; 7965 struct bfq_queue *bfqq;
8057 bool new_queue = false; 7966 bool new_queue = false;
7967 bool split = false;
8058 7968
8059 spin_lock_irq(&bfqd->lock); 7969 spin_lock_irq(&bfqd->lock);
8060 7970
@@ -8078,14 +7988,7 @@ static int bfq_get_rq_private(struct request_queue *q, struct request *rq,
8078 bic->saved_in_large_burst = true; 7988 bic->saved_in_large_burst = true;
8079 7989
8080 bfqq = bfq_split_bfqq(bic, bfqq); 7990 bfqq = bfq_split_bfqq(bic, bfqq);
8081 /* 7991 split = true;
8082 * A reference to bic->icq.ioc needs to be
8083 * released after a queue split. Do not do it
8084 * immediately, to not risk to possibly take
8085 * an ioc->lock while holding the scheduler
8086 * lock.
8087 */
8088 bfqd->ioc_to_put = bic->icq.ioc;
8089 7992
8090 if (!bfqq) 7993 if (!bfqq)
8091 bfqq = bfq_get_bfqq_handle_split(bfqd, bic, bio, 7994 bfqq = bfq_get_bfqq_handle_split(bfqd, bic, bio,
@@ -8110,7 +8013,7 @@ static int bfq_get_rq_private(struct request_queue *q, struct request *rq,
8110 */ 8013 */
8111 if (likely(bfqq != &bfqd->oom_bfqq) && bfqq_process_refs(bfqq) == 1) { 8014 if (likely(bfqq != &bfqd->oom_bfqq) && bfqq_process_refs(bfqq) == 1) {
8112 bfqq->bic = bic; 8015 bfqq->bic = bic;
8113 if (bfqd->ioc_to_put) { /* if true, there has been a split */ 8016 if (split) {
8114 /* 8017 /*
8115 * The queue has just been split from a shared 8018 * The queue has just been split from a shared
8116 * queue: restore the idle window and the 8019 * queue: restore the idle window and the
@@ -8123,7 +8026,7 @@ static int bfq_get_rq_private(struct request_queue *q, struct request *rq,
8123 if (unlikely(bfq_bfqq_just_created(bfqq))) 8026 if (unlikely(bfq_bfqq_just_created(bfqq)))
8124 bfq_handle_burst(bfqd, bfqq); 8027 bfq_handle_burst(bfqd, bfqq);
8125 8028
8126 bfq_unlock_put_ioc(bfqd); 8029 spin_unlock_irq(&bfqd->lock);
8127 8030
8128 return 0; 8031 return 0;
8129 8032
@@ -8168,7 +8071,7 @@ static void bfq_idle_slice_timer_body(struct bfq_queue *bfqq)
8168 bfq_bfqq_expire(bfqd, bfqq, true, reason); 8071 bfq_bfqq_expire(bfqd, bfqq, true, reason);
8169 8072
8170schedule_dispatch: 8073schedule_dispatch:
8171 bfq_unlock_put_ioc_restore(bfqd, flags); 8074 spin_unlock_irqrestore(&bfqd->lock, flags);
8172 bfq_schedule_dispatch(bfqd); 8075 bfq_schedule_dispatch(bfqd);
8173} 8076}
8174 8077