summaryrefslogtreecommitdiffstats
path: root/block/bfq-iosched.c
diff options
context:
space:
mode:
authorPaolo Valente <paolo.valente@linaro.org>2017-06-27 14:30:47 -0400
committerJens Axboe <axboe@kernel.dk>2017-06-27 14:30:47 -0400
commit13c931bd9a82d1a88e21f5904c5cdb0261b9d53c (patch)
treebeeabfbff7b14e99894cb3398f7189aebc96763a /block/bfq-iosched.c
parent8298912bb6de7e3c9f86ad19d6488ac88cd0e940 (diff)
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. Reported-by: Luca Miccio <lucmiccio@gmail.com> Signed-off-by: Paolo Valente <paolo.valente@linaro.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/bfq-iosched.c')
-rw-r--r--block/bfq-iosched.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index 60d32700f104..12bbc6b8657d 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -725,8 +725,12 @@ static void bfq_updated_next_req(struct bfq_data *bfqd,
725} 725}
726 726
727static void 727static void
728bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic) 728bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_data *bfqd,
729 struct bfq_io_cq *bic, bool bfq_already_existing)
729{ 730{
731 unsigned int old_wr_coeff = bfqq->wr_coeff;
732 bool busy = bfq_already_existing && bfq_bfqq_busy(bfqq);
733
730 if (bic->saved_idle_window) 734 if (bic->saved_idle_window)
731 bfq_mark_bfqq_idle_window(bfqq); 735 bfq_mark_bfqq_idle_window(bfqq);
732 else 736 else
@@ -754,6 +758,14 @@ bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
754 758
755 /* make sure weight will be updated, however we got here */ 759 /* make sure weight will be updated, however we got here */
756 bfqq->entity.prio_changed = 1; 760 bfqq->entity.prio_changed = 1;
761
762 if (likely(!busy))
763 return;
764
765 if (old_wr_coeff == 1 && bfqq->wr_coeff > 1)
766 bfqd->wr_busy_queues++;
767 else if (old_wr_coeff > 1 && bfqq->wr_coeff == 1)
768 bfqd->wr_busy_queues--;
757} 769}
758 770
759static int bfqq_process_refs(struct bfq_queue *bfqq) 771static int bfqq_process_refs(struct bfq_queue *bfqq)
@@ -4408,7 +4420,7 @@ static void bfq_prepare_request(struct request *rq, struct bio *bio)
4408 const int is_sync = rq_is_sync(rq); 4420 const int is_sync = rq_is_sync(rq);
4409 struct bfq_queue *bfqq; 4421 struct bfq_queue *bfqq;
4410 bool new_queue = false; 4422 bool new_queue = false;
4411 bool split = false; 4423 bool bfqq_already_existing = false, split = false;
4412 4424
4413 if (!rq->elv.icq) 4425 if (!rq->elv.icq)
4414 return; 4426 return;
@@ -4439,6 +4451,8 @@ static void bfq_prepare_request(struct request *rq, struct bio *bio)
4439 bfqq = bfq_get_bfqq_handle_split(bfqd, bic, bio, 4451 bfqq = bfq_get_bfqq_handle_split(bfqd, bic, bio,
4440 true, is_sync, 4452 true, is_sync,
4441 NULL); 4453 NULL);
4454 else
4455 bfqq_already_existing = true;
4442 } 4456 }
4443 } 4457 }
4444 4458
@@ -4464,7 +4478,8 @@ static void bfq_prepare_request(struct request *rq, struct bio *bio)
4464 * queue: restore the idle window and the 4478 * queue: restore the idle window and the
4465 * possible weight raising period. 4479 * possible weight raising period.
4466 */ 4480 */
4467 bfq_bfqq_resume_state(bfqq, bic); 4481 bfq_bfqq_resume_state(bfqq, bfqd, bic,
4482 bfqq_already_existing);
4468 } 4483 }
4469 } 4484 }
4470 4485