From 55af1d4ce32a32ebd3106cbdf1ef8b6cda55175f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Wed, 25 Aug 2021 01:28:47 +0900
Subject: [PATCH] core/cgroup: set bfq.weight first, and fixes blkio.weight
 value

Fixes issues introduced by 29eb0eefd14afc9a2424781a28b376db47c3c570.

This also fixes the value sets to blkio.weight, that is, "default" is dropped.

Moreover, This also changes the logic for mapping weight -> bfq.weight,
to always matches the min, max, and default values.

Fixes #20519 and #21187.

(cherry picked from commit 17283ce7b6035775f125585d1b228226942daf4b)

Conflict:NA
Reference:https://github.com/systemd/systemd/commit/55af1d4ce32a32ebd3106cbdf1ef8b6cda55175f
---
 src/core/cgroup.c | 55 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 44 insertions(+), 11 deletions(-)

diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 79e10ca3c0..8b5b403ae8 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -37,6 +37,12 @@
 
 #define CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
 
+/* Special values for the bfq.weight attribute */
+#define CGROUP_BFQ_WEIGHT_INVALID UINT64_MAX
+#define CGROUP_BFQ_WEIGHT_MIN UINT64_C(1)
+#define CGROUP_BFQ_WEIGHT_MAX UINT64_C(1000)
+#define CGROUP_BFQ_WEIGHT_DEFAULT UINT64_C(100)
+
 /* Returns the log level to use when cgroup attribute writes fail. When an attribute is missing or we have access
  * problems we downgrade to LOG_DEBUG. This is supposed to be nice to container managers and kernels which want to mask
  * out specific attributes from us. */
@@ -1194,21 +1200,48 @@ static int cgroup_apply_devices(Unit *u) {
         return r;
 }
 
-static void set_io_weight(Unit *u, const char *controller, uint64_t weight) {
-        char buf[8+DECIMAL_STR_MAX(uint64_t)+1];
-        const char *p;
+static void set_io_weight(Unit *u, uint64_t weight) {
+        char buf[STRLEN("default \n")+DECIMAL_STR_MAX(uint64_t)];
+        uint64_t bfq_weight;
+
+        assert(u);
+
+        /* FIXME: drop this when distro kernels properly support BFQ through "io.weight"
+         * See also: https://github.com/systemd/systemd/pull/13335 and
+         * https://github.com/torvalds/linux/commit/65752aef0a407e1ef17ec78a7fc31ba4e0b360f9.
+         * The range is 1..1000 apparently, and the default is 100. */
+        if (weight <= CGROUP_WEIGHT_DEFAULT)
+                bfq_weight = CGROUP_BFQ_WEIGHT_DEFAULT - (CGROUP_WEIGHT_DEFAULT - weight) * (CGROUP_BFQ_WEIGHT_DEFAULT - CGROUP_BFQ_WEIGHT_MIN) / (CGROUP_WEIGHT_DEFAULT - CGROUP_WEIGHT_MIN);
+        else
+                bfq_weight = CGROUP_BFQ_WEIGHT_DEFAULT + (weight - CGROUP_WEIGHT_DEFAULT) * (CGROUP_BFQ_WEIGHT_MAX - CGROUP_BFQ_WEIGHT_DEFAULT) / (CGROUP_WEIGHT_MAX - CGROUP_WEIGHT_DEFAULT);
+
+        xsprintf(buf, "%" PRIu64 "\n", bfq_weight);
+        (void) set_attribute_and_warn(u, "io", "io.bfq.weight", buf);
 
-        p = strjoina(controller, ".weight");
         xsprintf(buf, "default %" PRIu64 "\n", weight);
-        (void) set_attribute_and_warn(u, controller, p, buf);
+        (void) set_attribute_and_warn(u, "io", "io.weight", buf);
+}
+
+static void set_blkio_weight(Unit *u, uint64_t weight) {
+        char buf[STRLEN("\n")+DECIMAL_STR_MAX(uint64_t)];
+        uint64_t bfq_weight;
+
+        assert(u);
 
         /* FIXME: drop this when distro kernels properly support BFQ through "io.weight"
          * See also: https://github.com/systemd/systemd/pull/13335 and
          * https://github.com/torvalds/linux/commit/65752aef0a407e1ef17ec78a7fc31ba4e0b360f9.
-         * The range is 1..1000 apparently. */
-        p = strjoina(controller, ".bfq.weight");
-        xsprintf(buf, "%" PRIu64 "\n", (weight + 9) / 10);
-        (void) set_attribute_and_warn(u, controller, p, buf);
+         * The range is 1..1000 apparently, and the default is 100. */
+        if (weight <= CGROUP_BLKIO_WEIGHT_DEFAULT)
+                bfq_weight = CGROUP_BFQ_WEIGHT_DEFAULT - (CGROUP_BLKIO_WEIGHT_DEFAULT - weight) * (CGROUP_BFQ_WEIGHT_DEFAULT - CGROUP_BFQ_WEIGHT_MIN) / (CGROUP_BLKIO_WEIGHT_DEFAULT - CGROUP_BLKIO_WEIGHT_MIN);
+        else
+                bfq_weight = CGROUP_BFQ_WEIGHT_DEFAULT + (weight - CGROUP_BLKIO_WEIGHT_DEFAULT) * (CGROUP_BFQ_WEIGHT_MAX - CGROUP_BFQ_WEIGHT_DEFAULT) / (CGROUP_BLKIO_WEIGHT_MAX - CGROUP_BLKIO_WEIGHT_DEFAULT);
+
+        xsprintf(buf, "%" PRIu64 "\n", bfq_weight);
+        (void) set_attribute_and_warn(u, "blkio", "blkio.bfq.weight", buf);
+
+        xsprintf(buf, "%" PRIu64 "\n", weight);
+        (void) set_attribute_and_warn(u, "blkio", "blkio.weight", buf);
 }
 
 static void cgroup_apply_bpf_foreign_program(Unit *u) {
@@ -1322,7 +1355,7 @@ static void cgroup_context_apply(
                 } else
                         weight = CGROUP_WEIGHT_DEFAULT;
 
-                set_io_weight(u, "io", weight);
+                set_io_weight(u, weight);
 
                 if (has_io) {
                         CGroupIODeviceLatency *latency;
@@ -1392,7 +1425,7 @@ static void cgroup_context_apply(
                         else
                                 weight = CGROUP_BLKIO_WEIGHT_DEFAULT;
 
-                        set_io_weight(u, "blkio", weight);
+                        set_blkio_weight(u, weight);
 
                         if (has_io) {
                                 CGroupIODeviceWeight *w;
-- 
2.33.0

