]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
abstraction: Add support for unmappable settings
authorTom Hromatka <tom.hromatka@oracle.com>
Wed, 15 Dec 2021 21:13:29 +0000 (21:13 +0000)
committerTom Hromatka <tom.hromatka@oracle.com>
Thu, 3 Feb 2022 21:42:37 +0000 (14:42 -0700)
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 <tom.hromatka@oracle.com>
Reviewed-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
include/libcgroup/error.h
src/abstraction-common.c
src/abstraction-common.h
src/libcgroup-internal.h
src/wrapper.c

index 14a6e16818c0a241cc173a3e8b86113a9e01c94a..6d0c314cfed2b5061adb2acc506e6fe0e1b5a0ba 100644 (file)
@@ -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,
 };
 
 /**
index e6d51443a85739818db8072933ecb83109711bb2..35c0aba81176859081f7911b4395e8707c8947f7 100644 (file)
@@ -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;
 }
index e24b89c3dcb5875d8591aa6edc68756aabbd6d45..960d1575d729607b8878a53405e0b72662edd2fb 100644 (file)
@@ -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);
index a63244d1df2b21705bd03f7363f30972e48c3605..16a9265887911602a6500317b57260c7b7b90879 100644 (file)
@@ -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
index 77467d3519bef928521388b279631ae26d4ae665..3d50c5a7c2e6cda8b4c8dec5b19605f263a20cc5 100644 (file)
@@ -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;