Commit fd1bb3ae authored by Paolo Valente's avatar Paolo Valente Committed by Jens Axboe
Browse files

block, bfq: move forward the getting of an extra ref in bfq_bfqq_move



Commit ecedd3d7 ("block, bfq: get extra ref to prevent a queue
from being freed during a group move") gets an extra reference to a
bfq_queue before possibly deactivating it (temporarily), in
bfq_bfqq_move(). This prevents the bfq_queue from disappearing before
being reactivated in its new group.

Yet, the bfq_queue may also be expired (i.e., its service may be
stopped) before the bfq_queue is deactivated. And also an expiration
may lead to a premature freeing. This commit fixes this issue by
simply moving forward the getting of the extra reference already
introduced by commit ecedd3d7 ("block, bfq: get extra ref to
prevent a queue from being freed during a group move").

Reported-by: default avatar <cki-project@redhat.com>
Tested-by: default avatar <cki-project@redhat.com>
Signed-off-by: default avatarPaolo Valente <paolo.valente@linaro.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 2f95fa5c
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -642,6 +642,12 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
{
	struct bfq_entity *entity = &bfqq->entity;

	/*
	 * Get extra reference to prevent bfqq from being freed in
	 * next possible expire or deactivate.
	 */
	bfqq->ref++;

	/* If bfqq is empty, then bfq_bfqq_expire also invokes
	 * bfq_del_bfqq_busy, thereby removing bfqq and its entity
	 * from data structures related to current group. Otherwise we
@@ -652,12 +658,6 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
		bfq_bfqq_expire(bfqd, bfqd->in_service_queue,
				false, BFQQE_PREEMPTED);

	/*
	 * get extra reference to prevent bfqq from being freed in
	 * next possible deactivate
	 */
	bfqq->ref++;

	if (bfq_bfqq_busy(bfqq))
		bfq_deactivate_bfqq(bfqd, bfqq, false, false);
	else if (entity->on_st_or_in_serv)
@@ -677,7 +677,7 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,

	if (!bfqd->in_service_queue && !bfqd->rq_in_driver)
		bfq_schedule_dispatch(bfqd);
	/* release extra ref taken above */
	/* release extra ref taken above, bfqq may happen to be freed now */
	bfq_put_queue(bfqq);
}