From: Tom Hromatka Date: Wed, 15 Dec 2021 21:13:29 +0000 (+0000) Subject: abstraction: Add support for unmappable settings X-Git-Tag: v3.0~223 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=209110292ee135a442c11186cfa2e43a7d302522;p=thirdparty%2Flibcgroup.git abstraction: Add support for unmappable settings Add a function to explicitly handle settings that cannot be mapped from v1 to v2 or vice versa. This function returns ECGNOVERSIONCONVERT which cgxget, cgxset, etc. can then monitor and if requested by the user, ignore. Signed-off-by: Tom Hromatka Reviewed-by: Kamalesh Babulal --- diff --git a/include/libcgroup/error.h b/include/libcgroup/error.h index 14a6e168..6d0c314c 100644 --- a/include/libcgroup/error.h +++ b/include/libcgroup/error.h @@ -74,6 +74,8 @@ enum { ECGCANTSETVALUE, /** Removing of a group failed because it was not empty. */ ECGNONEMPTY, + /** Failed to convert from cgroup v1 to/from cgroup v2 */ + ECGNOVERSIONCONVERT, }; /** diff --git a/src/abstraction-common.c b/src/abstraction-common.c index e6d51443..35c0aba8 100644 --- a/src/abstraction-common.c +++ b/src/abstraction-common.c @@ -132,6 +132,14 @@ int cgroup_convert_passthrough(struct cgroup_controller * const dst_cgc, return cgroup_add_value_string(dst_cgc, out_setting, in_value); } +int cgroup_convert_unmappable(struct cgroup_controller * const dst_cgc, + const char * const in_value, + const char * const out_setting, + void *in_dflt, void *out_dflt) +{ + return ECGNOVERSIONCONVERT; +} + static int convert_setting(struct cgroup_controller * const out_cgc, const struct control_value * const in_ctrl_val) { @@ -182,32 +190,60 @@ out: return ret; } -static int convert_controller(struct cgroup_controller * const out_cgc, +static int convert_controller(struct cgroup_controller ** const out_cgc, struct cgroup_controller * const in_cgc) { + bool unmappable = false; int ret; int i; - if (in_cgc->version == out_cgc->version) { - ret = cgroup_copy_controller_values(out_cgc, in_cgc); + if (in_cgc->version == (*out_cgc)->version) { + ret = cgroup_copy_controller_values(*out_cgc, in_cgc); /* regardless of success/failure, there's nothing more to do */ goto out; } if (strcmp(in_cgc->name, "cpu") == 0) { - ret = cgroup_convert_cpu_nto1(out_cgc, in_cgc); + ret = cgroup_convert_cpu_nto1(*out_cgc, in_cgc); if (ret) goto out; } for (i = 0; i < in_cgc->index; i++) { - ret = convert_setting(out_cgc, in_cgc->values[i]); - if (ret) + ret = convert_setting(*out_cgc, in_cgc->values[i]); + if (ret == ECGNOVERSIONCONVERT) { + /* + * Ignore unmappable errors while they happen, as + * there may be mappable settings after that + */ + unmappable = true; + ret = 0; + } else if (ret) { + /* immediately fail on all other errors */ goto out; + } } out: + if (ret == 0 && unmappable) { + /* + * The only error received was an unmappable error. + * Return it. + */ + ret = ECGNOVERSIONCONVERT; + + if ((*out_cgc)->index == 0) { + /* + * No settings were successfully converted. Remove + * this controller so that tools like cgxget aren't + * confused + */ + cgroup_free_controller(*out_cgc); + *out_cgc = NULL; + } + } + return ret; } @@ -217,6 +253,7 @@ int cgroup_convert_cgroup(struct cgroup * const out_cgroup, enum cg_version_t in_version) { struct cgroup_controller *cgc; + bool unmappable = false; int ret = 0; int i; @@ -243,11 +280,34 @@ int cgroup_convert_cgroup(struct cgroup * const out_cgroup, goto out; } - ret = convert_controller(cgc, in_cgroup->controller[i]); - if (ret) + ret = convert_controller(&cgc, in_cgroup->controller[i]); + if (ret == ECGNOVERSIONCONVERT) { + /* + * Ignore unmappable errors while they happen, as + * there may be mappable settings after that + */ + unmappable = true; + + if (!cgc) + /* + * The converted controller had no settings + * and was removed. It's up to us to manage + * the controller count + */ + out_cgroup->index--; + } else if (ret) { + /* immediately fail on all other errors */ goto out; + } } out: + if (ret == 0 && unmappable) + /* + * The only error received was an unmappable error. + * Return it. + */ + ret = ECGNOVERSIONCONVERT; + return ret; } diff --git a/src/abstraction-common.h b/src/abstraction-common.h index e24b89c3..960d1575 100644 --- a/src/abstraction-common.h +++ b/src/abstraction-common.h @@ -86,6 +86,21 @@ int cgroup_convert_passthrough(struct cgroup_controller * const dst_cgc, const char * const out_setting, void *in_dflt, void *out_dflt); +/** + * Convert from an unmapple setting + * + * @param dst_cgc Destination cgroup controller (unused) + * @param in_value Contents of the input setting (unsed) + * @param out_setting Destination cgroup setting (unused) + * @param in_dflt Default value of the input setting (unused) + * @param out_dflt Default value of the output setting (unused) + * @return Always returns ECGNOVERSIONCONVERT + */ +int cgroup_convert_unmappable(struct cgroup_controller * const dst_cgc, + const char * const in_value, + const char * const out_setting, + void *in_dflt, void *out_dflt); + /* cpu */ int cgroup_convert_cpu_nto1(struct cgroup_controller * const out_cgc, struct cgroup_controller * const in_cgc); diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h index a63244d1..16a92658 100644 --- a/src/libcgroup-internal.h +++ b/src/libcgroup-internal.h @@ -388,6 +388,14 @@ int cgroup_copy_controller_values(struct cgroup_controller * const dst, int cgroup_remove_value(struct cgroup_controller * const controller, const char * const name); +/** + * Free the specified controller from the group. + * @param ctrl + * + * Note it's up to the caller to decrement the cgroup's index + */ +void cgroup_free_controller(struct cgroup_controller *ctrl); + /** * Functions that are defined as STATIC can be placed within the UNIT_TEST * ifdef. This will allow them to be included in the unit tests while diff --git a/src/wrapper.c b/src/wrapper.c index 77467d35..3d50c5a7 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -169,7 +169,7 @@ static void cgroup_free_value(struct control_value *value) free(value); } -static void cgroup_free_controller(struct cgroup_controller *ctrl) +void cgroup_free_controller(struct cgroup_controller *ctrl) { int i;