Jan Kara a1a4ac
From 4a1254ae1f3f698239bba8ef4c730f5f2fc73ff0 Mon Sep 17 00:00:00 2001
Jan Kara a1a4ac
From: Jan Kara <jack@suse.cz>
Jan Kara a1a4ac
Date: Tue, 21 Dec 2021 20:33:16 +0100
Jan Kara a1a4ac
Subject: [PATCH 3/9] bfq: Split shared queues on move between cgroups
Jan Kara a1a4ac
References: bsc#1197926
Jan Kara a1a4ac
Patch-mainline: submitted, in linux-block tree
Jan Kara a1a4ac
Jan Kara a1a4ac
When bfqq is shared by multiple processes it can happen that one of the
Jan Kara a1a4ac
processes gets moved to a different cgroup (or just starts submitting IO
Jan Kara a1a4ac
for different cgroup). In case that happens we need to split the merged
Jan Kara a1a4ac
bfqq as otherwise we will have IO for multiple cgroups in one bfqq and
Jan Kara a1a4ac
we will just account IO time to wrong entities etc.
Jan Kara a1a4ac
Jan Kara a1a4ac
Similarly if the bfqq is scheduled to merge with another bfqq but the
Jan Kara a1a4ac
merge didn't happen yet, cancel the merge as it need not be valid
Jan Kara a1a4ac
anymore.
Jan Kara a1a4ac
Jan Kara a1a4ac
Cc: stable@vger.kernel.org
Jan Kara a1a4ac
Fixes: e21b7a0b9887 ("block, bfq: add full hierarchical scheduling and cgroups support")
Jan Kara a1a4ac
Tested-by: "yukuai (C)" <yukuai3@huawei.com>
Jan Kara a1a4ac
Signed-off-by: Jan Kara <jack@suse.cz>
Jan Kara a1a4ac
Jan Kara a1a4ac
---
Jan Kara a1a4ac
 block/bfq-cgroup.c  |   36 +++++++++++++++++++++++++++++++++---
Jan Kara a1a4ac
 block/bfq-iosched.c |    2 +-
Jan Kara a1a4ac
 block/bfq-iosched.h |    1 +
Jan Kara a1a4ac
 3 files changed, 35 insertions(+), 4 deletions(-)
Jan Kara a1a4ac
Jan Kara a1a4ac
--- a/block/bfq-cgroup.c
Jan Kara a1a4ac
+++ b/block/bfq-cgroup.c
Jan Kara a1a4ac
@@ -719,9 +719,39 @@ static struct bfq_group *__bfq_bic_chang
Jan Kara a1a4ac
 	}
Jan Kara a1a4ac
 
Jan Kara a1a4ac
 	if (sync_bfqq) {
Jan Kara a1a4ac
-		entity = &sync_bfqq->entity;
Jan Kara a1a4ac
-		if (entity->sched_data != &bfqg->sched_data)
Jan Kara a1a4ac
-			bfq_bfqq_move(bfqd, sync_bfqq, bfqg);
Jan Kara a1a4ac
+		if (!sync_bfqq->new_bfqq && !bfq_bfqq_coop(sync_bfqq)) {
Jan Kara a1a4ac
+			/* We are the only user of this bfqq, just move it */
Jan Kara a1a4ac
+			if (sync_bfqq->entity.sched_data != &bfqg->sched_data)
Jan Kara a1a4ac
+				bfq_bfqq_move(bfqd, sync_bfqq, bfqg);
Jan Kara a1a4ac
+		} else {
Jan Kara a1a4ac
+			struct bfq_queue *bfqq;
Jan Kara a1a4ac
+
Jan Kara a1a4ac
+			/*
Jan Kara a1a4ac
+			 * The queue was merged to a different queue. Check
Jan Kara a1a4ac
+			 * that the merge chain still belongs to the same
Jan Kara a1a4ac
+			 * cgroup.
Jan Kara a1a4ac
+			 */
Jan Kara a1a4ac
+			for (bfqq = sync_bfqq; bfqq; bfqq = bfqq->new_bfqq)
Jan Kara a1a4ac
+				if (bfqq->entity.sched_data !=
Jan Kara a1a4ac
+				    &bfqg->sched_data)
Jan Kara a1a4ac
+					break;
Jan Kara a1a4ac
+			if (bfqq) {
Jan Kara a1a4ac
+				/*
Jan Kara a1a4ac
+				 * Some queue changed cgroup so the merge is
Jan Kara a1a4ac
+				 * not valid anymore. We cannot easily just
Jan Kara a1a4ac
+				 * cancel the merge (by clearing new_bfqq) as
Jan Kara a1a4ac
+				 * there may be other processes using this
Jan Kara a1a4ac
+				 * queue and holding refs to all queues below
Jan Kara a1a4ac
+				 * sync_bfqq->new_bfqq. Similarly if the merge
Jan Kara a1a4ac
+				 * already happened, we need to detach from
Jan Kara a1a4ac
+				 * bfqq now so that we cannot merge bio to a
Jan Kara a1a4ac
+				 * request from the old cgroup.
Jan Kara a1a4ac
+				 */
Jan Kara a1a4ac
+				bfq_put_cooperator(sync_bfqq);
Jan Kara a1a4ac
+				bfq_release_process_ref(bfqd, sync_bfqq);
Jan Kara a1a4ac
+				bic_set_bfqq(bic, NULL, 1);
Jan Kara a1a4ac
+			}
Jan Kara a1a4ac
+		}
Jan Kara a1a4ac
 	}
Jan Kara a1a4ac
 
Jan Kara a1a4ac
 	return bfqg;
Jan Kara a1a4ac
--- a/block/bfq-iosched.c
Jan Kara a1a4ac
+++ b/block/bfq-iosched.c
Jan Kara a1a4ac
@@ -5030,7 +5030,7 @@ void bfq_put_queue(struct bfq_queue *bfq
Jan Kara a1a4ac
 #endif
Jan Kara a1a4ac
 }
Jan Kara a1a4ac
 
Jan Kara a1a4ac
-static void bfq_put_cooperator(struct bfq_queue *bfqq)
Jan Kara a1a4ac
+void bfq_put_cooperator(struct bfq_queue *bfqq)
Jan Kara a1a4ac
 {
Jan Kara a1a4ac
 	struct bfq_queue *__bfqq, *next;
Jan Kara a1a4ac
 
Jan Kara a1a4ac
--- a/block/bfq-iosched.h
Jan Kara a1a4ac
+++ b/block/bfq-iosched.h
Jan Kara a1a4ac
@@ -955,6 +955,7 @@ void bfq_weights_tree_remove(struct bfq_
Jan Kara a1a4ac
 void bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq,
Jan Kara a1a4ac
 		     bool compensate, enum bfqq_expiration reason);
Jan Kara a1a4ac
 void bfq_put_queue(struct bfq_queue *bfqq);
Jan Kara a1a4ac
+void bfq_put_cooperator(struct bfq_queue *bfqq);
Jan Kara a1a4ac
 void bfq_end_wr_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg);
Jan Kara a1a4ac
 void bfq_release_process_ref(struct bfq_data *bfqd, struct bfq_queue *bfqq);
Jan Kara a1a4ac
 void bfq_schedule_dispatch(struct bfq_data *bfqd);