Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba17485b authored by Paolo Valente's avatar Paolo Valente Committed by Razziell
Browse files

block/bfq: update wr_busy_queues if needed on a queue split



This commit fixes a bug triggered by a non-trivial sequence of
events. These events are briefly described in the next two
paragraphs. The impatiens, or those who are familiar with queue
merging and splitting, can jump directly to the last paragraph.

On each I/O-request arrival for a shared bfq_queue, i.e., for a
bfq_queue that is the result of the merge of two or more bfq_queues,
BFQ checks whether the shared bfq_queue has become seeky (i.e., if too
many random I/O requests have arrived for the bfq_queue; if the device
is non rotational, then random requests must be also small for the
bfq_queue to be tagged as seeky). If the shared bfq_queue is actually
detected as seeky, then a split occurs: the bfq I/O context of the
process that has issued the request is redirected from the shared
bfq_queue to a new non-shared bfq_queue. As a degenerate case, if the
shared bfq_queue actually happens to be shared only by one process
(because of previous splits), then no new bfq_queue is created: the
state of the shared bfq_queue is just changed from shared to non
shared.

Regardless of whether a brand new non-shared bfq_queue is created, or
the pre-existing shared bfq_queue is just turned into a non-shared
bfq_queue, several parameters of the non-shared bfq_queue are set
(restored) to the original values they had when the bfq_queue
associated with the bfq I/O context of the process (that has just
issued an I/O request) was merged with the shared bfq_queue. One of
these parameters is the weight-raising state.

If, on the split of a shared bfq_queue,
1) a pre-existing shared bfq_queue is turned into a non-shared
bfq_queue;
2) the previously shared bfq_queue happens to be busy;
3) the weight-raising state of the previously shared bfq_queue happens
to change;
the number of weight-raised busy queues changes. The field
wr_busy_queues must then be updated accordingly, but such an update
was missing. This commit adds the missing update.

Change-Id: I04a806244c07c71ba72b5ea6c222bb5459996b4f
Signed-off-by: default avatarPaolo Valente <paolo.valente@linaro.org>
Signed-off-by: default avatarFAROVITUS <farovitus@gmail.com>
Signed-off-by: default avatarAlbert I <krascgq@outlook.co.id>
parent 649f3ab0
Loading
Loading
Loading
Loading
+39 −8
Original line number Diff line number Diff line
@@ -686,8 +686,12 @@ static unsigned int bfq_wr_duration(struct bfq_data *bfqd)
}

static void
bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_data *bfqd,
		      struct bfq_io_cq *bic, bool bfq_already_existing)
{
	unsigned int old_wr_coeff;
	bool busy = bfq_already_existing && bfq_bfqq_busy(bfqq);

	if (bic->saved_idle_window)
		bfq_mark_bfqq_idle_window(bfqq);
	else
@@ -698,6 +702,9 @@ bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
	else
		bfq_clear_bfqq_IO_bound(bfqq);

	if (unlikely(busy))
		old_wr_coeff = bfqq->wr_coeff;

	bfqq->wr_coeff = bic->saved_wr_coeff;
	bfqq->wr_start_at_switch_to_srt = bic->saved_wr_start_at_switch_to_srt;
	BUG_ON(time_is_after_jiffies(bfqq->wr_start_at_switch_to_srt));
@@ -715,8 +722,20 @@ bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic)

		bfqq->wr_coeff = 1;
	}

	/* make sure weight will be updated, however we got here */
	bfqq->entity.prio_changed = 1;

	if (likely(!busy))
		return;

	if (old_wr_coeff == 1 && bfqq->wr_coeff > 1) {
		bfqd->wr_busy_queues++;
		BUG_ON(bfqd->wr_busy_queues > bfqd->busy_queues);
	} else if (old_wr_coeff > 1 && bfqq->wr_coeff == 1) {
		bfqd->wr_busy_queues--;
		BUG_ON(bfqd->wr_busy_queues < 0);
	}
}

