[systemd-devel] [PATCH] core: add startup resource control option

Umut Tezduyar Lindskog umut at tezduyar.com
Wed May 21 05:02:08 PDT 2014


Hi Cho,

Do you have any technical reason why CPU shares are reverted back to
the default value on "StartupFinished" but instead when the unit is in
"activated" state?

Through out the boot, until StartupFinished, a unit might get
activated quite early but still having a higher CPU share. If the
service has some low priority task scheduled to do some non important
jobs, up until StartupFinished, low priority task is getting more CPU.
Thoughts?

Just out of curiosity, how does it work when the service is restarted
before StartupFinished is reached?

On Thu, May 15, 2014 at 5:09 PM, WaLyong Cho <walyong.cho at samsung.com> wrote:
> Similar to CPUShares= and BlockIOWeight= respectively. However only
> assign the specified weight during startup. Each control group
> attribute is re-assigned as weight by CPUShares=weight and
> BlockIOWeight=weight after startup.  If not CPUShares= or
> BlockIOWeight= be specified, then the attribute is re-assigned to each
> default attribute value. (default cpu.shares=1024, blkio.weight=1000)
> If only CPUShares=weight or BlockIOWeight=weight be specified, then
> that implies StartupCPUShares=weight and StartupBlockIOWeight=weight.
> ---
>  man/systemd.resource-control.xml      | 24 ++++++++++
>  src/core/cgroup.c                     | 40 ++++++++++++-----
>  src/core/cgroup.h                     |  8 +++-
>  src/core/dbus-cgroup.c                | 42 ++++++++++++++++++
>  src/core/load-fragment-gperf.gperf.m4 |  2 +
>  src/core/load-fragment.c              | 83 +++++++++++++++++++++++++++++++++++
>  src/core/load-fragment.h              |  2 +
>  src/core/manager.c                    | 16 +++++++
>  src/core/manager.h                    |  3 ++
>  src/core/unit.c                       | 18 ++++++++
>  10 files changed, 226 insertions(+), 12 deletions(-)
>
> diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
> index 80c365b..33d2f2e 100644
> --- a/man/systemd.resource-control.xml
> +++ b/man/systemd.resource-control.xml
> @@ -171,6 +171,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
>        </varlistentry>
>
>        <varlistentry>
> +        <term><varname>StartupCPUShares=<replaceable>weight</replaceable></varname></term>
> +
> +        <listitem>
> +          <para>Similar to <varname>CPUShares=</varname>. However,
> +          only be assigned on startup state. After finishing startup, will be
> +          re-assigned by <varname>CPUShares=</varname>. If
> +          <varname>CPUShares=</varname> is not specified, then it will be
> +          assigned to default(1024).</para>
> +        </listitem>
> +      </varlistentry>
> +
> +      <varlistentry>
>          <term><varname>MemoryAccounting=</varname></term>
>
>          <listitem>
> @@ -241,6 +253,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
>        </varlistentry>
>
>        <varlistentry>
> +        <term><varname>StartupBlockIOWeight=<replaceable>weight</replaceable></varname></term>
> +
> +        <listitem>
> +          <para>Similar to <varname>BlockIOWeight=</varname>. However,
> +          only be assigned on startup state. After finishing startup, will be
> +          re-assigned by <varname>BlockIOWeight=</varname>. If
> +          <varname>BlockIOWeight=</varname> is not specified, then it will be
> +          assigned to default(1000).</para>
> +        </listitem>
> +      </varlistentry>
> +
> +      <varlistentry>
>          <term><varname>BlockIODeviceWeight=<replaceable>device</replaceable> <replaceable>weight</replaceable></varname></term>
>
>          <listitem>
> diff --git a/src/core/cgroup.c b/src/core/cgroup.c
> index 29ab645..80a5575 100644
> --- a/src/core/cgroup.c
> +++ b/src/core/cgroup.c
> @@ -34,8 +34,12 @@ void cgroup_context_init(CGroupContext *c) {
>           * structure is preinitialized to 0 */
>
>          c->cpu_shares = 1024;
> +        c->startup_cpu_shares = 1024;
> +        c->startup_cpu_shares_set = false;

I really think patch can be implemented without startup_cpu_shares_set
and startup_blockio_weight_set. In the end, c->startup_cpu_shares =
1024 and c->cpu_shares = 1024 means that we don't want any special
treatment.

Thanks,
Umut

>          c->memory_limit = (uint64_t) -1;
>          c->blockio_weight = 1000;
> +        c->startup_blockio_weight = 1000;
> +        c->startup_blockio_weight_set = false;
>
>          c->cpu_quota_per_sec_usec = (usec_t) -1;
>          c->cpu_quota_usec = (usec_t) -1;
> @@ -124,20 +128,24 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
>                  "%sBlockIOAccounting=%s\n"
>                  "%sMemoryAccounting=%s\n"
>                  "%sCPUShares=%lu\n"
> +                "%sStartupCPUShares=%lu\n"
>                  "%sCPUQuota=%s\n"
>                  "%sCPUQuotaPerSecSec=%s\n"
>                  "%sCPUQuotaPeriodSec=%s\n"
>                  "%sBlockIOWeight=%lu\n"
> +                "%sStartupBlockIOWeight=%lu\n"
>                  "%sMemoryLimit=%" PRIu64 "\n"
>                  "%sDevicePolicy=%s\n",
>                  prefix, yes_no(c->cpu_accounting),
>                  prefix, yes_no(c->blockio_accounting),
>                  prefix, yes_no(c->memory_accounting),
>                  prefix, c->cpu_shares,
> +                prefix, c->startup_cpu_shares,
>                  prefix, strna(format_timespan(u, sizeof(u), cgroup_context_get_cpu_quota_usec(c), 1)),
>                  prefix, strna(format_timespan(t, sizeof(t), cgroup_context_get_cpu_quota_per_sec_usec(c), 1)),
>                  prefix, strna(format_timespan(s, sizeof(s), c->cpu_quota_period_usec, 1)),
>                  prefix, c->blockio_weight,
> +                prefix, c->startup_blockio_weight,
>                  prefix, c->memory_limit,
>                  prefix, cgroup_device_policy_to_string(c->device_policy));
>
> @@ -306,7 +314,7 @@ fail:
>          return -errno;
>  }
>
> -void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path) {
> +void cgroup_context_apply(Manager *m, CGroupContext *c, CGroupControllerMask mask, const char *path) {
>          bool is_root;
>          int r;
>
> @@ -324,7 +332,9 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
>                  char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1];
>                  usec_t q;
>
> -                sprintf(buf, "%lu\n", c->cpu_shares);
> +                sprintf(buf, "%lu\n", manager_state(m) == MANAGER_STARTING
> +                        ? c->startup_cpu_shares
> +                        : c->cpu_shares);
>                  r = cg_set_attribute("cpu", path, "cpu.shares", buf);
>                  if (r < 0)
>                          log_warning("Failed to set cpu.shares on %s: %s", path, strerror(-r));
> @@ -352,7 +362,9 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
>                  CGroupBlockIODeviceBandwidth *b;
>
>                  if (!is_root) {
> -                        sprintf(buf, "%lu\n", c->blockio_weight);
> +                        sprintf(buf, "%lu\n", manager_state(m) == MANAGER_STARTING
> +                                ? c->startup_blockio_weight
> +                                : c->blockio_weight);
>                          r = cg_set_attribute("blkio", path, "blkio.weight", buf);
>                          if (r < 0)
>                                  log_warning("Failed to set blkio.weight on %s: %s", path, strerror(-r));
> @@ -462,22 +474,30 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
>          }
>  }
>
> -CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
> +CGroupControllerMask cgroup_context_get_mask(Manager *m, CGroupContext *c) {
>          CGroupControllerMask mask = 0;
>
>          /* Figure out which controllers we need */
>
>          if (c->cpu_accounting ||
> -            c->cpu_shares != 1024 ||
> +            (manager_state(m) == MANAGER_STARTING ? c->startup_cpu_shares : c->cpu_shares) != 1024 ||
> +            (manager_state(m) != MANAGER_STARTING && c->startup_cpu_shares_set && c->startup_cpu_shares != c->cpu_shares) ||
>              c->cpu_quota_usec != (usec_t) -1 ||
> -            c->cpu_quota_per_sec_usec != (usec_t) -1)
> +            c->cpu_quota_per_sec_usec != (usec_t) -1) {
>                  mask |= CGROUP_CPUACCT | CGROUP_CPU;
> +                if (manager_state(m) != MANAGER_STARTING)
> +                        c->startup_cpu_shares_set = false;
> +        }
>
>          if (c->blockio_accounting ||
> -            c->blockio_weight != 1000 ||
> +            (manager_state(m) == MANAGER_STARTING ? c->startup_blockio_weight : c->blockio_weight) != 1000 ||
> +            (manager_state(m) != MANAGER_STARTING && c->startup_blockio_weight_set && c->startup_blockio_weight != c->blockio_weight) ||
>              c->blockio_device_weights ||
> -            c->blockio_device_bandwidths)
> +            c->blockio_device_bandwidths) {
>                  mask |= CGROUP_BLKIO;
> +                if (manager_state(m) != MANAGER_STARTING)
> +                        c->startup_blockio_weight_set = false;
> +        }
>
>          if (c->memory_accounting ||
>              c->memory_limit != (uint64_t) -1)
> @@ -496,7 +516,7 @@ CGroupControllerMask unit_get_cgroup_mask(Unit *u) {
>          if (!c)
>                  return 0;
>
> -        return cgroup_context_get_mask(c);
> +        return cgroup_context_get_mask(u->manager, c);
>  }
>
>  CGroupControllerMask unit_get_members_mask(Unit *u) {
> @@ -700,7 +720,7 @@ static int unit_realize_cgroup_now(Unit *u) {
>                  return r;
>
>          /* Finally, apply the necessary attributes. */
> -        cgroup_context_apply(unit_get_cgroup_context(u), mask, u->cgroup_path);
> +        cgroup_context_apply(u->manager, unit_get_cgroup_context(u), mask, u->cgroup_path);
>
>          return 0;
>  }
> diff --git a/src/core/cgroup.h b/src/core/cgroup.h
> index 2b19add..64d3ac6 100644
> --- a/src/core/cgroup.h
> +++ b/src/core/cgroup.h
> @@ -71,11 +71,15 @@ struct CGroupContext {
>          bool memory_accounting;
>
>          unsigned long cpu_shares;
> +        unsigned long startup_cpu_shares;
> +        bool startup_cpu_shares_set:1;
>          usec_t cpu_quota_per_sec_usec;
>          usec_t cpu_quota_usec;
>          usec_t cpu_quota_period_usec;
>
>          unsigned long blockio_weight;
> +        unsigned long startup_blockio_weight;
> +        bool startup_blockio_weight_set:1;
>          LIST_HEAD(CGroupBlockIODeviceWeight, blockio_device_weights);
>          LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths);
>
> @@ -92,9 +96,9 @@ struct CGroupContext {
>  void cgroup_context_init(CGroupContext *c);
>  void cgroup_context_done(CGroupContext *c);
>  void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
> -void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path);
> +void cgroup_context_apply(Manager *m, CGroupContext *c, CGroupControllerMask mask, const char *path);
>
> -CGroupControllerMask cgroup_context_get_mask(CGroupContext *c);
> +CGroupControllerMask cgroup_context_get_mask(Manager *m, CGroupContext *c);
>
>  void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a);
>  void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w);
> diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
> index e9bdabf..a7c8ca6 100644
> --- a/src/core/dbus-cgroup.c
> +++ b/src/core/dbus-cgroup.c
> @@ -173,11 +173,13 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
>          SD_BUS_VTABLE_START(0),
>          SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
>          SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0),
> +        SD_BUS_PROPERTY("StartupCPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, startup_cpu_shares), 0),
>          SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", property_get_cpu_quota_per_sec_usec, 0, 0),
>          SD_BUS_PROPERTY("CPUQuotaUSec", "t", property_get_cpu_quota_usec, 0, 0),
>          SD_BUS_PROPERTY("CPUQuotaPeriodUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_period_usec), 0),
>          SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
>          SD_BUS_PROPERTY("BlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, blockio_weight), 0),
> +        SD_BUS_PROPERTY("StartupBlockIOWeight", "t", bus_property_get_ulong, offsetof(CGroupContext, startup_blockio_weight), 0),
>          SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
>          SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
>          SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
> @@ -238,6 +240,26 @@ int bus_cgroup_set_property(
>
>                  return 1;
>
> +        } else if (streq(name, "StartupCPUShares")) {
> +                uint64_t u64;
> +                unsigned long ul;
> +
> +                r = sd_bus_message_read(message, "t", &u64);
> +                if (r < 0)
> +                        return r;
> +
> +                ul = (unsigned long) u64;
> +                if (ul <= 0 || (uint64_t) ul != u64)
> +                        return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
> +
> +                if (mode != UNIT_CHECK) {
> +                        c->startup_cpu_shares = ul;
> +                        c->startup_cpu_shares_set = true;
> +                        unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul);
> +                }
> +
> +                return 1;
> +
>          } else if (streq(name, "CPUQuotaPerSecUSec")) {
>                  uint64_t u64;
>
> @@ -330,6 +352,26 @@ int bus_cgroup_set_property(
>
>                  return 1;
>
> +        } else if (streq(name, "StartupBlockIOWeight")) {
> +                uint64_t u64;
> +                unsigned long ul;
> +
> +                r = sd_bus_message_read(message, "t", &u64);
> +                if (r < 0)
> +                        return r;
> +
> +                ul = (unsigned long) u64;
> +                if (ul < 10 || ul > 1000)
> +                        return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
> +
> +                if (mode != UNIT_CHECK) {
> +                        c->startup_blockio_weight = ul;
> +                        c->startup_blockio_weight_set = true;
> +                        unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul);
> +                }
> +
> +                return 1;
> +
>          } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
>                  const char *path;
>                  bool read = true;
> diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
> index 21bccbb..91061df 100644
> --- a/src/core/load-fragment-gperf.gperf.m4
> +++ b/src/core/load-fragment-gperf.gperf.m4
> @@ -106,6 +106,7 @@ m4_define(`CGROUP_CONTEXT_CONFIG_ITEMS',
>  `$1.Slice,                       config_parse_unit_slice,            0,                             0
>  $1.CPUAccounting,                config_parse_bool,                  0,                             offsetof($1, cgroup_context.cpu_accounting)
>  $1.CPUShares,                    config_parse_cpu_shares,            0,                             offsetof($1, cgroup_context)
> +$1.StartupCPUShares,             config_parse_startup_cpu_shares,    0,                             offsetof($1, cgroup_context)
>  $1.CPUQuota,                     config_parse_cpu_quota,             0,                             offsetof($1, cgroup_context)
>  $1.CPUQuotaPeriodSec,            config_parse_sec,                   0,                             offsetof($1, cgroup_context.cpu_quota_period_usec)
>  $1.MemoryAccounting,             config_parse_bool,                  0,                             offsetof($1, cgroup_context.memory_accounting)
> @@ -114,6 +115,7 @@ $1.DeviceAllow,                  config_parse_device_allow,          0,
>  $1.DevicePolicy,                 config_parse_device_policy,         0,                             offsetof($1, cgroup_context.device_policy)
>  $1.BlockIOAccounting,            config_parse_bool,                  0,                             offsetof($1, cgroup_context.blockio_accounting)
>  $1.BlockIOWeight,                config_parse_blockio_weight,        0,                             offsetof($1, cgroup_context)
> +$1.StartupBlockIOWeight,         config_parse_startup_blockio_weight, 0,                            offsetof($1, cgroup_context)
>  $1.BlockIODeviceWeight,          config_parse_blockio_device_weight, 0,                             offsetof($1, cgroup_context)
>  $1.BlockIOReadBandwidth,         config_parse_blockio_bandwidth,     0,                             offsetof($1, cgroup_context)
>  $1.BlockIOWriteBandwidth,        config_parse_blockio_bandwidth,     0,                             offsetof($1, cgroup_context)'
> diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
> index 14c194b..9605d8d 100644
> --- a/src/core/load-fragment.c
> +++ b/src/core/load-fragment.c
> @@ -2451,6 +2451,47 @@ int config_parse_cpu_shares(
>          }
>
>          c->cpu_shares = lu;
> +        if (!c->startup_cpu_shares_set)
> +                c->startup_cpu_shares = lu;
> +
> +        return 0;
> +}
> +
> +int config_parse_startup_cpu_shares(
> +                const char *unit,
> +                const char *filename,
> +                unsigned line,
> +                const char *section,
> +                unsigned section_line,
> +                const char *lvalue,
> +                int ltype,
> +                const char *rvalue,
> +                void *data,
> +                void *userdata) {
> +
> +        CGroupContext *c = data;
> +        unsigned long lu;
> +        int r;
> +
> +        assert(filename);
> +        assert(lvalue);
> +        assert(rvalue);
> +
> +        if (isempty(rvalue)) {
> +                c->startup_cpu_shares = 1024;
> +                return 0;
> +        }
> +
> +        r = safe_atolu(rvalue, &lu);
> +        if (r < 0 || lu <= 0) {
> +                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
> +                           "Startup CPU shares '%s' invalid. Ignoring.", rvalue);
> +                return 0;
> +        }
> +
> +        c->startup_cpu_shares = lu;
> +        c->startup_cpu_shares_set = true;
> +
>          return 0;
>  }
>
> @@ -2628,6 +2669,46 @@ int config_parse_blockio_weight(
>          }
>
>          c->blockio_weight = lu;
> +        if (!c->startup_blockio_weight_set)
> +                c->startup_blockio_weight = lu;
> +
> +        return 0;
> +}
> +
> +int config_parse_startup_blockio_weight(
> +                const char *unit,
> +                const char *filename,
> +                unsigned line,
> +                const char *section,
> +                unsigned section_line,
> +                const char *lvalue,
> +                int ltype,
> +                const char *rvalue,
> +                void *data,
> +                void *userdata) {
> +
> +        CGroupContext *c = data;
> +        unsigned long lu;
> +        int r;
> +
> +        assert(filename);
> +        assert(lvalue);
> +        assert(rvalue);
> +
> +        if (isempty(rvalue)) {
> +                c->startup_blockio_weight = 1000;
> +                return 0;
> +        }
> +
> +        r = safe_atolu(rvalue, &lu);
> +        if (r < 0 || lu < 10 || lu > 1000) {
> +                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
> +                           "Startup Block IO weight '%s' invalid. Ignoring.", rvalue);
> +                return 0;
> +        }
> +
> +        c->startup_blockio_weight = lu;
> +        c->startup_blockio_weight_set = true;
>
>          return 0;
>  }
> @@ -3445,11 +3526,13 @@ void unit_dump_config_items(FILE *f) {
>                  { config_parse_address_families,      "FAMILIES" },
>  #endif
>                  { config_parse_cpu_shares,            "SHARES" },
> +                { config_parse_startup_cpu_shares,    "STARTUPSHARES" },
>                  { config_parse_memory_limit,          "LIMIT" },
>                  { config_parse_device_allow,          "DEVICE" },
>                  { config_parse_device_policy,         "POLICY" },
>                  { config_parse_blockio_bandwidth,     "BANDWIDTH" },
>                  { config_parse_blockio_weight,        "WEIGHT" },
> +                { config_parse_startup_blockio_weight, "STARTUPWEIGHT" },
>                  { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
>                  { config_parse_long,                  "LONG" },
>                  { config_parse_socket_service,        "SERVICE" },
> diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
> index 242fd27..5b1bcf9 100644
> --- a/src/core/load-fragment.h
> +++ b/src/core/load-fragment.h
> @@ -80,10 +80,12 @@ int config_parse_syscall_errno(const char *unit, const char *filename, unsigned
>  int config_parse_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
> +int config_parse_startup_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_device_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_device_allow(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_blockio_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
> +int config_parse_startup_blockio_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_blockio_device_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_blockio_bandwidth(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
>  int config_parse_job_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
> diff --git a/src/core/manager.c b/src/core/manager.c
> index 5772f40..809d995 100644
> --- a/src/core/manager.c
> +++ b/src/core/manager.c
> @@ -456,6 +456,10 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
>          if (r < 0)
>                  goto fail;
>
> +        r = set_ensure_allocated(&m->startup_units, trivial_hash_func, trivial_compare_func);
> +        if (r < 0)
> +                goto fail;
> +
>          r = set_ensure_allocated(&m->failed_units, trivial_hash_func, trivial_compare_func);
>          if (r < 0)
>                  goto fail;
> @@ -794,6 +798,7 @@ void manager_free(Manager *m) {
>          hashmap_free(m->watch_pids2);
>          hashmap_free(m->watch_bus);
>
> +        set_free(m->startup_units);
>          set_free(m->failed_units);
>
>          sd_event_source_unref(m->signal_event_source);
> @@ -2446,6 +2451,9 @@ bool manager_unit_inactive_or_pending(Manager *m, const char *name) {
>  void manager_check_finished(Manager *m) {
>          char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
>          usec_t firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec;
> +        Unit *u = NULL;
> +        Iterator i;
> +        UnitActiveState state;
>
>          assert(m);
>
> @@ -2533,6 +2541,14 @@ void manager_check_finished(Manager *m) {
>                                     NULL);
>          }
>
> +        SET_FOREACH(u, m->startup_units, i) {
> +                u = set_steal_first(m->startup_units);
> +                state = unit_active_state(u);
> +                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(state))
> +                        continue;
> +                cgroup_context_apply(m, unit_get_cgroup_context(u), unit_get_cgroup_mask(u), u->cgroup_path);
> +        }
> +
>          bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
>
>          sd_notifyf(false,
> diff --git a/src/core/manager.h b/src/core/manager.h
> index a3de351..ab4cafc 100644
> --- a/src/core/manager.h
> +++ b/src/core/manager.h
> @@ -116,6 +116,9 @@ struct Manager {
>          Hashmap *watch_pids1;  /* pid => Unit object n:1 */
>          Hashmap *watch_pids2;  /* pid => Unit object n:1 */
>
> +        /* A set contains all units which cgroup should be refreshed after startup */
> +        Set *startup_units;
> +
>          /* A set which contains all currently failed units */
>          Set *failed_units;
>
> diff --git a/src/core/unit.c b/src/core/unit.c
> index 6ac359e..cb50bcc 100644
> --- a/src/core/unit.c
> +++ b/src/core/unit.c
> @@ -1071,6 +1071,20 @@ static int unit_add_mount_dependencies(Unit *u) {
>          return 0;
>  }
>
> +static int unit_add_startup_units(Unit *u) {
> +        CGroupContext *c;
> +        int r = 0;
> +
> +        c = unit_get_cgroup_context(u);
> +        if (c != NULL && manager_state(u->manager) == MANAGER_STARTING &&
> +            (c->startup_cpu_shares_set || c->startup_blockio_weight_set)) {
> +                r = set_put(u->manager->startup_units, u);
> +                if (r == -EEXIST)
> +                        r = 0;
> +        }
> +        return r;
> +}
> +
>  int unit_load(Unit *u) {
>          int r;
>
> @@ -1112,6 +1126,10 @@ int unit_load(Unit *u) {
>                  if (r < 0)
>                          goto fail;
>
> +                r = unit_add_startup_units(u);
> +                if (r < 0)
> +                        goto fail;
> +
>                  if (u->on_failure_job_mode == JOB_ISOLATE && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
>                          log_error_unit(u->id, "More than one OnFailure= dependencies specified for %s but OnFailureJobMode=isolate set. Refusing.", u->id);
>                          r = -EINVAL;
> --
> 1.9.0
>
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel


More information about the systemd-devel mailing list