linux-block.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup
@ 2021-03-08 12:00 brookxu
  2021-03-08 12:00 ` [RFC PATCH 1/8] bfq: introduce bfq_entity_to_bfqg helper method brookxu
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

Tasks in the production environment can be roughly divided into
three categories: emergency tasks, ordinary tasks and offline
tasks. Emergency tasks need to be scheduled in real time, and the
amount of data for such tasks is usually not very large, such as
system agents. Offline tasks do not need to guarantee QoS, but
can improve system resource utilization during system idle
periods, such as various background tasks. The above requirements
need to achieve IO preemption. At present, we can use weights to
simulate IO preemption, but since weights are more of a shared
concept, they cannot be simulated well. For example, the weights
of emergency tasks and ordinary tasks cannot be determined well,
offline tasks (with the same weight) actually occupy different
resources on disks with different performance, and the tail delay
caused by offline tasks cannot be well controlled. Using ioprio's
concept of preemption, we can solve the above problems very well.
Second, we can still use weights to control resource isolation of
the same priority, thereby achieving better IO Qos control.

However, currently implemented by bfq, the class of bfq_group is
always be class, and the ioprio class of the task can only be
reflected in a single cgroup. We cannot guarantee that real-time
tasks in a cgroup are scheduled in time. To this end, we
introduced cgroup ioprio. In this way, we can ensure that the
real-time tasks of a cgroup can be scheduled in time. Similarly,
the processing of offline task groups can also be simpler.

To this end, we have introduced the bfq.ioprio interface for
cgroup v1 and cgroup v2. Users can configure the priority
through this interface, as shown below:

echo "1 2"> blkio.bfq.weight

The above two values respectively represent the values of ioprio
class and ioprio for cgroup. The ioprio of tasks within the cgroup
is uniformly equal to the ioprio of the cgroup. If the ioprio of
the cgroup is disabled, the ioprio of the task remains the same,
usually from io_context.

When testing, using fio and fio_generate_plots we can clearly see
that the IO delay of the task satisfies RT> BE> IDLE. When RT is
running, BE and IDLE are guaranteed minimum bandwidth. When used
with bfq.weight, we can also isolate the weight within the same
class.

The last three patches are irrelevant to the cgroup ioprio,
they are brought together here for the convenience of patch
management.

Chunguang Xu (8):
  bfq: introduce bfq_entity_to_bfqg helper method
  bfq: limit the IO depth of idle_class to 1
  bfq: keep the minimun bandwidth for be_class
  bfq: expire bfqq if a higher priority class is waiting
  bfq: introduce bfq.ioprio for cgroup
  bfq: convert the type of bfq_group.bfqd to bfq_data*
  bfq: remove unnecessary initialization logic
  bfq: optimize the calculation of bfq_weight_to_ioprio()

 block/bfq-cgroup.c  |  99 +++++++++++++++++++++++++++++++++++++-----
 block/bfq-iosched.c |  32 +++++++++++++-
 block/bfq-iosched.h |  20 ++++++---
 block/bfq-wf2q.c    | 103 +++++++++++++++++++++++++++++++-------------
 4 files changed, 207 insertions(+), 47 deletions(-)

-- 
2.30.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC PATCH 1/8] bfq: introduce bfq_entity_to_bfqg helper method
  2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
@ 2021-03-08 12:00 ` brookxu
  2021-03-08 12:00 ` [RFC PATCH 2/8] bfq: limit the IO depth of idle_class to 1 brookxu
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

From: Chunguang Xu <brookxu@tencent.com>

Introduce bfq_entity_to_bfqg() to make it easier to obtain the
bfq_group corresponding to the entity.

Signed-off-by: Chunguang Xu <brookxu@tencent.com>
---
 block/bfq-cgroup.c  |  6 ++----
 block/bfq-iosched.h |  1 +
 block/bfq-wf2q.c    | 16 ++++++++++++----
 3 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index b791e2041e49..a5f544acaa61 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -309,8 +309,7 @@ struct bfq_group *bfqq_group(struct bfq_queue *bfqq)
 {
 	struct bfq_entity *group_entity = bfqq->entity.parent;
 
-	return group_entity ? container_of(group_entity, struct bfq_group,
-					   entity) :
+	return group_entity ? bfq_entity_to_bfqg(group_entity) :
 			      bfqq->bfqd->root_group;
 }
 
@@ -610,8 +609,7 @@ struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd,
 	 */
 	entity = &bfqg->entity;
 	for_each_entity(entity) {
-		struct bfq_group *curr_bfqg = container_of(entity,
-						struct bfq_group, entity);
+		struct bfq_group *curr_bfqg = bfq_entity_to_bfqg(entity);
 		if (curr_bfqg != bfqd->root_group) {
 			parent = bfqg_parent(curr_bfqg);
 			if (!parent)
diff --git a/block/bfq-iosched.h b/block/bfq-iosched.h
index b8e793c34ff1..a6f98e9e14b5 100644
--- a/block/bfq-iosched.h
+++ b/block/bfq-iosched.h
@@ -941,6 +941,7 @@ struct bfq_group {
 #endif
 
 struct bfq_queue *bfq_entity_to_bfqq(struct bfq_entity *entity);
+struct bfq_group *bfq_entity_to_bfqg(struct bfq_entity *entity);
 
 /* --------------- main algorithm interface ----------------- */
 
diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c
index 070e34a7feb1..5ff0028920a2 100644
--- a/block/bfq-wf2q.c
+++ b/block/bfq-wf2q.c
@@ -149,7 +149,7 @@ struct bfq_group *bfq_bfqq_to_bfqg(struct bfq_queue *bfqq)
 	if (!group_entity)
 		group_entity = &bfqq->bfqd->root_group->entity;
 
-	return container_of(group_entity, struct bfq_group, entity);
+	return bfq_entity_to_bfqg(group_entity);
 }
 
 /*
@@ -208,7 +208,7 @@ static bool bfq_no_longer_next_in_service(struct bfq_entity *entity)
 	if (bfq_entity_to_bfqq(entity))
 		return true;
 
-	bfqg = container_of(entity, struct bfq_group, entity);
+	bfqg = bfq_entity_to_bfqg(entity);
 
 	/*
 	 * The field active_entities does not always contain the
@@ -266,6 +266,15 @@ struct bfq_queue *bfq_entity_to_bfqq(struct bfq_entity *entity)
 	return bfqq;
 }
 
+struct bfq_group *bfq_entity_to_bfqg(struct bfq_entity *entity)
+{
+	struct bfq_group *bfqg = NULL;
+
+	if (entity->my_sched_data)
+		bfqg = container_of(entity, struct bfq_group, entity);
+
+	return bfqg;
+}
 
 /**
  * bfq_delta - map service into the virtual time domain.
@@ -1001,8 +1010,7 @@ static void __bfq_activate_entity(struct bfq_entity *entity,
 
 #ifdef CONFIG_BFQ_GROUP_IOSCHED
 	if (!bfq_entity_to_bfqq(entity)) { /* bfq_group */
-		struct bfq_group *bfqg =
-			container_of(entity, struct bfq_group, entity);
+		struct bfq_group *bfqg = bfq_entity_to_bfqg(entity);
 		struct bfq_data *bfqd = bfqg->bfqd;
 
 		if (!entity->in_groups_with_pending_reqs) {
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 2/8] bfq: limit the IO depth of idle_class to 1
  2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
  2021-03-08 12:00 ` [RFC PATCH 1/8] bfq: introduce bfq_entity_to_bfqg helper method brookxu
