diff --git a/src/Makefile.am b/src/Makefile.am index 50065cf9..c145d86e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,6 +31,7 @@ lib_LTLIBRARIES = libcgroup.la libcgroup_la_SOURCES = parse.h parse.y lex.l api.c config.c libcgroup-internal.h libcgroup.map \ wrapper.c log.c abstraction-common.c abstraction-common.h \ abstraction-map.c abstraction-map.h abstraction-cpu.c abstraction-cpuset.c \ + abstraction-memory.c \ systemd.c tools/cgxget.c tools/cgxset.c libcgroup_la_LIBADD = -lpthread $(CODE_COVERAGE_LIBS) @@ -47,7 +48,8 @@ noinst_LTLIBRARIES = libcgroupfortesting.la libcgroupfortesting_la_SOURCES = parse.h parse.y lex.l api.c config.c libcgroup-internal.h \ libcgroup.map wrapper.c log.c abstraction-common.c \ abstraction-common.h abstraction-map.c abstraction-map.h \ - abstraction-cpu.c abstraction-cpuset.c systemd.c + abstraction-cpu.c abstraction-cpuset.c abstraction-memory.c \ + systemd.c libcgroupfortesting_la_LIBADD = -lpthread $(CODE_COVERAGE_LIBS) libcgroupfortesting_la_CFLAGS = $(CODE_COVERAGE_CFLAGS) -DSTATIC= -DUNIT_TEST diff --git a/src/abstraction-common.h b/src/abstraction-common.h index 9507e583..97290faa 100644 --- a/src/abstraction-common.h +++ b/src/abstraction-common.h @@ -112,6 +112,23 @@ int cgroup_convert_cpuset_to_partition(struct cgroup_controller * const dst_cgc, const char * const in_value, const char * const out_setting, void *in_dflt, void *out_dflt); +/* memory */ +int cgroup_convert_memory_max_limit_to_max(struct cgroup_controller * const dst_cgc, + const char * const in_value, const char * const out_setting, + void *in_dflt, void *out_dflt); + +int cgroup_convert_memory_high_limit_to_max(struct cgroup_controller * const dst_cgc, + const char * const in_value, const char * const out_setting, + void *in_dflt, void *out_dflt); + +int cgroup_convert_memory_max_max_to_limit(struct cgroup_controller * const dst_cgc, + const char * const in_value, const char * const out_setting, + void *in_dflt, void *out_dflt); + +int cgroup_convert_memory_high_max_to_limit(struct cgroup_controller * const dst_cgc, + const char * const in_value, const char * const out_setting, + void *in_dflt, void *out_dflt); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/abstraction-map.c b/src/abstraction-map.c index 3e63b9d5..d9a9a900 100644 --- a/src/abstraction-map.c +++ b/src/abstraction-map.c @@ -41,6 +41,12 @@ const struct cgroup_abstraction_map cgroup_v1_to_v2_map[] = { {cgroup_convert_unmappable, "cpuset.memory_spread_slab", NULL, NULL, NULL}, {cgroup_convert_unmappable, "cpuset.sched_load_balance", NULL, NULL, NULL}, {cgroup_convert_unmappable, "cpuset.sched_relax_domain_level", NULL, NULL, NULL}, + + /* memory controller */ + {cgroup_convert_memory_max_limit_to_max, "memory.limit_in_bytes", + (void *)"9223372036854771712", "memory.max", (void *)"max"}, + {cgroup_convert_memory_high_limit_to_max, "memory.soft_limit_in_bytes", + (void *)"9223372036854771712", "memory.high", (void *)"max"}, }; const int cgroup_v1_to_v2_map_sz = ARRAY_SIZE(cgroup_v1_to_v2_map); @@ -58,5 +64,11 @@ const struct cgroup_abstraction_map cgroup_v2_to_v1_map[] = { {cgroup_convert_passthrough, "cpuset.mems", NULL, "cpuset.mems", NULL}, {cgroup_convert_cpuset_to_exclusive, "cpuset.cpus.partition", NULL, "cpuset.cpu_exclusive", NULL}, + + /* memory controller */ + {cgroup_convert_memory_max_max_to_limit, "memory.max", (void *)"max", + "memory.limit_in_bytes", (void *)"9223372036854771712"}, + {cgroup_convert_memory_high_max_to_limit, "memory.high", (void *)"max", + "memory.soft_limit_in_bytes", (void *)"9223372036854771712"}, }; const int cgroup_v2_to_v1_map_sz = ARRAY_SIZE(cgroup_v2_to_v1_map); diff --git a/src/abstraction-memory.c b/src/abstraction-memory.c new file mode 100644 index 00000000..72dd577a --- /dev/null +++ b/src/abstraction-memory.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: LGPL-2.1-only +/** + * Libcgroup abstraction layer for the cpu controller + * + * Copyright (c) 2021-2022 Oracle and/or its affiliates. + * Author: Tom Hromatka + */ + +#include "abstraction-common.h" +#include "abstraction-map.h" + +#include +#include + +#include +#include +#include +#include +#include + +#define LL_MAX 8192 + +static const char * const V2_MAX = "max"; +static const char * const V1_MAX = "9223372036854771712"; + +static int read_setting(const char * const cgrp_name, const char * const controller_name, + const char * const setting_name, char ** const value) +{ + char tmp_line[LL_MAX]; + void *handle; + int ret; + + //fprintf(stderr, "%s:%d setting = %s\n", __func__, __LINE__, setting_name); + ret = cgroup_read_value_begin(controller_name, cgrp_name, setting_name, &handle, + tmp_line, LL_MAX); + //fprintf(stderr, "%s:%d, ret = %d\n", __func__, __LINE__, ret); + if (ret == ECGEOF) + goto read_end; + else if (ret != 0) + goto end; + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + + *value = strdup(tmp_line); + if ((*value) == NULL) + ret = ECGOTHER; + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + +read_end: + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + cgroup_read_value_end(&handle); + if (ret == ECGEOF) + ret = 0; +end: + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + return ret; +} + +static int convert_limit_to_max(struct cgroup_controller * const dst_cgc, + const char * const in_setting, const char * const in_value, + const char * const out_setting, void *in_dflt, void *out_dflt) +{ + char max_line[LL_MAX] = {0}; + char *limit = NULL; + int ret; + + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + if (strlen(in_value) == 0) { + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + /* There's no value to convert. Populate the setting */ + ret = cgroup_add_value_string(dst_cgc, out_setting, NULL); + if (ret) + goto out; + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + } else { + ret = read_setting(dst_cgc->cgroup->name, "memory", in_setting, &limit); + if (ret) + goto out; + + //fprintf(stderr, "in dflt = %s\n", (char *)in_dflt); + //fprintf(stderr, "limit = %s\n", limit); + if (strcmp(limit, in_dflt) == 0) + snprintf(max_line, LL_MAX, "%s", V2_MAX); + else + snprintf(max_line, LL_MAX, "%s", limit); + + ret = cgroup_add_value_string(dst_cgc, out_setting, max_line); + if (ret) + goto out; + } + +out: + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + if (limit) + free(limit); + + return ret; +} +int cgroup_convert_memory_max_limit_to_max(struct cgroup_controller * const dst_cgc, + const char * const in_value, const char * const out_setting, + void *in_dflt, void *out_dflt) +{ + return convert_limit_to_max(dst_cgc, "memory.limit_in_bytes", in_value, out_setting, + in_dflt, out_dflt); +} + +int cgroup_convert_memory_high_limit_to_max(struct cgroup_controller * const dst_cgc, + const char * const in_value, const char * const out_setting, + void *in_dflt, void *out_dflt) +{ + return convert_limit_to_max(dst_cgc, "memory.soft_limit_in_bytes", in_value, out_setting, + in_dflt, out_dflt); +} + +static int convert_max_to_limit(struct cgroup_controller * const dst_cgc, + const char * const in_setting, const char * const in_value, + const char * const out_setting, void *in_dflt, void *out_dflt) +{ + char max_line[LL_MAX] = {0}; + char *limit = NULL; + int ret; + + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + if (strlen(in_value) == 0) { + /* There's no value to convert. Populate the setting and return */ + return cgroup_add_value_string(dst_cgc, out_setting, NULL); + } else { + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + ret = read_setting(dst_cgc->cgroup->name, "memory", in_setting, &limit); + if (ret) + goto out; + + //fprintf(stderr, "%s:%d\n", __func__, __LINE__); + //fprintf(stderr, "in dflt = %s\n", (char *)in_dflt); + //fprintf(stderr, "limit = %s\n", limit); + if (strcmp(limit, in_dflt) == 0) + snprintf(max_line, LL_MAX, "%s", V1_MAX); + else + snprintf(max_line, LL_MAX, "%s", limit); + + ret = cgroup_add_value_string(dst_cgc, out_setting, max_line); + if (ret) + goto out; + } + +out: + if (limit) + free(limit); + + return ret; +} + +int cgroup_convert_memory_max_max_to_limit(struct cgroup_controller * const dst_cgc, + const char * const in_value, const char * const out_setting, + void *in_dflt, void *out_dflt) +{ + return convert_max_to_limit(dst_cgc, "memory.max", in_value, out_setting, + in_dflt, out_dflt); +} + +int cgroup_convert_memory_high_max_to_limit(struct cgroup_controller * const dst_cgc, + const char * const in_value, const char * const out_setting, + void *in_dflt, void *out_dflt) +{ + return convert_max_to_limit(dst_cgc, "memory.high", in_value, out_setting, + in_dflt, out_dflt); +}