static int bfqq_process_refs(struct bfq_queue *bfqq)
@@ -1465,6 +1484,7 @@ static void bfq_add_request(struct request *rq)
			bfqq->wr_cur_max_time = bfq_wr_duration(bfqd);

			bfqd->wr_busy_queues++;
			BUG_ON(bfqd->wr_busy_queues > bfqd->busy_queues);
			bfqq->entity.prio_changed = 1;
			bfq_log_bfqq(bfqd, bfqq,
				     "non-idle wrais starting, "
@@ -1704,8 +1724,10 @@ static void bfq_bfqq_end_wr(struct bfq_queue *bfqq)
{
	BUG_ON(!bfqq);

	if (bfq_bfqq_busy(bfqq))
	if (bfq_bfqq_busy(bfqq)) {
		bfqq->bfqd->wr_busy_queues--;
		BUG_ON(bfqq->bfqd->wr_busy_queues < 0);
	}
	bfqq->wr_coeff = 1;
	bfqq->wr_cur_max_time = 0;
	bfqq->last_wr_start_finish = jiffies;
@@ -2084,8 +2106,11 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
		new_bfqq->last_wr_start_finish = bfqq->last_wr_start_finish;
		new_bfqq->wr_start_at_switch_to_srt =
			bfqq->wr_start_at_switch_to_srt;
		if (bfq_bfqq_busy(new_bfqq))
		if (bfq_bfqq_busy(new_bfqq)) {
			bfqd->wr_busy_queues++;
			BUG_ON(bfqd->wr_busy_queues > bfqd->busy_queues);
		}

		new_bfqq->entity.prio_changed = 1;
		bfq_log_bfqq(bfqd, new_bfqq,
			     "wr start after merge with %d, rais_max_time %u",
@@ -2096,8 +2121,11 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
	if (bfqq->wr_coeff > 1) { /* bfqq has given its wr to new_bfqq */
		bfqq->wr_coeff = 1;
		bfqq->entity.prio_changed = 1;
		if (bfq_bfqq_busy(bfqq))
		if (bfq_bfqq_busy(bfqq)) {
			bfqd->wr_busy_queues--;
			BUG_ON(bfqd->wr_busy_queues < 0);
		}

	}

	bfq_log_bfqq(bfqd, new_bfqq, "merge_bfqqs: wr_busy %d",
@@ -4558,7 +4586,7 @@ static int bfq_set_request(struct request_queue *q, struct request *rq,
	const int is_sync = rq_is_sync(rq);
	struct bfq_queue *bfqq;
	unsigned long flags;
	bool split = false;
	bool bfqq_already_existing = false, split = false;

	spin_lock_irqsave(q->queue_lock, flags);
	bfq_check_ioprio_change(bic, bio);
@@ -4617,6 +4645,8 @@ new_queue:
			split = true;
			if (!bfqq)
				goto new_queue;
			else
				bfqq_already_existing = true;
		}
	}

@@ -4642,7 +4672,8 @@ new_queue:
			 * queue, restore the idle window and the possible
			 * weight raising period.
			 */
			bfq_bfqq_resume_state(bfqq, bic);
			bfq_bfqq_resume_state(bfqq, bfqd, bic,
					      bfqq_already_existing);
		}
	}

+7 −2
Original line number Diff line number Diff line
@@ -1932,8 +1932,10 @@ static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
		bfq_weights_tree_remove(bfqd, &bfqq->entity,
					&bfqd->queue_weights_tree);

	if (bfqq->wr_coeff > 1)
	if (bfqq->wr_coeff > 1) {
		bfqd->wr_busy_queues--;
		BUG_ON(bfqd->wr_busy_queues < 0);
	}

	bfqg_stats_update_dequeue(bfqq_group(bfqq));

@@ -1962,6 +1964,9 @@ static void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq)
			bfq_weights_tree_add(bfqd, &bfqq->entity,
					     &bfqd->queue_weights_tree);

	if (bfqq->wr_coeff > 1)
	if (bfqq->wr_coeff > 1) {
		bfqd->wr_busy_queues++;
		BUG_ON(bfqd->wr_busy_queues > bfqd->busy_queues);
	}

}