@ 2021-03-08 12:00 ` brookxu
  2021-03-08 12:00 ` [RFC PATCH 3/8] bfq: keep the minimun bandwidth for be_class brookxu
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

From: Chunguang Xu <brookxu@tencent.com>

The IO depth of idle_class is limited to 1, so that it can
avoid introducing a larger tail latency under a device with
a larger IO depth. Although limiting the IO depth may reduce
the performance of idle_class, it is generally not a big
problem, because idle_class usually does not have strict
performance requirements.

Signed-off-by: Chunguang Xu <brookxu@tencent.com>
---
 block/bfq-iosched.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index ec482e6641ff..ea9d7f6f4e3d 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -4808,6 +4808,17 @@ static struct request *__bfq_dispatch_request(struct blk_mq_hw_ctx *hctx)
 	if (!bfqq)
 		goto exit;
 
+	/*
+	 * Here, the IO depth of idle_class is limited to 1, so that it
+	 * can avoid introducing a larger tail latency under a device
+	 * with a larger IO depth. Although limiting the IO depth may
+	 * reduce the performance of idle_class, it is generally not a
+	 * big problem, because idle_class usually does not have strict
+	 * performance requirements.
+	 */
+	if (bfq_class_idle(bfqq) && bfqq->dispatched)
+		goto exit;
+
 	rq = bfq_dispatch_rq_from_bfqq(bfqd, bfqq);
 
 	if (rq) {
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 3/8] bfq: keep the minimun bandwidth for be_class
  2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
  2021-03-08 12:00 ` [RFC PATCH 1/8] bfq: introduce bfq_entity_to_bfqg helper method brookxu
  2021-03-08 12:00 ` [RFC PATCH 2/8] bfq: limit the IO depth of idle_class to 1 brookxu
@ 2021-03-08 12:00 ` brookxu
  2021-03-08 12:00 ` [RFC PATCH 4/8] bfq: expire bfqq if a higher priority class is waiting brookxu
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

