]> www.infradead.org Git - users/hch/dma-mapping.git/commitdiff
block, bfq: fix procress reference leakage for bfqq in merge chain
authorYu Kuai <yukuai3@huawei.com>
Mon, 9 Sep 2024 13:41:49 +0000 (21:41 +0800)
committerJens Axboe <axboe@kernel.dk>
Tue, 10 Sep 2024 22:32:09 +0000 (16:32 -0600)
Original state:

        Process 1       Process 2       Process 3       Process 4
         (BIC1)          (BIC2)          (BIC3)          (BIC4)
          Λ                |               |               |
           \--------------\ \-------------\ \-------------\|
                           V               V               V
          bfqq1--------->bfqq2---------->bfqq3----------->bfqq4
    ref    0               1               2               4

After commit 0e456dba86c7 ("block, bfq: choose the last bfqq from merge
chain in bfq_setup_cooperator()"), if P1 issues a new IO:

Without the patch:

        Process 1       Process 2       Process 3       Process 4
         (BIC1)          (BIC2)          (BIC3)          (BIC4)
          Λ                |               |               |
           \------------------------------\ \-------------\|
                                           V               V
          bfqq1--------->bfqq2---------->bfqq3----------->bfqq4
    ref    0               0               2               4

bfqq3 will be used to handle IO from P1, this is not expected, IO
should be redirected to bfqq4;

With the patch:

          -------------------------------------------
          |                                         |
        Process 1       Process 2       Process 3   |   Process 4
         (BIC1)          (BIC2)          (BIC3)     |    (BIC4)
                           |               |        |      |
                            \-------------\ \-------------\|
                                           V               V
          bfqq1--------->bfqq2---------->bfqq3----------->bfqq4
    ref    0               0               2               4

IO is redirected to bfqq4, however, procress reference of bfqq3 is still
2, while there is only P2 using it.

Fix the problem by calling bfq_merge_bfqqs() for each bfqq in the merge
chain. Also change bfqq_merge_bfqqs() to return new_bfqq to simplify
code.

Fixes: 0e456dba86c7 ("block, bfq: choose the last bfqq from merge chain in bfq_setup_cooperator()")
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Link: https://lore.kernel.org/r/20240909134154.954924-3-yukuai1@huaweicloud.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/bfq-iosched.c

index d5d39974c67486754a07d9492969cd41c5d55671..f4192d5411d2a0d89c0fb09764f4e612a4eacb79 100644 (file)
@@ -3129,10 +3129,12 @@ void bfq_release_process_ref(struct bfq_data *bfqd, struct bfq_queue *bfqq)
        bfq_put_queue(bfqq);
 }
 
-static void
-bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
-               struct bfq_queue *bfqq, struct bfq_queue *new_bfqq)
+static struct bfq_queue *bfq_merge_bfqqs(struct bfq_data *bfqd,
+                                        struct bfq_io_cq *bic,
+                                        struct bfq_queue *bfqq)
 {
+       struct bfq_queue *new_bfqq = bfqq->new_bfqq;
+
        bfq_log_bfqq(bfqd, bfqq, "merging with queue %lu",
                (unsigned long)new_bfqq->pid);
        /* Save weight raising and idle window of the merged queues */
@@ -3226,6 +3228,8 @@ bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic,
        bfq_reassign_last_bfqq(bfqq, new_bfqq);
 
        bfq_release_process_ref(bfqd, bfqq);
+
+       return new_bfqq;
 }
 
 static bool bfq_allow_bio_merge(struct request_queue *q, struct request *rq,
@@ -3261,14 +3265,8 @@ static bool bfq_allow_bio_merge(struct request_queue *q, struct request *rq,
                 * fulfilled, i.e., bic can be redirected to new_bfqq
                 * and bfqq can be put.
                 */
-               bfq_merge_bfqqs(bfqd, bfqd->bio_bic, bfqq,
-                               new_bfqq);
-               /*
-                * If we get here, bio will be queued into new_queue,
-                * so use new_bfqq to decide whether bio and rq can be
-                * merged.
-                */
-               bfqq = new_bfqq;
+               while (bfqq != new_bfqq)
+                       bfqq = bfq_merge_bfqqs(bfqd, bfqd->bio_bic, bfqq);
 
                /*
                 * Change also bqfd->bio_bfqq, as
@@ -5705,9 +5703,7 @@ bfq_do_early_stable_merge(struct bfq_data *bfqd, struct bfq_queue *bfqq,
         * state before killing it.
         */
        bfqq->bic = bic;
-       bfq_merge_bfqqs(bfqd, bic, bfqq, new_bfqq);
-
-       return new_bfqq;
+       return bfq_merge_bfqqs(bfqd, bic, bfqq);
 }
 
 /*
@@ -6162,6 +6158,7 @@ static bool __bfq_insert_request(struct bfq_data *bfqd, struct request *rq)
        bool waiting, idle_timer_disabled = false;
 
        if (new_bfqq) {
+               struct bfq_queue *old_bfqq = bfqq;
                /*
                 * Release the request's reference to the old bfqq
                 * and make sure one is taken to the shared queue.
@@ -6178,18 +6175,18 @@ static bool __bfq_insert_request(struct bfq_data *bfqd, struct request *rq)
                 * new_bfqq.
                 */
                if (bic_to_bfqq(RQ_BIC(rq), true,
-                               bfq_actuator_index(bfqd, rq->bio)) == bfqq)
-                       bfq_merge_bfqqs(bfqd, RQ_BIC(rq),
-                                       bfqq, new_bfqq);
+                               bfq_actuator_index(bfqd, rq->bio)) == bfqq) {
+                       while (bfqq != new_bfqq)
+                               bfqq = bfq_merge_bfqqs(bfqd, RQ_BIC(rq), bfqq);
+               }
 
-               bfq_clear_bfqq_just_created(bfqq);
+               bfq_clear_bfqq_just_created(old_bfqq);
                /*
                 * rq is about to be enqueued into new_bfqq,
                 * release rq reference on bfqq
                 */
-               bfq_put_queue(bfqq);
+               bfq_put_queue(old_bfqq);
                rq->elv.priv[1] = new_bfqq;
-               bfqq = new_bfqq;
        }
 
        bfq_update_io_thinktime(bfqd, bfqq);