From 5631509ba35a714a7de79b7d7328ac626065e59e Mon Sep 17 00:00:00 2001 From: Tom Hromatka Date: Wed, 15 Dec 2021 20:37:37 +0000 Subject: [PATCH] api.c/wrapper/abstraction: Save previous setting name in control_value When there's an N->1 mapping, the abstraction layer needs to know which "1" setting to map back to. Add a field to struct control_value that saves off the original setting, so that the abstraction layer can know how to map back from an N->1 setting. A good example of this is cpu.max/cpu.cfs_quota_us. The abstraction layer will map cpu.cfs_quota_us to cpu.max. During the return conversion, the abstraction layer needs to know whether to map cpu.max to cfs_quota_us or cfs_period_us. Signed-off-by: Tom Hromatka Reviewed-by: Kamalesh Babulal --- src/abstraction-common.c | 14 +++++++++++++- src/api.c | 15 +++++++++++++++ src/libcgroup-internal.h | 7 +++++++ src/wrapper.c | 2 ++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/abstraction-common.c b/src/abstraction-common.c index a93bf322..6852afcb 100644 --- a/src/abstraction-common.c +++ b/src/abstraction-common.c @@ -155,7 +155,19 @@ static int convert_setting(struct cgroup_controller * const out_cgc, } for (i = 0; i < tbl_sz; i++) { - if (strcmp(convert_tbl[i].in_setting, in_ctrl_val->name) == 0) { + /* + * For a few settings, e.g. cpu.max <-> cpu.cfs_quota_us/ + * cpu.cfs_period_us, the conversion from the N->1 field + * (cpu.max) back to one of the other settings cannot be done + * without prior knowledge of our desired setting (quota or + * period in this example). If prev_name is set, it can guide + * us back to the correct mapping. + */ + if (strcmp(convert_tbl[i].in_setting, in_ctrl_val->name) == 0 && + (in_ctrl_val->prev_name == NULL || + strcmp(in_ctrl_val->prev_name, + convert_tbl[i].out_setting) == 0)) { + ret = convert_tbl[i].cgroup_convert(out_cgc, in_ctrl_val->value, convert_tbl[i].out_setting, diff --git a/src/api.c b/src/api.c index e2ff6441..5fbf0248 100644 --- a/src/api.c +++ b/src/api.c @@ -2296,6 +2296,18 @@ int cgroup_copy_controller_values(struct cgroup_controller * const dst, dst_val->multiline_value = NULL; } + if (src_val->prev_name) { + dst_val->prev_name = + strdup(src_val->prev_name); + if (!dst_val->prev_name) { + last_errno = errno; + ret = ECGOTHER; + goto err; + } + } else { + dst_val->prev_name = NULL; + } + dst_val->dirty = src_val->dirty; } @@ -2308,6 +2320,9 @@ err: if (dst->values[i]->multiline_value) free(dst->values[i]->multiline_value); + if (dst->values[i]->prev_name) + free(dst->values[i]->prev_name); + free(dst->values[i]); } } diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h index 616271fe..056085bc 100644 --- a/src/libcgroup-internal.h +++ b/src/libcgroup-internal.h @@ -93,6 +93,13 @@ struct control_value { /* cgget uses this field for values that span multiple lines */ char *multiline_value; + + /* + * The abstraction layer uses prev_name when there's an N->1 or + * 1->N relationship between cgroup v1 and v2 settings. + */ + char *prev_name; + bool dirty; }; diff --git a/src/wrapper.c b/src/wrapper.c index 2b287656..150e6c4b 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -170,6 +170,8 @@ void cgroup_free_controllers(struct cgroup *cgroup) for (j = 0; j < cgroup->controller[i]->index; j++) { if (cgroup->controller[i]->values[j]->multiline_value) free(cgroup->controller[i]->values[j]->multiline_value); + if (cgroup->controller[i]->values[j]->prev_name) + free(cgroup->controller[i]->values[j]->prev_name); free(cgroup->controller[i]->values[j]); } -- 2.47.2