diff options
author | Paolo Valente <paolo.valente@linaro.org> | 2019-01-29 06:06:34 -0500 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2019-01-31 14:50:24 -0500 |
commit | 9dee8b3b057e1da26f85f1842f2aaf3bb200fb94 (patch) | |
tree | 909db0541b6ce1e5368ea986cde0483cdeddd32f | |
parent | d87447d84fe194b0e4f5413b5344dc82cc100711 (diff) |
block, bfq: fix queue removal from weights tree
bfq maintains an ordered list, through a red-black tree, of unique
weights of active bfq_queues. This list is used to detect whether there
are active queues with differentiated weights. The weight of a queue is
removed from the list when both the following two conditions become
true:
(1) the bfq_queue is flagged as inactive
(2) the has no in-flight request any longer;
Unfortunately, in the rare cases where condition (2) becomes true before
condition (1), the removal fails, because the function to remove the
weight of the queue (bfq_weights_tree_remove) is rightly invoked in the
path that deactivates the bfq_queue, but mistakenly invoked *before* the
function that actually performs the deactivation (bfq_deactivate_bfqq).
This commits moves the invocation of bfq_weights_tree_remove for
condition (1) to after bfq_deactivate_bfqq. As a consequence of this
move, it is necessary to add a further reference to the queue when the
weight of a queue is added, because the queue might otherwise be freed
before bfq_weights_tree_remove is invoked. This commit adds this
reference and makes all related modifications.
Signed-off-by: Paolo Valente <paolo.valente@linaro.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | block/bfq-iosched.c | 17 | ||||
-rw-r--r-- | block/bfq-wf2q.c | 6 |
2 files changed, 16 insertions, 7 deletions
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 12228af16198..bf585ad29bb5 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c | |||
@@ -754,6 +754,7 @@ void bfq_weights_tree_add(struct bfq_data *bfqd, struct bfq_queue *bfqq, | |||
754 | 754 | ||
755 | inc_counter: | 755 | inc_counter: |
756 | bfqq->weight_counter->num_active++; | 756 | bfqq->weight_counter->num_active++; |
757 | bfqq->ref++; | ||
757 | } | 758 | } |
758 | 759 | ||
759 | /* | 760 | /* |
@@ -778,6 +779,7 @@ void __bfq_weights_tree_remove(struct bfq_data *bfqd, | |||
778 | 779 | ||
779 | reset_entity_pointer: | 780 | reset_entity_pointer: |
780 | bfqq->weight_counter = NULL; | 781 | bfqq->weight_counter = NULL; |
782 | bfq_put_queue(bfqq); | ||
781 | } | 783 | } |
782 | 784 | ||
783 | /* | 785 | /* |
@@ -789,9 +791,6 @@ void bfq_weights_tree_remove(struct bfq_data *bfqd, | |||
789 | { | 791 | { |
790 | struct bfq_entity *entity = bfqq->entity.parent; | 792 | struct bfq_entity *entity = bfqq->entity.parent; |
791 | 793 | ||
792 | __bfq_weights_tree_remove(bfqd, bfqq, | ||
793 | &bfqd->queue_weights_tree); | ||
794 | |||
795 | for_each_entity(entity) { | 794 | for_each_entity(entity) { |
796 | struct bfq_sched_data *sd = entity->my_sched_data; | 795 | struct bfq_sched_data *sd = entity->my_sched_data; |
797 | 796 | ||
@@ -825,6 +824,15 @@ void bfq_weights_tree_remove(struct bfq_data *bfqd, | |||
825 | bfqd->num_groups_with_pending_reqs--; | 824 | bfqd->num_groups_with_pending_reqs--; |
826 | } | 825 | } |
827 | } | 826 | } |
827 | |||
828 | /* | ||
829 | * Next function is invoked last, because it causes bfqq to be | ||
830 | * freed if the following holds: bfqq is not in service and | ||
831 | * has no dispatched request. DO NOT use bfqq after the next | ||
832 | * function invocation. | ||
833 | */ | ||
834 | __bfq_weights_tree_remove(bfqd, bfqq, | ||
835 | &bfqd->queue_weights_tree); | ||
828 | } | 836 | } |
829 | 837 | ||
830 | /* | 838 | /* |
@@ -1020,7 +1028,8 @@ bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_data *bfqd, | |||
1020 | 1028 | ||
1021 | static int bfqq_process_refs(struct bfq_queue *bfqq) | 1029 | static int bfqq_process_refs(struct bfq_queue *bfqq) |
1022 | { | 1030 | { |
1023 | return bfqq->ref - bfqq->allocated - bfqq->entity.on_st; | 1031 | return bfqq->ref - bfqq->allocated - bfqq->entity.on_st - |
1032 | (bfqq->weight_counter != NULL); | ||
1024 | } | 1033 | } |
1025 | 1034 | ||
1026 | /* Empty burst list and add just bfqq (see comments on bfq_handle_burst) */ | 1035 | /* Empty burst list and add just bfqq (see comments on bfq_handle_burst) */ |
diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c index ce37d709a34f..63311d1ff1ed 100644 --- a/block/bfq-wf2q.c +++ b/block/bfq-wf2q.c | |||
@@ -1673,15 +1673,15 @@ void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq, | |||
1673 | 1673 | ||
1674 | bfqd->busy_queues[bfqq->ioprio_class - 1]--; | 1674 | bfqd->busy_queues[bfqq->ioprio_class - 1]--; |
1675 | 1675 | ||
1676 | if (!bfqq->dispatched) | ||
1677 | bfq_weights_tree_remove(bfqd, bfqq); | ||
1678 | |||
1679 | if (bfqq->wr_coeff > 1) | 1676 | if (bfqq->wr_coeff > 1) |
1680 | bfqd->wr_busy_queues--; | 1677 | bfqd->wr_busy_queues--; |
1681 | 1678 | ||
1682 | bfqg_stats_update_dequeue(bfqq_group(bfqq)); | 1679 | bfqg_stats_update_dequeue(bfqq_group(bfqq)); |
1683 | 1680 | ||
1684 | bfq_deactivate_bfqq(bfqd, bfqq, true, expiration); | 1681 | bfq_deactivate_bfqq(bfqd, bfqq, true, expiration); |
1682 | |||
1683 | if (!bfqq->dispatched) | ||
1684 | bfq_weights_tree_remove(bfqd, bfqq); | ||
1685 | } | 1685 | } |
1686 | 1686 | ||
1687 | /* | 1687 | /* |