cgroup: add cgroup_parse_float()
authorTejun Heo <tj@kernel.org>
Mon, 13 May 2019 19:37:17 +0000 (12:37 -0700)
committerTejun Heo <tj@kernel.org>
Fri, 31 May 2019 18:48:40 +0000 (11:48 -0700)
cgroup already uses floating point for percent[ile] numbers and there
are several controllers which want to take them as input.  Add a
generic parse helper to handle inputs.

Update the interface convention documentation about the use of
percentage numbers.  While at it, also clarify the default time unit.

Signed-off-by: Tejun Heo <tj@kernel.org>
Documentation/admin-guide/cgroup-v2.rst
include/linux/cgroup.h
kernel/cgroup/cgroup.c

index 88e7460..73b0c0d 100644 (file)
@@ -696,6 +696,12 @@ Conventions
   informational files on the root cgroup which end up showing global
   information available elsewhere shouldn't exist.
 
+- The default time unit is microseconds.  If a different unit is ever
+  used, an explicit unit suffix must be present.
+
+- A parts-per quantity should use a percentage decimal with at least
+  two digit fractional part - e.g. 13.40.
+
 - If a controller implements weight based resource distribution, its
   interface file should be named "weight" and have the range [1,
   10000] with 100 as the default.  The values are chosen to allow
index 0297f93..3745ecd 100644 (file)
@@ -131,6 +131,8 @@ void cgroup_free(struct task_struct *p);
 int cgroup_init_early(void);
 int cgroup_init(void);
 
+int cgroup_parse_float(const char *input, unsigned dec_shift, s64 *v);
+
 /*
  * Iteration helpers and macros.
  */
index a7df319..7dffcfe 100644 (file)
@@ -6387,4 +6387,47 @@ static int __init cgroup_sysfs_init(void)
        return sysfs_create_group(kernel_kobj, &cgroup_sysfs_attr_group);
 }
 subsys_initcall(cgroup_sysfs_init);
+
+static u64 power_of_ten(int power)
+{
+       u64 v = 1;
+       while (power--)
+               v *= 10;
+       return v;
+}
+
+/**
+ * cgroup_parse_float - parse a floating number
+ * @input: input string
+ * @dec_shift: number of decimal digits to shift
+ * @v: output
+ *
+ * Parse a decimal floating point number in @input and store the result in
+ * @v with decimal point right shifted @dec_shift times.  For example, if
+ * @input is "12.3456" and @dec_shift is 3, *@v will be set to 12345.
+ * Returns 0 on success, -errno otherwise.
+ *
+ * There's nothing cgroup specific about this function except that it's
+ * currently the only user.
+ */
+int cgroup_parse_float(const char *input, unsigned dec_shift, s64 *v)
+{
+       s64 whole, frac = 0;
+       int fstart = 0, fend = 0, flen;
+
+       if (!sscanf(input, "%lld.%n%lld%n", &whole, &fstart, &frac, &fend))
+               return -EINVAL;
+       if (frac < 0)
+               return -EINVAL;
+
+       flen = fend > fstart ? fend - fstart : 0;
+       if (flen < dec_shift)
+               frac *= power_of_ten(dec_shift - flen);
+       else
+               frac = DIV_ROUND_CLOSEST_ULL(frac, power_of_ten(flen - dec_shift));
+
+       *v = whole * power_of_ten(dec_shift) + frac;
+       return 0;
+}
+
 #endif /* CONFIG_SYSFS */