From: Chunguang Xu <brookxu@tencent.com>

rt_class will preempt other classes, which may cause other
classes to starve to death. At present, idle_class has
alleviated the starvation problem through the minimum
bandwidth mechanism. Similarly, we should do the same for
be_class.

Signed-off-by: Chunguang Xu <brookxu@tencent.com>
---
 block/bfq-iosched.c |  2 +-
 block/bfq-iosched.h |  9 +++++----
 block/bfq-wf2q.c    | 46 ++++++++++++++++++++++++++++-----------------
 3 files changed, 35 insertions(+), 22 deletions(-)

diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index ea9d7f6f4e3d..b639cdbb4192 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -6539,7 +6539,7 @@ static void bfq_init_root_group(struct bfq_group *root_group,
 	root_group->rq_pos_tree = RB_ROOT;
 	for (i = 0; i < BFQ_IOPRIO_CLASSES; i++)
 		root_group->sched_data.service_tree[i] = BFQ_SERVICE_TREE_INIT;
-	root_group->sched_data.bfq_class_idle_last_service = jiffies;
+	root_group->sched_data.class_timeout_last_check = jiffies;
 }
 
 static int bfq_init_queue(struct request_queue *q, struct elevator_type *e)
diff --git a/block/bfq-iosched.h b/block/bfq-iosched.h
index a6f98e9e14b5..2fe7456aa7bc 100644
--- a/block/bfq-iosched.h
+++ b/block/bfq-iosched.h
@@ -13,7 +13,7 @@
 #include "blk-cgroup-rwstat.h"
 
 #define BFQ_IOPRIO_CLASSES	3
-#define BFQ_CL_IDLE_TIMEOUT	(HZ/5)
+#define BFQ_CLASS_TIMEOUT	(HZ/5)
 
 #define BFQ_MIN_WEIGHT			1
 #define BFQ_MAX_WEIGHT			1000
