I've changed the options, it was indeed confusing, sorry for that. Very good observation, Thank you!
________________________________________ From: Kok, Auke-jan H [[email protected]] Sent: Thursday, July 14, 2011 12:41 AM To: Patrascu, Cristian Cc: [email protected]; Zaharia, Adrian; [email protected] Subject: Re: [systemd-devel] [PATCH] systemd-cgroup-limits.patch On Wed, Jul 13, 2011 at 12:35 AM, Patrascu, Cristian <[email protected]> wrote: > Patch adds functionality to apply certain cgroups limits, such as shares of > cpu, memory limit and blkio. > Unit files of type Service, Mount, Swap and Socket have new options (under > corresponding [Service], [Mount], [Swap], [Socket] option group ): > - "MemoryHardLimit" accepts int64 value (considered bytes), puts the value in > "memory" cgroup (if defined) in file "memory.limit_in_bytes" ; > - "MemoryLimit" accepts int64 value (considered bytes), puts the value in > "memory" cgroup (if defined) in file "memory.soft_limit_in_bytes" ; nitpick, but still you define MemoryHardLimit to set limit_in_bytes you define MemoryLimit to set soft_limit_in_bytes that's confusing, since "MemoryLimit" does not set "limit_in_bytes". Why not just 1:1 map this to cgroup naming instead: MemoryLimit -> limit_in_bytes MemorySoftLimit -> soft_limit_in_bytes seems so trivial to do that instead... Auke
From 8d47086086689645e0a02ca19dfcc56dc5f6c2e3 Mon Sep 17 00:00:00 2001 From: Cristian Patrascu <[email protected]> Date: Wed, 6 Jul 2011 12:30:15 +0300 Subject: [PATCH] systemd cgroup limits --- src/cgroup-util.c | 19 ++++++ src/cgroup-util.h | 2 + src/cgroup.c | 112 ++++++++++++++++++++++++++++++++++++ src/cgroup.h | 6 ++ src/dbus-common.c | 13 ++++ src/dbus-common.h | 1 + src/dbus-execute.c | 24 ++++++++ src/dbus-execute.h | 15 ++++- src/execute.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/execute.h | 44 ++++++++++++++ src/load-fragment.c | 56 ++++++++++++++++++- src/service.c | 34 +++++++++++ src/systemctl.c | 8 +++ 13 files changed, 487 insertions(+), 5 deletions(-) diff --git a/src/cgroup-util.c b/src/cgroup-util.c index 090573b..39acaf6 100644 --- a/src/cgroup-util.c +++ b/src/cgroup-util.c @@ -1001,3 +1001,22 @@ int cg_get_user_path(char **path) { *path = p; return 0; } + +/* Set a value in a cgroup controller file */ +int cg_set_value(const char * controller, const char * cg_path, const char * file, char * value) { + int r; + char * file_path; + + if (cg_path == NULL || controller == NULL || file == NULL || value == NULL) { + r = -ENXIO; + return r; + } + + r = cg_get_path(controller, cg_path, file, &file_path); + if (r < 0) return r; + + r = write_one_line_file(file_path, value); + if (r < 0) return r; + + return 0; +} diff --git a/src/cgroup-util.h b/src/cgroup-util.h index d142af3..289e4da 100644 --- a/src/cgroup-util.h +++ b/src/cgroup-util.h @@ -69,4 +69,6 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_ int cg_get_user_path(char **path); +int cg_set_value(const char * controller, const char * cg_path, const char * file, char * value); + #endif diff --git a/src/cgroup.c b/src/cgroup.c index 0c6f20d..749641a 100644 --- a/src/cgroup.c +++ b/src/cgroup.c @@ -469,3 +469,115 @@ pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) { return 0; } + +/* Sets memory.limit_in_bytes in memory controller of cgroup */ +int cgroup_bonding_set_memory_limit_hard(CGroupBonding *first, const long long in_mem_limit_bytes) { + CGroupBonding *b = NULL; + int r; + const char * mem_ctl = "memory"; + const char * mem_limit_file_name = "memory.limit_in_bytes"; + char mem_limit_val[64]; + + b = cgroup_bonding_find_list(first, mem_ctl); + if (NULL == b) { + r = -ENXIO; + return r; + } + + snprintf(mem_limit_val, sizeof(mem_limit_val),"%lld\n", in_mem_limit_bytes); + + r = cg_set_value(mem_ctl, b->path, mem_limit_file_name, mem_limit_val); + if (r < 0) return r; + + return 0; +} + +/* Sets memory.soft_limit_in_bytes in memory controller of cgroup */ +int cgroup_bonding_set_memory_limit_soft(CGroupBonding *first, const long long in_mem_limit_bytes) { + CGroupBonding *b = NULL; + int r; + const char * mem_ctl = "memory"; + const char * mem_soft_limit_file_name = "memory.soft_limit_in_bytes"; + char mem_soft_limit_val[64]; + + b = cgroup_bonding_find_list(first, mem_ctl); + if (NULL == b) { + r = -ENXIO; + return r; + } + + snprintf(mem_soft_limit_val, sizeof(mem_soft_limit_val),"%lld\n", in_mem_limit_bytes); + + r = cg_set_value(mem_ctl, b->path, mem_soft_limit_file_name, mem_soft_limit_val); + if (r < 0) return r; + + return 0; +} + +/* Sets blkio.throttle.read_bps_device in blkio controller of cgroup + limits a disk read bandwidth (bytes per second) */ +int cgroup_bonding_set_blkio_read_limit(CGroupBonding *first, const char * in_disk, const long long in_limit) { + CGroupBonding *b = NULL; + int r; + const char * ctl = "blkio"; + const char * limit_file_name = "blkio.throttle.read_bps_device"; + char limit_val[64]; + + b = cgroup_bonding_find_list(first, ctl); + if (NULL == b) { + r = -ENXIO; + return r; + } + + snprintf(limit_val, sizeof(limit_val),"%s %lld\n", in_disk, in_limit); + + r = cg_set_value(ctl, b->path, limit_file_name, limit_val); + if (r < 0) return r; + + return 0; +} + +/* Sets blkio.throttle.write_bps_device in blkio controller of cgroup + limits a disk write bandwidth (bytes per second) */ +int cgroup_bonding_set_blkio_write_limit(CGroupBonding *first, const char * in_disk, const long long in_limit) { + CGroupBonding *b = NULL; + int r; + const char * ctl = "blkio"; + const char * limit_file_name = "blkio.throttle.write_bps_device"; + char limit_val[64]; + + b = cgroup_bonding_find_list(first, ctl); + if (NULL == b) { + r = -ENXIO; + return r; + } + + snprintf(limit_val, sizeof(limit_val),"%s %lld\n", in_disk, in_limit); + + r = cg_set_value(ctl, b->path, limit_file_name, limit_val); + if (r < 0) return r; + + return 0; +} + +/* Sets cpu.shares in cpu controller of cgroup */ +int cgroup_bonding_set_cpu_shares(CGroupBonding *first, const int in_cpu_shares) { + CGroupBonding *b = NULL; + int r; + const char * cpu_ctl = "cpu"; + const char * cpu_shares_file_name = "cpu.shares"; + char cpu_shares_val[32]; + + b = cgroup_bonding_find_list(first, cpu_ctl); + if (NULL == b) { + r = -ENXIO; + return r; + } + + snprintf(cpu_shares_val, sizeof(cpu_shares_val),"%d\n", in_cpu_shares); + + r = cg_set_value(cpu_ctl, b->path, cpu_shares_file_name, cpu_shares_val); + if (r < 0) return r; + + return 0; +} diff --git a/src/cgroup.h b/src/cgroup.h index c6dff43..5ac7d8f 100644 --- a/src/cgroup.h +++ b/src/cgroup.h @@ -75,6 +75,12 @@ char *cgroup_bonding_to_string(CGroupBonding *b); pid_t cgroup_bonding_search_main_pid(CGroupBonding *b); pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *b); +int cgroup_bonding_set_memory_limit_hard(CGroupBonding *first, const long long in_mem_limit_bytes); +int cgroup_bonding_set_memory_limit_soft(CGroupBonding *first, const long long in_mem_limit_bytes); +int cgroup_bonding_set_cpu_shares(CGroupBonding *first, const int in_cpu_shares); +int cgroup_bonding_set_blkio_read_limit(CGroupBonding *first, const char * in_disk, const long long in_limit); +int cgroup_bonding_set_blkio_write_limit(CGroupBonding *first, const char * in_disk, const long long in_limit); + #include "manager.h" int manager_setup_cgroup(Manager *m); diff --git a/src/dbus-common.c b/src/dbus-common.c index 5db077b..b4aebfe 100644 --- a/src/dbus-common.c +++ b/src/dbus-common.c @@ -542,6 +542,19 @@ int bus_property_append_int32(DBusMessageIter *i, const char *property, void *da return 0; } +int bus_property_append_int64(DBusMessageIter *i, const char *property, void *data) { + assert(i); + assert(property); + assert(data); + + assert_cc(sizeof(int64_t) == sizeof(long long)); + + if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, data)) + return -ENOMEM; + + return 0; +} + int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) { uint64_t u; diff --git a/src/dbus-common.h b/src/dbus-common.h index a88cb13..7dc1f17 100644 --- a/src/dbus-common.h +++ b/src/dbus-common.h @@ -121,6 +121,7 @@ int bus_property_append_string(DBusMessageIter *i, const char *property, void *d int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data); int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data); int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data); +int bus_property_append_int64(DBusMessageIter *i, const char *property, void *data); int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data); int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data); int bus_property_append_size(DBusMessageIter *i, const char *property, void *data); diff --git a/src/dbus-execute.c b/src/dbus-execute.c index 6ceffc5..09b37a3 100644 --- a/src/dbus-execute.c +++ b/src/dbus-execute.c @@ -352,3 +352,27 @@ int bus_execute_append_command(DBusMessageIter *i, const char *property, void *d return 0; } + +int bus_execute_append_hdd_limit(DBusMessageIter *it, const char *property, const struct hdd_cgroup_limit *hdd_cg_limit) { + char ** str_list = NULL; + int i; + + assert(hdd_cg_limit); + assert(it); + assert(property); + + for (i=0; i<MAX_HDD_LIMIT_DISKS; i++) { + char tmp[25]; + + if (streq(hdd_cg_limit[i].disk, "")) + break; + + sprintf(tmp, "%s %lld", hdd_cg_limit[i].disk, hdd_cg_limit[i].limit_bps); + str_list = strv_append(str_list, tmp); + } + + if (str_list == NULL) + str_list = strv_append(str_list, ""); + + return bus_property_append_strv(it, property, str_list); +} diff --git a/src/dbus-execute.h b/src/dbus-execute.h index 56c5bcd..3a8d112 100644 --- a/src/dbus-execute.h +++ b/src/dbus-execute.h @@ -91,7 +91,12 @@ " <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \ " <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n" \ " <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \ - " <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n" + " <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n" \ + " <property name=\"MemoryLimit\" type=\"x\" access=\"readwrite\"/>\n" \ + " <property name=\"MemorySoftLimit\" type=\"x\" access=\"readwrite\"/>\n" \ + " <property name=\"CPUShares\" type=\"i\" access=\"readwrite\"/>\n" \ + " <property name=\"HddReadLimit\" type=\"as\" access=\"readwrite\"/>\n" \ + " <property name=\"HddWriteLimit\" type=\"as\" access=\"readwrite\"/>\n" #define BUS_EXEC_COMMAND_INTERFACE(name) \ " <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n" @@ -153,7 +158,12 @@ { interface, "SameProcessGroup", bus_property_append_bool, "b", &(context).same_pgrp }, \ { interface, "KillMode", bus_execute_append_kill_mode, "s", &(context).kill_mode }, \ { interface, "KillSignal", bus_property_append_int, "i", &(context).kill_signal }, \ - { interface, "UtmpIdentifier", bus_property_append_string, "s", (context).utmp_id } + { interface, "UtmpIdentifier", bus_property_append_string, "s", (context).utmp_id }, \ + { interface, "MemoryLimit", bus_property_append_int64, "x", &(context).cgroup_limits.memory_limit_in_bytes }, \ + { interface, "MemorySoftLimit", bus_property_append_int64, "x", &(context).cgroup_limits.memory_soft_limit_in_bytes }, \ + { interface, "CPUShares", bus_property_append_int32, "i", &(context).cgroup_limits.cpu_shares }, \ + { interface, "HddReadLimit", bus_execute_append_hdd_limit, "as", (context).cgroup_limits.hdd_read_limit }, \ + { interface, "HddWriteLimit", bus_execute_append_hdd_limit, "as", (context).cgroup_limits.hdd_write_limit } #define BUS_EXEC_STATUS_PROPERTIES(interface, estatus, prefix) \ { interface, prefix "StartTimestamp", bus_property_append_usec, "t", &(estatus).start_timestamp.realtime }, \ @@ -182,5 +192,6 @@ int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *d int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data); int bus_execute_append_kill_mode(DBusMessageIter *i, const char *property, void *data); int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data); +int bus_execute_append_hdd_limit(DBusMessageIter *it, const char *property, const struct hdd_cgroup_limit *hdd_cg_limit); #endif diff --git a/src/execute.c b/src/execute.c index a62f9db..4be271d 100644 --- a/src/execute.c +++ b/src/execute.c @@ -979,6 +979,156 @@ finish: return r; } +/* Applies cgroup limits */ +static void exec_apply_cg_limits(const CGroupLimits *cgroup_limits, struct CGroupBonding * cgroup_bondings) { + int i; + + assert(cgroup_limits); + assert(cgroup_bondings); + + if (cgroup_limits->cpu_shares > 0) + cgroup_bonding_set_cpu_shares(cgroup_bondings, cgroup_limits->cpu_shares); + if (cgroup_limits->memory_limit_in_bytes > 0LL) + cgroup_bonding_set_memory_limit_hard(cgroup_bondings, cgroup_limits->memory_limit_in_bytes); + if (cgroup_limits->memory_soft_limit_in_bytes > 0LL) + cgroup_bonding_set_memory_limit_soft(cgroup_bondings, cgroup_limits->memory_soft_limit_in_bytes); + + for (i = 0; i<MAX_HDD_LIMIT_DISKS; i++) { + if (streq(cgroup_limits->hdd_read_limit[i].disk,"")) + break; + + if (cgroup_limits->hdd_read_limit[i].limit_bps > 0LL) + cgroup_bonding_set_blkio_read_limit(cgroup_bondings, cgroup_limits->hdd_read_limit[i].disk, cgroup_limits->hdd_read_limit[i].limit_bps); + } + + for (i = 0; i<MAX_HDD_LIMIT_DISKS; i++) { + if (streq(cgroup_limits->hdd_write_limit[i].disk,"")) + break; + + if (cgroup_limits->hdd_write_limit[i].limit_bps > 0LL) + cgroup_bonding_set_blkio_write_limit(cgroup_bondings, cgroup_limits->hdd_write_limit[i].disk, cgroup_limits->hdd_write_limit[i].limit_bps); + } +} + +/* Serialize hdd cgroup limit to string */ +void exec_hdd_lim_serialize(const struct hdd_cgroup_limit * hdd_lim, char ** out_hdd_lim_ser) { + int i; + + char * out_str = NULL; + + assert(hdd_lim); + + for (i=0; i<MAX_HDD_LIMIT_DISKS; i++) { + char tmp[30]; + + if (streq(hdd_lim[i].disk, "")) + break; + + sprintf(tmp, "%s %lld ; ", hdd_lim[i].disk, hdd_lim[i].limit_bps); + out_str = strappend(out_str, tmp); + } + + *out_hdd_lim_ser = out_str; +} + +/* Sets a hdd limit value coresponding to given disk, + * returns -1 if error, 0 if set (new or different limit), + * 1 if not set (same limit) */ +static int exec_hdd_cgroup_limit_set_internal_value(struct hdd_cgroup_limit * hdd_lim, const char * disk, const long long limit) { + int first_empty = -1; + int i; + + int valid_limit = (limit <= 0 ? 0 : limit); + + for (i=0; i<MAX_HDD_LIMIT_DISKS; i++) { + if (streq(hdd_lim[i].disk, disk)) { + if (hdd_lim[i].limit_bps != valid_limit) { + hdd_lim[i].limit_bps = valid_limit; + return 0; + } + return 1; + } + + if (first_empty == -1 && + streq(hdd_lim[i].disk, "")) { + first_empty = i; + } + } + + if (first_empty > -1) { + strcpy(hdd_lim[first_empty].disk, disk); + hdd_lim[first_empty].limit_bps = valid_limit; + return 0; + } + + return -1; +} + +/* Parse and set hdd read/write limits from string (';' delimits another disk limit) + ex: "8:0 1500000 ; 7:0 2500000" */ +int exec_parse_hdd_cgroup_limit(const char * str_value, struct hdd_cgroup_limit * hdd_cg_limit) { + int r = 0; + char *tmp_str; + char *w; + char *disk; + long long disk_limit; + int k; + int i; + + assert(str_value); + assert(hdd_cg_limit); + + if (streq(str_value,strnull(NULL))) { + for (i=0; i<MAX_HDD_LIMIT_DISKS; i++) { + if (streq(hdd_cg_limit[i].disk, "")) + break; + + strcpy(hdd_cg_limit[i].disk, ""); + hdd_cg_limit[i].limit_bps = 0; + } + return r; + } + + tmp_str = strdup(str_value); + + k = 0; + w = strtok(tmp_str, WHITESPACE); + while (w != NULL) { + /* Delimits another disk limit */ + if (strcmp(w, ";") == 0) { + w = strtok(NULL, WHITESPACE); + continue; + } + + /* Disk specifier (1st word) */ + if (k % 2 == 0) { + disk = w; + } + /* limit value for disk (2nd word) */ + else { + if (safe_atolli(w, &disk_limit) < 0) { + r = -ENOMEM; + goto free_res; + } + + /* set the internal values */ + if ((r = exec_hdd_cgroup_limit_set_internal_value(hdd_cg_limit, disk, disk_limit)) < 0) { + r = -ENOMEM; + goto free_res; + } + } + + k++; + w = strtok(NULL, WHITESPACE); + } + +free_res: + if (tmp_str) + free(tmp_str); + + return r; +} + int exec_spawn(ExecCommand *command, char **argv, const ExecContext *context, @@ -1160,11 +1310,13 @@ int exec_spawn(ExecCommand *command, goto fail_child; } - if (cgroup_bondings) + if (cgroup_bondings) { if (cgroup_bonding_install_list(cgroup_bondings, 0) < 0) { r = EXIT_CGROUP; goto fail_child; } + exec_apply_cg_limits(&context->cgroup_limits, cgroup_bondings); + } if (context->oom_score_adjust_set) { char t[16]; @@ -1436,8 +1588,10 @@ int exec_spawn(ExecCommand *command, * outside of the cgroup) and in the parent (so that we can be * sure that when we kill the cgroup the process will be * killed too). */ - if (cgroup_bondings) + if (cgroup_bondings) { cgroup_bonding_install_list(cgroup_bondings, pid); + exec_apply_cg_limits(&context->cgroup_limits, cgroup_bondings); + } log_debug("Forked %s as %lu", command->path, (unsigned long) pid); diff --git a/src/execute.h b/src/execute.h index 55bae24..dac2f29 100644 --- a/src/execute.h +++ b/src/execute.h @@ -96,6 +96,44 @@ struct ExecCommand { bool ignore; }; +/* 10 physical disks sould be enough + (limit is per whole disk, not per partition!) */ +#define MAX_HDD_LIMIT_DISKS 10 + +struct hdd_cgroup_limit { + /* The disk to be limited (r/w). + It is specified in format "<major>:<minor>" + ex.: "8:0" (6 chars should be enough) */ + char disk[6]; + + /* Limit of disk read/write bytes per second */ + long long limit_bps; +}; + +typedef struct _CGroupLimits { + /* For "MemoryLimit" option - if set, searches + * the cgroup in "memory" controller and sets + * "memory.limit_in_bytes" with specified value. */ + long long memory_limit_in_bytes; + + /* For "MemorySoftLimit" option - if set, searches + * the cgroup in "memory" controller and sets + * "memory.soft_limit_in_bytes" with specified value. */ + long long memory_soft_limit_in_bytes; + + /* For "CPUShares" option - if set, searches + * the cgroup in "cpu" controller and sets + * "cpu.shares" with specified value. */ + int cpu_shares; + + /* hdd read limit (bytes per sec.), for max. 10 disks */ + struct hdd_cgroup_limit hdd_read_limit[MAX_HDD_LIMIT_DISKS]; + + /* hdd write limit (bytes per sec.), for max. 10 disks */ + struct hdd_cgroup_limit hdd_write_limit[MAX_HDD_LIMIT_DISKS]; + +} CGroupLimits; + struct ExecContext { char **environment; char **environment_files; @@ -127,6 +165,9 @@ struct ExecContext { bool tty_vhangup; bool tty_vt_disallocate; + /* Some usefull cgroup limits for controllers: cpu, memory, blkio */ + CGroupLimits cgroup_limits; + /* Since resolving these names might might involve socket * connections and we don't want to deadlock ourselves these * names are resolved on execution only and in the child @@ -222,4 +263,7 @@ KillMode kill_mode_from_string(const char *s); const char *kill_who_to_string(KillWho k); KillWho kill_who_from_string(const char *s); +int exec_parse_hdd_cgroup_limit(const char * str_value, struct hdd_cgroup_limit * hdd_cg_limit); +void exec_hdd_lim_serialize(const struct hdd_cgroup_limit * hdd_lim, char ** out_hdd_lim_ser); + #endif diff --git a/src/load-fragment.c b/src/load-fragment.c index 56eaed9..45b893a 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -60,6 +60,55 @@ static int config_parse_warn_compat( } #endif +static int config_parse_hdd_lim( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + struct hdd_cgroup_limit * hdd_cg_limit = data; + int r = 0; + + assert(rvalue); + assert(hdd_cg_limit); + + r = exec_parse_hdd_cgroup_limit(rvalue, hdd_cg_limit); + + if (r<0) + log_error("[%s:%u] Failed to parse cgroup hdd limit, ignoring: %s. ", filename, line, rvalue); + + return 0; +} + +static int config_parse_int64( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + long long *mem_lim = data; + long long u; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (safe_atoi64(rvalue, &u) < 0) { + log_error("[%s:%u] Failed to parse int64 value, ignoring: %s", filename, line, rvalue); + return 0; + } + + *mem_lim = u; + return 0; +} + static int config_parse_deps( const char *filename, unsigned line, @@ -1908,7 +1957,12 @@ static int load_from_path(Unit *u, const char *path) { { "KillMode", config_parse_kill_mode, 0, &(context).kill_mode, section }, \ { "KillSignal", config_parse_kill_signal, 0, &(context).kill_signal, section }, \ { "SendSIGKILL", config_parse_bool, 0, &(context).send_sigkill, section }, \ - { "UtmpIdentifier", config_parse_string_printf, 0, &(context).utmp_id, section } + { "UtmpIdentifier", config_parse_string_printf, 0, &(context).utmp_id, section }, \ + { "MemoryLimit", config_parse_int64, 0, &(context).cgroup_limits.memory_limit_in_bytes, section }, \ + { "MemorySoftLimit", config_parse_int64, 0, &(context).cgroup_limits.memory_soft_limit_in_bytes, section }, \ + { "CPUShares", config_parse_int, 0, &(context).cgroup_limits.cpu_shares, section }, \ + { "HddReadLimit", config_parse_hdd_lim, 0, (context).cgroup_limits.hdd_read_limit, section }, \ + { "HddWriteLimit", config_parse_hdd_lim, 0, (context).cgroup_limits.hdd_write_limit, section } const ConfigItem items[] = { { "Names", config_parse_names, 0, u, "Unit" }, diff --git a/src/service.c b/src/service.c index d59c4cb..3d83e9e 100644 --- a/src/service.c +++ b/src/service.c @@ -2411,6 +2411,27 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { } } + /* only if service is running, serialize cgroup limits state */ + if (s->state == SERVICE_RUNNING) { + char * hdd_limit_serialized = NULL; + + unit_serialize_item_format( + u, f, "cgroup-limits","%lld %lld %d", + s->exec_context.cgroup_limits.memory_limit_in_bytes , + s->exec_context.cgroup_limits.memory_soft_limit_in_bytes , + s->exec_context.cgroup_limits.cpu_shares); + + exec_hdd_lim_serialize(s->exec_context.cgroup_limits.hdd_read_limit, &hdd_limit_serialized); + unit_serialize_item_format(u, f, "hdd_read_limit", "%s", hdd_limit_serialized); + if (hdd_limit_serialized) + free(hdd_limit_serialized); + + exec_hdd_lim_serialize(s->exec_context.cgroup_limits.hdd_write_limit, &hdd_limit_serialized); + unit_serialize_item_format(u, f, "hdd_write_limit", "%s", hdd_limit_serialized); + if (hdd_limit_serialized) + free(hdd_limit_serialized); + } + return 0; } @@ -2510,6 +2531,19 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, dual_timestamp_deserialize(value, &s->main_exec_status.start_timestamp); else if (streq(key, "main-exec-status-exit")) dual_timestamp_deserialize(value, &s->main_exec_status.exit_timestamp); + else if ( + s->deserialized_state == SERVICE_RUNNING && + streq(key, "cgroup-limits") && + sscanf( + value, "%lld %lld %d", + &s->exec_context.cgroup_limits.memory_limit_in_bytes , + &s->exec_context.cgroup_limits.memory_soft_limit_in_bytes , + &s->exec_context.cgroup_limits.cpu_shares) != 3) + log_error("Failed to parse cgroup limit '%s' for deserializing", value); + else if (s->deserialized_state == SERVICE_RUNNING && streq(key, "hdd_read_limit")) + exec_parse_hdd_cgroup_limit(value, s->exec_context.cgroup_limits.hdd_read_limit); + else if (s->deserialized_state == SERVICE_RUNNING && streq(key, "hdd_write_limit")) + exec_parse_hdd_cgroup_limit(value, s->exec_context.cgroup_limits.hdd_write_limit); else log_debug("Unknown serialization key '%s'", key); diff --git a/src/systemctl.c b/src/systemctl.c index 08c7fab..11792cb 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -2316,6 +2316,14 @@ static int print_property(const char *name, DBusMessageIter *iter) { return 0; } + case DBUS_TYPE_INT64: { + int64_t i; + dbus_message_iter_get_basic(iter, &i); + + printf("%s=%lld\n", name, (long long) i); + return 0; + } + case DBUS_TYPE_DOUBLE: { double d; dbus_message_iter_get_basic(iter, &d); -- 1.7.0.4
_______________________________________________ systemd-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/systemd-devel
