Add a function - cgroup_convert_cgroup() - that can convert from
one cgroup version to another.  This function will be the building
block for the libcgroup abstraction layer.

Signed-off-by: Tom Hromatka <tom.hroma...@oracle.com>
---
 src/abstraction-common.c | 103 +++++++++++++++++++++++++++++++++++++++
 src/abstraction-common.h |  17 +++++++
 src/libcgroup-internal.h |   1 +
 src/libcgroup.map        |   4 ++
 4 files changed, 125 insertions(+)

diff --git a/src/abstraction-common.c b/src/abstraction-common.c
index df5fa1b3a452..e0e3984006b7 100644
--- a/src/abstraction-common.c
+++ b/src/abstraction-common.c
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include "abstraction-common.h"
+#include "abstraction-map.h"
 
 int cgroup_strtol(const char * const in_str, int base,
                  long int * const out_value)
@@ -108,3 +109,105 @@ out:
 
        return ret;
 }
+
+static int convert_setting(struct cgroup_controller * const out_cgc,
+                          const struct control_value * const in_ctrl_val)
+{
+       const struct cgroup_abstraction_map *convert_tbl;
+       int tbl_sz = 0;
+       int ret = ECGINVAL;
+       int i;
+
+       switch (out_cgc->version) {
+       case CGROUP_V1:
+               convert_tbl = cgroup_v2_to_v1_map;
+               tbl_sz = cgroup_v2_to_v1_map_sz;
+               break;
+       case CGROUP_V2:
+               convert_tbl = cgroup_v1_to_v2_map;
+               tbl_sz = cgroup_v1_to_v2_map_sz;
+               break;
+       default:
+               ret = ECGFAIL;
+               goto out;
+       }
+
+       for (i = 0; i < tbl_sz; i++) {
+               if (strcmp(convert_tbl[i].in_setting, in_ctrl_val->name) == 0) {
+                       ret = convert_tbl[i].cgroup_convert(out_cgc,
+                                       in_ctrl_val->value,
+                                       convert_tbl[i].out_setting,
+                                       convert_tbl[i].in_dflt,
+                                       convert_tbl[i].out_dflt);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+out:
+       return ret;
+}
+
+static int convert_controller(struct cgroup_controller * const out_cgc,
+                             const struct cgroup_controller * const in_cgc)
+{
+       int ret;
+       int i;
+
+
+       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;
+       }
+
+       for (i = 0; i < in_cgc->index; i++) {
+               ret = convert_setting(out_cgc, in_cgc->values[i]);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       return ret;
+}
+
+int cgroup_convert_cgroup(struct cgroup * const out_cgroup,
+                         enum cg_version_t out_version,
+                         const struct cgroup * const in_cgroup,
+                         enum cg_version_t in_version)
+{
+       struct cgroup_controller *cgc;
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < in_cgroup->index; i++) {
+               cgc = cgroup_add_controller(out_cgroup,
+                                           in_cgroup->controller[i]->name);
+               if (cgc == NULL) {
+                       ret = ECGFAIL;
+                       goto out;
+               }
+
+               /* the user has overridden the version */
+               if (in_version == CGROUP_V1 || in_version == CGROUP_V2) {
+                       in_cgroup->controller[i]->version = in_version;
+               }
+
+               cgc->version = out_version;
+
+               if (cgc->version == CGROUP_UNK ||
+                   cgc->version == CGROUP_DISK) {
+                       ret = cgroup_get_controller_version(cgc->name,
+                               &cgc->version);
+                       if (ret)
+                               goto out;
+               }
+
+               ret = convert_controller(cgc, in_cgroup->controller[i]);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       return ret;
+}
diff --git a/src/abstraction-common.h b/src/abstraction-common.h
index 02f7b9ff9541..69a28538e091 100644
--- a/src/abstraction-common.h
+++ b/src/abstraction-common.h
@@ -57,6 +57,23 @@ int cgroup_convert_int(struct cgroup_controller * const 
dst_cgc,
                       const char * const out_setting,
                       void *in_dflt, void *out_dflt);
 
+/*
+ * Convert from one cgroup version to another version
+ *
+ * @param out_cgroup Destination cgroup
+ * @param out_version Destination cgroup version
+ * @param in_cgroup Source cgroup
+ * @param in_version Source cgroup version, only used if set to v1 or v2
+ *
+ * @return 0 on success
+ *         ECGFAIL conversion failed
+ *         ECGCONTROLLERNOTEQUAL incorrect controller version provided
+ */
+int cgroup_convert_cgroup(struct cgroup * const out_cgroup,
+                         enum cg_version_t out_version,
+                         const struct cgroup * const in_cgroup,
+                         enum cg_version_t in_version);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h
index 34c5be703920..6d9de03a00bc 100644
--- a/src/libcgroup-internal.h
+++ b/src/libcgroup-internal.h
@@ -89,6 +89,7 @@ enum cg_version_t {
        CGROUP_UNK = 0,
        CGROUP_V1,
        CGROUP_V2,
+       CGROUP_DISK = 0xFF,
 };
 
 struct control_value {
diff --git a/src/libcgroup.map b/src/libcgroup.map
index 68098cd3accb..d99a2ce73c04 100644
--- a/src/libcgroup.map
+++ b/src/libcgroup.map
@@ -139,3 +139,7 @@ CGROUP_2.0 {
        cg_mount_table_lock;
        cgroup_get_controller_version;
 } CGROUP_0.42;
+
+CGROUP_3.0 {
+       cgroup_convert_cgroup;
+} CGROUP_2.0;
-- 
2.25.1



_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to