summaryrefslogtreecommitdiffstats
path: root/block/bfq-iosched.c
diff options
context:
space:
mode:
authorPaolo Valente <paolo.valente@linaro.org>2017-10-09 07:11:23 -0400
committerJens Axboe <axboe@kernel.dk>2017-10-09 11:54:58 -0400
commit99fead8d38e5302b1be9403d4de815ce9174a3df (patch)
tree9aaad76e82a450377f5175b3d0730ce093d6238b /block/bfq-iosched.c
parentb5dc5d4d1f4ff9032eb6c21a3c571a1317dc9289 (diff)
block, bfq: fix unbalanced decrements of burst size
The commit "block, bfq: decrease burst size when queues in burst exit" introduced the decrement of burst_size on the removal of a bfq_queue from the burst list. Unfortunately, this decrement can happen to be performed even when burst size is already equal to 0, because of unbalanced decrements. A description follows of the cause of these unbalanced decrements, namely a wrong assumption, and of the way how this wrong assumption leads to unbalanced decrements. The wrong assumption is that a bfq_queue can exit only if the process associated with the bfq_queue has exited. This is false, because a bfq_queue, say Q, may exit also as a consequence of a merge with another bfq_queue. In this case, Q exits because the I/O of its associated process has been redirected to another bfq_queue. The decrement unbalance occurs because Q may then be re-created after a split, and added back to the current burst list, *without* incrementing burst_size. burst_size is not incremented because Q is not a new bfq_queue added to the burst list, but a bfq_queue only temporarily removed from the list, and, before the commit "bfq-sq, bfq-mq: decrease burst size when queues in burst exit", burst_size was not decremented when Q was removed. This commit addresses this issue by just checking whether the exiting bfq_queue is a merged bfq_queue, and, in that case, not decrementing burst_size. Unfortunately, this still leaves room for unbalanced decrements, in the following rarer case: on a split, the bfq_queue happens to be inserted into a different burst list than that it was removed from when merged. If this happens, the number of elements in the new burst list becomes higher than burst_size (by one). When the bfq_queue then exits, it is of course not in a merged state any longer, thus burst_size is decremented, which results in an unbalanced decrement. To handle this sporadic, unlucky case in a simple way, this commit also checks that burst_size is larger than 0 before decrementing it. Finally, this commit removes an useless, extra check: the check that the bfq_queue is sync, performed before checking whether the bfq_queue is in the burst list. This extra check is redundant, because only sync bfq_queues can be inserted into the burst list. Fixes: 7cb04004fa37 ("block, bfq: decrease burst size when queues in burst exit") Reported-by: Philip Müller <philm@manjaro.org> Signed-off-by: Paolo Valente <paolo.valente@linaro.org> Signed-off-by: Angelo Ruocco <angeloruocco90@gmail.com> Tested-by: Philip Müller <philm@manjaro.org> Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name> Tested-by: Lee Tibbert <lee.tibbert@gmail.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/bfq-iosched.c')
-rw-r--r--block/bfq-iosched.c59
1 files changed, 57 insertions, 2 deletions
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index 261f98695910..889a8549d97f 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -3726,9 +3726,36 @@ void bfq_put_queue(struct bfq_queue *bfqq)
3726 if (bfqq->ref) 3726 if (bfqq->ref)
3727 return; 3727 return;
3728 3728
3729 if (bfq_bfqq_sync(bfqq) && !hlist_unhashed(&bfqq->burst_list_node)) { 3729 if (!hlist_unhashed(&bfqq->burst_list_node)) {
3730 hlist_del_init(&bfqq->burst_list_node); 3730 hlist_del_init(&bfqq->burst_list_node);
3731 bfqq->bfqd->burst_size--; 3731 /*
3732 * Decrement also burst size after the removal, if the
3733 * process associated with bfqq is exiting, and thus
3734 * does not contribute to the burst any longer. This
3735 * decrement helps filter out false positives of large
3736 * bursts, when some short-lived process (often due to
3737 * the execution of commands by some service) happens
3738 * to start and exit while a complex application is
3739 * starting, and thus spawning several processes that
3740 * do I/O (and that *must not* be treated as a large
3741 * burst, see comments on bfq_handle_burst).
3742 *
3743 * In particular, the decrement is performed only if:
3744 * 1) bfqq is not a merged queue, because, if it is,
3745 * then this free of bfqq is not triggered by the exit
3746 * of the process bfqq is associated with, but exactly
3747 * by the fact that bfqq has just been merged.
3748 * 2) burst_size is greater than 0, to handle
3749 * unbalanced decrements. Unbalanced decrements may
3750 * happen in te following case: bfqq is inserted into
3751 * the current burst list--without incrementing
3752 * bust_size--because of a split, but the current
3753 * burst list is not the burst list bfqq belonged to
3754 * (see comments on the case of a split in
3755 * bfq_set_request).
3756 */
3757 if (bfqq->bic && bfqq->bfqd->burst_size > 0)
3758 bfqq->bfqd->burst_size--;
3732 } 3759 }
3733 3760
3734 kmem_cache_free(bfq_pool, bfqq); 3761 kmem_cache_free(bfq_pool, bfqq);
@@ -4460,6 +4487,34 @@ static struct bfq_queue *bfq_get_bfqq_handle_split(struct bfq_data *bfqd,
4460 else { 4487 else {
4461 bfq_clear_bfqq_in_large_burst(bfqq); 4488 bfq_clear_bfqq_in_large_burst(bfqq);
4462 if (bic->was_in_burst_list) 4489 if (bic->was_in_burst_list)
4490 /*
4491 * If bfqq was in the current
4492 * burst list before being
4493 * merged, then we have to add
4494 * it back. And we do not need
4495 * to increase burst_size, as
4496 * we did not decrement
4497 * burst_size when we removed
4498 * bfqq from the burst list as
4499 * a consequence of a merge
4500 * (see comments in
4501 * bfq_put_queue). In this
4502 * respect, it would be rather
4503 * costly to know whether the
4504 * current burst list is still
4505 * the same burst list from
4506 * which bfqq was removed on
4507 * the merge. To avoid this
4508 * cost, if bfqq was in a
4509 * burst list, then we add
4510 * bfqq to the current burst
4511 * list without any further
4512 * check. This can cause
4513 * inappropriate insertions,
4514 * but rarely enough to not
4515 * harm the detection of large
4516 * bursts significantly.
4517 */
4463 hlist_add_head(&bfqq->burst_list_node, 4518 hlist_add_head(&bfqq->burst_list_node,
4464 &bfqd->burst_list); 4519 &bfqd->burst_list);
4465 } 4520 }