@@ -97,9 +97,10 @@ struct bfq_sched_data {
 	struct bfq_entity *next_in_service;
 	/* array of service trees, one per ioprio_class */
 	struct bfq_service_tree service_tree[BFQ_IOPRIO_CLASSES];
-	/* last time CLASS_IDLE was served */
-	unsigned long bfq_class_idle_last_service;
-
+	/* last time the class timeout was checked */
+	unsigned long class_timeout_last_check;
+	/* the position to start class timeout check next time */
+	unsigned int next_class_index;
 };
 
 /**
diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c
index 5ff0028920a2..0d10eb3ed555 100644
--- a/block/bfq-wf2q.c
+++ b/block/bfq-wf2q.c
@@ -1435,6 +1435,34 @@ __bfq_lookup_next_entity(struct bfq_service_tree *st, bool in_service)
 	return entity;
 }
 
+static int bfq_select_next_class(struct bfq_sched_data *sd)
+{
+	struct bfq_service_tree *st = sd->service_tree;
+	int i, class_idx, next_class = 0;
+	unsigned long last_check;
+
+	/*
+	 * we needed to guarantee a minimum bandwidth for each class (if
+	 * there is some active entity in this class). This should also
+	 * mitigate priority-inversion problems in case a low priority
+	 * task is holding file system resources.
+	 */
+	for (i = 0; i < BFQ_IOPRIO_CLASSES; i++) {
+		class_idx = (sd->next_class_index + i) % BFQ_IOPRIO_CLASSES;
+		last_check = sd->class_timeout_last_check;
+		if (time_is_before_jiffies(last_check + BFQ_CLASS_TIMEOUT)) {
+			sd->class_timeout_last_check = jiffies;
+			if (!RB_EMPTY_ROOT(&(st + class_idx)->active)) {
+				next_class = class_idx++;
+				class_idx %= BFQ_IOPRIO_CLASSES;
+				sd->next_class_index = class_idx;
+				break;
+			}
+		}
+	}
+	return next_class;
+}
+
 /**
  * bfq_lookup_next_entity - return the first eligible entity in @sd.
  * @sd: the sched_data.
@@ -1448,24 +1476,8 @@ static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
 						 bool expiration)
 {
 	struct bfq_service_tree *st = sd->service_tree;
-	struct bfq_service_tree *idle_class_st = st + (BFQ_IOPRIO_CLASSES - 1);
 	struct bfq_entity *entity = NULL;
-	int class_idx = 0;
-
-	/*
-	 * Choose from idle class, if needed to guarantee a minimum
-	 * bandwidth to this class (and if there is some active entity
-	 * in idle class). This should also mitigate
-	 * priority-inversion problems in case a low priority task is
-	 * holding file system resources.
-	 */
-	if (time_is_before_jiffies(sd->bfq_class_idle_last_service +
-				   BFQ_CL_IDLE_TIMEOUT)) {
-		if (!RB_EMPTY_ROOT(&idle_class_st->active))
-			class_idx = BFQ_IOPRIO_CLASSES - 1;
-		/* About to be served if backlogged, or not yet backlogged */
-		sd->bfq_class_idle_last_service = jiffies;
-	}
+	int class_idx = bfq_select_next_class(sd);
 
 	/*
 	 * Find the next entity to serve for the highest-priority
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 4/8] bfq: expire bfqq if a higher priority class is waiting
  2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
                   ` (2 preceding siblings ...)
  2021-03-08 12:00 ` [RFC PATCH 3/8] bfq: keep the minimun bandwidth for be_class brookxu
@ 2021-03-08 12:00 ` brookxu
  2021-03-08 12:00 ` [RFC PATCH 5/8] bfq: introduce bfq.ioprio for cgroup brookxu
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

From: Chunguang Xu <brookxu@tencent.com>

Expire bfqq If a higher priority class is waiting to be served, we
can further guarantee the delay of the higher priority class.

Signed-off-by: Chunguang Xu <brookxu@tencent.com>
---
 block/bfq-iosched.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index b639cdbb4192..223affaa7c92 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -4677,7 +4677,10 @@ static struct request *bfq_dispatch_rq_from_bfqq(struct bfq_data *bfqd,
 						 struct bfq_queue *bfqq)
 {
 	struct request *rq = bfqq->next_rq;
+	struct bfq_sched_data *sd = bfqq->entity.sched_data;
+	struct bfq_service_tree *st = sd->service_tree;
 	unsigned long service_to_charge;
+	int idx;
 
 	service_to_charge = bfq_serv_to_charge(rq, bfqq);
 
@@ -4714,6 +4717,17 @@ static struct request *bfq_dispatch_rq_from_bfqq(struct bfq_data *bfqd,
 	if (!(bfq_tot_busy_queues(bfqd) > 1 && bfq_class_idle(bfqq)))
 		goto return_rq;
 
+	/*
+	 * Expire bfqq, if other queues belong to higher priority
+	 * class are waiting for service.
+	 */
+	for (idx = bfqq->ioprio_class - 2; idx >= 0; idx--) {
+		if (!RB_EMPTY_ROOT(&(st + idx)->active))
+			break;
+	}
+	if (idx < 0)
+		goto return_rq;
+
 	bfq_bfqq_expire(bfqd, bfqq, false, BFQQE_BUDGET_EXHAUSTED);
 
 return_rq:
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 5/8] bfq: introduce bfq.ioprio for cgroup
  2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
                   ` (3 preceding siblings ...)
  2021-03-08 12:00 ` [RFC PATCH 4/8] bfq: expire bfqq if a higher priority class is waiting brookxu
@ 2021-03-08 12:00 ` brookxu
  2021-03-08 12:00 ` [RFC PATCH 6/8] bfq: convert the type of bfq_group.bfqd to bfq_data* brookxu
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

From: Chunguang Xu <brookxu@tencent.com>

Tasks in the production environment can be roughly divided into
three categories: emergency tasks, ordinary tasks and offline
tasks. Emergency tasks need to be scheduled in real time, and the
amount of data for such tasks is usually not very large, such as
system agents. Offline tasks do not need to guarantee QoS, but
can improve system resource utilization during system idle
periods, such as various background tasks. The above requirements
need to achieve IO preemption. At present, we can use weights to
simulate IO preemption, but since weights are more of a shared
concept, they cannot be simulated well. For example, the weights
of emergency tasks and ordinary tasks cannot be determined well,
offline tasks (with the same weight) actually occupy different
resources on disks with different performance, and the tail delay
caused by offline tasks cannot be well controlled. Using ioprio's
concept of preemption, we can solve the above problems very well.
Second, we can still use weights to control resource isolation of
the same priority, thereby achieving better IO Qos control.

However, currently implemented by bfq, the class of bfq_group is
always be class, and the ioprio class of the task can only be
reflected in a single cgroup. We cannot guarantee that real-time
tasks in a cgroup are scheduled in time. To this end, we
introduced cgroup ioprio. In this way, we can ensure that the
real-time tasks of a cgroup can be scheduled in time. Similarly,
the processing of offline task groups can also be simpler.

To this end, we have introduced the bfq.ioprio interface for
cgroup v1 and cgroup v2. Users can configure the priority
through this interface, as shown below:

echo "1 2"> blkio.bfq.weight

The above two values respectively represent the values of ioprio
class and ioprio for cgroup. The ioprio of tasks within the cgroup
is uniformly equal to the ioprio of the cgroup. If the ioprio of
the cgroup is disabled, the ioprio of the task remains the same,
usually from io_context.

