Skip to content

Commit 3bc5e68

Browse files
jankaraaxboe
authored andcommitted
bfq: Split shared queues on move between cgroups
When bfqq is shared by multiple processes it can happen that one of the processes gets moved to a different cgroup (or just starts submitting IO for different cgroup). In case that happens we need to split the merged bfqq as otherwise we will have IO for multiple cgroups in one bfqq and we will just account IO time to wrong entities etc. Similarly if the bfqq is scheduled to merge with another bfqq but the merge didn't happen yet, cancel the merge as it need not be valid anymore. CC: [email protected] Fixes: e21b7a0 ("block, bfq: add full hierarchical scheduling and cgroups support") Tested-by: "yukuai (C)" <[email protected]> Signed-off-by: Jan Kara <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent c1cee4a commit 3bc5e68

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

block/bfq-cgroup.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -743,9 +743,39 @@ static struct bfq_group *__bfq_bic_change_cgroup(struct bfq_data *bfqd,
743743
}
744744

745745
if (sync_bfqq) {
746-
entity = &sync_bfqq->entity;
747-
if (entity->sched_data != &bfqg->sched_data)
748-
bfq_bfqq_move(bfqd, sync_bfqq, bfqg);
746+
if (!sync_bfqq->new_bfqq && !bfq_bfqq_coop(sync_bfqq)) {
747+
/* We are the only user of this bfqq, just move it */
748+
if (sync_bfqq->entity.sched_data != &bfqg->sched_data)
749+
bfq_bfqq_move(bfqd, sync_bfqq, bfqg);
750+
} else {
751+
struct bfq_queue *bfqq;
752+
753+
/*
754+
* The queue was merged to a different queue. Check
755+
* that the merge chain still belongs to the same
756+
* cgroup.
757+
*/
758+
for (bfqq = sync_bfqq; bfqq; bfqq = bfqq->new_bfqq)
759+
if (bfqq->entity.sched_data !=
760+
&bfqg->sched_data)
761+
break;
762+
if (bfqq) {
763+
/*
764+
* Some queue changed cgroup so the merge is
765+
* not valid anymore. We cannot easily just
766+
* cancel the merge (by clearing new_bfqq) as
767+
* there may be other processes using this
768+
* queue and holding refs to all queues below
769+
* sync_bfqq->new_bfqq. Similarly if the merge
770+
* already happened, we need to detach from
771+
* bfqq now so that we cannot merge bio to a
772+
* request from the old cgroup.
773+
*/
774+
bfq_put_cooperator(sync_bfqq);
775+
bfq_release_process_ref(bfqd, sync_bfqq);
776+
bic_set_bfqq(bic, NULL, 1);
777+
}
778+
}
749779
}
750780

751781
return bfqg;

block/bfq-iosched.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5315,7 +5315,7 @@ static void bfq_put_stable_ref(struct bfq_queue *bfqq)
53155315
bfq_put_queue(bfqq);
53165316
}
53175317

5318-
static void bfq_put_cooperator(struct bfq_queue *bfqq)
5318+
void bfq_put_cooperator(struct bfq_queue *bfqq)
53195319
{
53205320
struct bfq_queue *__bfqq, *next;
53215321

block/bfq-iosched.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ void bfq_weights_tree_remove(struct bfq_data *bfqd,
979979
void bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq,
980980
bool compensate, enum bfqq_expiration reason);
981981
void bfq_put_queue(struct bfq_queue *bfqq);
982+
void bfq_put_cooperator(struct bfq_queue *bfqq);
982983
void bfq_end_wr_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg);
983984
void bfq_release_process_ref(struct bfq_data *bfqd, struct bfq_queue *bfqq);
984985
void bfq_schedule_dispatch(struct bfq_data *bfqd);

0 commit comments

Comments
 (0)