From: Tejun Heo tj@kernel.org
mainline inclusion from mainline-5.3-rc1 commit a5e112e6424adb77d953eac20e6936b952fd6b32 category: feature bugzilla: 38688 CVE: NA
---------------------------
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 Signed-off-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Hou Tao houtao1@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- Documentation/admin-guide/cgroup-v2.rst | 6 ++++ include/linux/cgroup.h | 2 ++ kernel/cgroup/cgroup.c | 43 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+)
diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index 184193bcb262a..5094ca1bf9509 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -694,6 +694,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 diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 02da4e1def61e..d4d3a3acb9ab3 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -130,6 +130,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. */ diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 4aa4821a9c6aa..bcdd8030ac742 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -6076,4 +6076,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 */