Signed-off-by: Chunguang Xu <brookxu@tencent.com>
---
 block/bfq-cgroup.c  | 87 ++++++++++++++++++++++++++++++++++++++++++++-
 block/bfq-iosched.c |  5 +++
 block/bfq-iosched.h |  8 +++++
 block/bfq-wf2q.c    | 30 +++++++++++++---
 4 files changed, 124 insertions(+), 6 deletions(-)

diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index a5f544acaa61..0b0a3514a5d2 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -489,7 +489,7 @@ static struct bfq_group_data *cpd_to_bfqgd(struct blkcg_policy_data *cpd)
 	return cpd ? container_of(cpd, struct bfq_group_data, pd) : NULL;
 }
 
-static struct bfq_group_data *blkcg_to_bfqgd(struct blkcg *blkcg)
+struct bfq_group_data *blkcg_to_bfqgd(struct blkcg *blkcg)
 {
 	return cpd_to_bfqgd(blkcg_to_cpd(blkcg, &blkcg_policy_bfq));
 }
@@ -553,6 +553,16 @@ static void bfq_pd_init(struct blkg_policy_data *pd)
 	bfqg->bfqd = bfqd;
 	bfqg->active_entities = 0;
 	bfqg->rq_pos_tree = RB_ROOT;
+
+	bfqg->new_ioprio_class = IOPRIO_PRIO_CLASS(d->ioprio);
+	bfqg->new_ioprio = IOPRIO_PRIO_DATA(d->ioprio);
+	bfqg->ioprio_class = bfqg->new_ioprio_class;
+	bfqg->ioprio = bfqg->new_ioprio;
+
+	if (d->ioprio) {
+		entity->new_weight = bfq_ioprio_to_weight(bfqg->ioprio);
+		entity->weight = entity->new_weight;
+	}
 }
 
 static void bfq_pd_free(struct blkg_policy_data *pd)
@@ -981,6 +991,20 @@ static int bfq_io_show_weight(struct seq_file *sf, void *v)
 	return 0;
 }
 
+static int bfq_io_show_ioprio(struct seq_file *sf, void *v)
+{
+	struct blkcg *blkcg = css_to_blkcg(seq_css(sf));
+	struct bfq_group_data *bfqgd = blkcg_to_bfqgd(blkcg);
+	unsigned int val = 0;
+
+	if (bfqgd)
+		val = bfqgd->ioprio;
+
+	seq_printf(sf, "%u %lu\n", IOPRIO_PRIO_CLASS(val), IOPRIO_PRIO_DATA(val));
+
+	return 0;
+}
+
 static void bfq_group_set_weight(struct bfq_group *bfqg, u64 weight, u64 dev_weight)
 {
 	weight = dev_weight ?: weight;
@@ -1098,6 +1122,55 @@ static ssize_t bfq_io_set_weight(struct kernfs_open_file *of,
 	return bfq_io_set_device_weight(of, buf, nbytes, off);
 }
 
+static ssize_t bfq_io_set_ioprio(struct kernfs_open_file *of, char *buf,
+				 size_t nbytes, loff_t off)
+{
+	struct cgroup_subsys_state *css = of_css(of);
+	struct blkcg *blkcg = css_to_blkcg(css);
+	struct bfq_group_data *bfqgd = blkcg_to_bfqgd(blkcg);
+	struct blkcg_gq *blkg;
+	unsigned int class, data;
+	char *endp;
+
+	buf = strstrip(buf);
+
+	class = simple_strtoul(buf, &endp, 10);
+	if (*endp != ' ')
+		return -EINVAL;
+	buf = endp + 1;
+
+	data = simple_strtoul(buf, &endp, 10);
+	if ((*endp != ' ') && (*endp != '\0'))
+		return -EINVAL;
+
+	if (class > IOPRIO_CLASS_IDLE || data >= IOPRIO_BE_NR)
+		return -EINVAL;
+
+	spin_lock_irq(&blkcg->lock);
+	bfqgd->ioprio = IOPRIO_PRIO_VALUE(class, data);
+	hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) {
+		struct bfq_group *bfqg = blkg_to_bfqg(blkg);
+
+		if (bfqg) {
+			if ((bfqg->ioprio_class != class) ||
+			    (bfqg->ioprio != data)) {
+				unsigned short weight;
+
+				weight = class ? bfq_ioprio_to_weight(data) :
+					BFQ_WEIGHT_LEGACY_DFL;
+
+				bfqg->new_ioprio_class = class;
+				bfqg->new_ioprio = data;
+				bfqg->entity.new_weight = weight;
+				bfqg->entity.prio_changed = 1;
+			}
+		}
+	}
+	spin_unlock_irq(&blkcg->lock);
+
+	return nbytes;
+}
+
 static int bfqg_print_rwstat(struct seq_file *sf, void *v)
 {
 	blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), blkg_prfill_rwstat,
