@@ -5184,22 +5184,16 @@ static void bfq_put_stable_ref(struct bfq_queue *bfqq)
bfq_put_queue(bfqq);
}
+
+/*
+ * If this queue was scheduled to merge with another queue, be
+ * sure to drop the reference taken on that queue.
+ */
static void bfq_put_cooperator(struct bfq_queue *bfqq)
{
- struct bfq_queue *__bfqq, *next;
-
- /*
- * If this queue was scheduled to merge with another queue, be
- * sure to drop the reference taken on that queue (and others in
- * the merge chain). See bfq_setup_merge and bfq_merge_bfqqs.
- */
- __bfqq = bfqq->new_bfqq;
- while (__bfqq) {
- if (__bfqq == bfqq)
- break;
- next = __bfqq->new_bfqq;
- bfq_put_queue(__bfqq);
- __bfqq = next;
+ if (bfqq->new_bfqq) {
+ bfq_put_queue(bfqq->new_bfqq);
+ bfqq->new_bfqq = NULL;
}
}
All calls to bfq_setup_merge() are followed by bfq_merge_bfqqs() so there should be no chance for chaining several queue merges. And if chained queue merges were possible, then bfq_put_cooperator() would drop cooperator references without clearing corresponding bfqq->new_bfqq pointers causing possible use-after-free issues. Fix these problems by making bfq_put_cooperator() drop only the immediate bfqq->new_bfqq reference. CC: stable@vger.kernel.org Fixes: 36eca8948323 ("block, bfq: add Early Queue Merge (EQM)") Signed-off-by: Jan Kara <jack@suse.cz> --- block/bfq-iosched.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-)