@@ -1264,6 +1337,12 @@ struct cftype bfq_blkcg_legacy_files[] = {
 		.seq_show = bfq_io_show_weight,
 		.write = bfq_io_set_weight,
 	},
+	{
+		.name = "bfq.ioprio",
+		.flags = CFTYPE_NOT_ON_ROOT,
+		.seq_show = bfq_io_show_ioprio,
+		.write = bfq_io_set_ioprio,
+	},
 
 	/* statistics, covers only the tasks in the bfqg */
 	{
@@ -1384,6 +1463,12 @@ struct cftype bfq_blkg_files[] = {
 		.seq_show = bfq_io_show_weight,
 		.write = bfq_io_set_weight,
 	},
+	{
+		.name = "bfq.ioprio",
+		.flags = CFTYPE_NOT_ON_ROOT,
+		.seq_show = bfq_io_show_ioprio,
+		.write = bfq_io_set_ioprio,
+	},
 	{} /* terminate */
 };
 
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index 223affaa7c92..fe05d73d0fed 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -5130,7 +5130,12 @@ static void bfq_check_ioprio_change(struct bfq_io_cq *bic, struct bio *bio)
 {
 	struct bfq_data *bfqd = bic_to_bfqd(bic);
 	struct bfq_queue *bfqq;
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
+	struct bfq_group_data *bfqgd = blkcg_to_bfqgd(__bio_blkcg(bio));
+	int ioprio = bfqgd->ioprio ?: bic->icq.ioc->ioprio;
+#else
 	int ioprio = bic->icq.ioc->ioprio;
+#endif
 
 	/*
 	 * This condition may trigger on a newly created bic, be sure to
diff --git a/block/bfq-iosched.h b/block/bfq-iosched.h
index 2fe7456aa7bc..d5c05d5f9714 100644
--- a/block/bfq-iosched.h
+++ b/block/bfq-iosched.h
@@ -868,6 +868,7 @@ struct bfq_group_data {
 	struct blkcg_policy_data pd;
 
 	unsigned int weight;
+	unsigned short ioprio;
 };
 
 /**
@@ -924,6 +925,11 @@ struct bfq_group {
 
 	int active_entities;
 
+	/* current ioprio and ioprio class */
+	unsigned short ioprio, ioprio_class;
+	/* next ioprio and ioprio class if a change is in progress */
+	unsigned short new_ioprio, new_ioprio_class;
+
 	struct rb_root rq_pos_tree;
 
 	struct bfqg_stats stats;
@@ -992,6 +998,7 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
 void bfq_init_entity(struct bfq_entity *entity, struct bfq_group *bfqg);
 void bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio);
 void bfq_end_wr_async(struct bfq_data *bfqd);
+struct bfq_group_data *blkcg_to_bfqgd(struct blkcg *blkcg);
 struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd,
 				     struct blkcg *blkcg);
 struct blkcg_gq *bfqg_to_blkg(struct bfq_group *bfqg);
@@ -1038,6 +1045,7 @@ extern struct blkcg_policy blkcg_policy_bfq;
 
 struct bfq_group *bfq_bfqq_to_bfqg(struct bfq_queue *bfqq);
 struct bfq_queue *bfq_entity_to_bfqq(struct bfq_entity *entity);
+unsigned int bfq_class_idx(struct bfq_entity *entity);
 unsigned int bfq_tot_busy_queues(struct bfq_data *bfqd);
 struct bfq_service_tree *bfq_entity_service_tree(struct bfq_entity *entity);
 struct bfq_entity *bfq_entity_of(struct rb_node *node);
diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c
index 0d10eb3ed555..01172202b076 100644
--- a/block/bfq-wf2q.c
+++ b/block/bfq-wf2q.c
@@ -27,12 +27,21 @@ static struct bfq_entity *bfq_root_active_entity(struct rb_root *tree)
 	return rb_entry(node, struct bfq_entity, rb_node);
 }
 
-static unsigned int bfq_class_idx(struct bfq_entity *entity)
+unsigned int bfq_class_idx(struct bfq_entity *entity)
 {
 	struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
+	unsigned short class = BFQ_DEFAULT_GRP_CLASS;
 
-	return bfqq ? bfqq->ioprio_class - 1 :
-		BFQ_DEFAULT_GRP_CLASS - 1;
+	if (bfqq)
+		class = bfqq->ioprio_class;
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
+	else {
+		struct bfq_group *bfqg = bfq_entity_to_bfqg(entity);
+
+		class = bfqg->ioprio_class ?: BFQ_DEFAULT_GRP_CLASS;
+	}
+#endif
+	return class - 1;
 }
 
 unsigned int bfq_tot_busy_queues(struct bfq_data *bfqd)
@@ -767,14 +776,25 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
 				  bfq_weight_to_ioprio(entity->orig_weight);
 		}
 
-		if (bfqq && update_class_too)
-			bfqq->ioprio_class = bfqq->new_ioprio_class;
+		if (update_class_too) {
+			if (bfqq)
+				bfqq->ioprio_class = bfqq->new_ioprio_class;
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
+			else
+				bfqg->ioprio_class = bfqg->new_ioprio_class;
+#endif
+		}
 
 		/*
 		 * Reset prio_changed only if the ioprio_class change
 		 * is not pending any longer.
 		 */
+#ifdef CONFIG_BFQ_GROUP_IOSCHED
+		if ((bfqq && bfqq->ioprio_class == bfqq->new_ioprio_class) ||
+		    (!bfqq && bfqg->ioprio_class == bfqg->new_ioprio_class))
+#else
 		if (!bfqq || bfqq->ioprio_class == bfqq->new_ioprio_class)
+#endif
 			entity->prio_changed = 0;
 
 		/*
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 6/8] bfq: convert the type of bfq_group.bfqd to bfq_data*
  2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
                   ` (4 preceding siblings ...)
  2021-03-08 12:00 ` [RFC PATCH 5/8] bfq: introduce bfq.ioprio for cgroup brookxu
@ 2021-03-08 12:00 ` brookxu
  2021-03-08 12:00 ` [RFC PATCH 7/8] bfq: remove unnecessary initialization logic brookxu
  2021-03-08 12:00 ` [RFC PATCH 8/8] bfq: optimize the calculation of bfq_weight_to_ioprio() brookxu
  7 siblings, 0 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

From: Chunguang Xu <brookxu@tencent.com>

Setting bfq_group.bfqd to void* type does not seem to make much sense.
This will cause unnecessary type conversion. Perhaps it would be better
to change it to bfq_data* type.

Signed-off-by: Chunguang Xu <brookxu@tencent.com>
---
 block/bfq-cgroup.c  | 2 +-
 block/bfq-iosched.h | 2 +-
 block/bfq-wf2q.c    | 6 +++---
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index 0b0a3514a5d2..ab4bc410e635 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -224,7 +224,7 @@ void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq,
 {
 	blkg_rwstat_add(&bfqg->stats.queued, op, 1);
 	bfqg_stats_end_empty_time(&bfqg->stats);
-	if (!(bfqq == ((struct bfq_data *)bfqg->bfqd)->in_service_queue))
+	if (!(bfqq == bfqg->bfqd->in_service_queue))
 		bfqg_stats_set_start_group_wait_time(bfqg, bfqq_group(bfqq));
 }
 
diff --git a/block/bfq-iosched.h b/block/bfq-iosched.h
index d5c05d5f9714..ab44b10ece1d 100644
--- a/block/bfq-iosched.h
+++ b/block/bfq-iosched.h
@@ -916,7 +916,7 @@ struct bfq_group {
 	struct bfq_entity entity;
 	struct bfq_sched_data sched_data;
 
-	void *bfqd;
+	struct bfq_data *bfqd;
 
 	struct bfq_queue *async_bfqq[2][IOPRIO_BE_NR];
 	struct bfq_queue *async_idle_bfqq;
diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c
index 01172202b076..850a8e2f0bda 100644
--- a/block/bfq-wf2q.c
+++ b/block/bfq-wf2q.c
@@ -507,7 +507,7 @@ static void bfq_active_insert(struct bfq_service_tree *st,
 #ifdef CONFIG_BFQ_GROUP_IOSCHED
 	sd = entity->sched_data;
 	bfqg = container_of(sd, struct bfq_group, sched_data);
-	bfqd = (struct bfq_data *)bfqg->bfqd;
+	bfqd = bfqg->bfqd;
 #endif
 	if (bfqq)
 		list_add(&bfqq->bfqq_list, &bfqq->bfqd->active_list);
@@ -606,7 +606,7 @@ static void bfq_active_extract(struct bfq_service_tree *st,
 #ifdef CONFIG_BFQ_GROUP_IOSCHED
 	sd = entity->sched_data;
 	bfqg = container_of(sd, struct bfq_group, sched_data);
-	bfqd = (struct bfq_data *)bfqg->bfqd;
+	bfqd = bfqg->bfqd;
 #endif
 	if (bfqq)
 		list_del(&bfqq->bfqq_list);
@@ -752,7 +752,7 @@ __bfq_entity_update_weight_prio(struct bfq_service_tree *old_st,
 		else {
 			sd = entity->my_sched_data;
 			bfqg = container_of(sd, struct bfq_group, sched_data);
-			bfqd = (struct bfq_data *)bfqg->bfqd;
+			bfqd = bfqg->bfqd;
 		}
 #endif
 
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 7/8] bfq: remove unnecessary initialization logic
  2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
                   ` (5 preceding siblings ...)
  2021-03-08 12:00 ` [RFC PATCH 6/8] bfq: convert the type of bfq_group.bfqd to bfq_data* brookxu
@ 2021-03-08 12:00 ` brookxu
  2021-03-08 12:00 ` [RFC PATCH 8/8] bfq: optimize the calculation of bfq_weight_to_ioprio() brookxu
  7 siblings, 0 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

From: Chunguang Xu <brookxu@tencent.com>

Since we will initialize sched_data.service_tree[] in
bfq_init_root_group(), bfq_create_group_hierarchy() can
ignore this part of the initialization, which can avoid
repeated initialization.

Signed-off-by: Chunguang Xu <brookxu@tencent.com>
---
 block/bfq-cgroup.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index ab4bc410e635..05054e1b5d97 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -1514,15 +1514,11 @@ void bfqg_and_blkg_put(struct bfq_group *bfqg) {}
 struct bfq_group *bfq_create_group_hierarchy(struct bfq_data *bfqd, int node)
 {
 	struct bfq_group *bfqg;
-	int i;
 
 	bfqg = kmalloc_node(sizeof(*bfqg), GFP_KERNEL | __GFP_ZERO, node);
 	if (!bfqg)
 		return NULL;
 
-	for (i = 0; i < BFQ_IOPRIO_CLASSES; i++)
-		bfqg->sched_data.service_tree[i] = BFQ_SERVICE_TREE_INIT;
-
 	return bfqg;
 }
 #endif	/* CONFIG_BFQ_GROUP_IOSCHED */
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 8/8] bfq: optimize the calculation of bfq_weight_to_ioprio()
  2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
                   ` (6 preceding siblings ...)
  2021-03-08 12:00 ` [RFC PATCH 7/8] bfq: remove unnecessary initialization logic brookxu
@ 2021-03-08 12:00 ` brookxu
  7 siblings, 0 replies; 9+ messages in thread
From: brookxu @ 2021-03-08 12:00 UTC (permalink / raw)
  To: paolo.valente, axboe, tj; +Cc: linux-block, cgroups, linux-kernel

From: Chunguang Xu <brookxu@tencent.com>

From: Chunguang Xu <brookxu@tencent.com>

The value range of ioprio is [0, 7], but the result of
bfq_weight_to_ioprio() may exceed this range, so simple
optimization is required.

Signed-off-by: Chunguang Xu <brookxu@tencent.com>
---
 block/bfq-wf2q.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c
index 850a8e2f0bda..1d565daf516f 100644
--- a/block/bfq-wf2q.c
+++ b/block/bfq-wf2q.c
@@ -536,8 +536,9 @@ unsigned short bfq_ioprio_to_weight(int ioprio)
  */
 static unsigned short bfq_weight_to_ioprio(int weight)
 {
-	return max_t(int, 0,
-		     IOPRIO_BE_NR * BFQ_WEIGHT_CONVERSION_COEFF - weight);
+	int ioprio = IOPRIO_BE_NR  - weight / BFQ_WEIGHT_CONVERSION_COEFF;
+
+	return ioprio < 0 ? 0 : min_t(int, ioprio, IOPRIO_BE_NR - 1);
 }
 
 static void bfq_get_entity(struct bfq_entity *entity)
-- 
2.30.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-03-08 12:01 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-08 12:00 [RFC PATCH 0/8] bfq: introduce bfq.ioprio for cgroup brookxu
2021-03-08 12:00 ` [RFC PATCH 1/8] bfq: introduce bfq_entity_to_bfqg helper method brookxu
2021-03-08 12:00 ` [RFC PATCH 2/8] bfq: limit the IO depth of idle_class to 1 brookxu
2021-03-08 12:00 ` [RFC PATCH 3/8] bfq: keep the minimun bandwidth for be_class brookxu
2021-03-08 12:00 ` [RFC PATCH 4/8] bfq: expire bfqq if a higher priority class is waiting brookxu
2021-03-08 12:00 ` [RFC PATCH 5/8] bfq: introduce bfq.ioprio for cgroup brookxu
2021-03-08 12:00 ` [RFC PATCH 6/8] bfq: convert the type of bfq_group.bfqd to bfq_data* brookxu
2021-03-08 12:00 ` [RFC PATCH 7/8] bfq: remove unnecessary initialization logic brookxu
2021-03-08 12:00 ` [RFC PATCH 8/8] bfq: optimize the calculation of bfq_weight_to_ioprio() brookxu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).