diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/cgroup.c | 69 | ||||
-rw-r--r-- | src/core/cgroup.h | 1 | ||||
-rw-r--r-- | src/core/dbus-cgroup.c | 5 | ||||
-rw-r--r-- | src/core/dbus-manager.c | 57 | ||||
-rw-r--r-- | src/core/dbus-mount.c | 2 | ||||
-rw-r--r-- | src/core/dbus-unit.c | 155 | ||||
-rw-r--r-- | src/core/dbus-unit.h | 8 | ||||
-rw-r--r-- | src/core/dbus.c | 71 | ||||
-rw-r--r-- | src/core/dbus.h | 5 | ||||
-rw-r--r-- | src/core/execute.c | 38 | ||||
-rw-r--r-- | src/core/job.c | 17 | ||||
-rw-r--r-- | src/core/job.h | 4 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 3 | ||||
-rw-r--r-- | src/core/load-fragment.c | 27 | ||||
-rw-r--r-- | src/core/main.c | 6 | ||||
-rw-r--r-- | src/core/manager.c | 29 | ||||
-rw-r--r-- | src/core/mount-setup.c | 6 | ||||
-rw-r--r-- | src/core/mount.c | 14 | ||||
-rw-r--r-- | src/core/mount.h | 3 | ||||
-rw-r--r-- | src/core/org.freedesktop.systemd1.conf | 8 | ||||
-rw-r--r-- | src/core/scope.c | 2 | ||||
-rw-r--r-- | src/core/selinux-access.h | 2 | ||||
-rw-r--r-- | src/core/service.c | 2 | ||||
-rw-r--r-- | src/core/unit.c | 72 | ||||
-rw-r--r-- | src/core/unit.h | 10 |
25 files changed, 491 insertions, 125 deletions
diff --git a/src/core/cgroup.c b/src/core/cgroup.c index ca3c3366f3..7873f88785 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -66,6 +66,7 @@ void cgroup_context_init(CGroupContext *c) { c->memory_high = CGROUP_LIMIT_MAX; c->memory_max = CGROUP_LIMIT_MAX; + c->memory_swap_max = CGROUP_LIMIT_MAX; c->memory_limit = CGROUP_LIMIT_MAX; @@ -173,6 +174,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { "%sMemoryLow=%" PRIu64 "\n" "%sMemoryHigh=%" PRIu64 "\n" "%sMemoryMax=%" PRIu64 "\n" + "%sMemorySwapMax=%" PRIu64 "\n" "%sMemoryLimit=%" PRIu64 "\n" "%sTasksMax=%" PRIu64 "\n" "%sDevicePolicy=%s\n" @@ -194,6 +196,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { prefix, c->memory_low, prefix, c->memory_high, prefix, c->memory_max, + prefix, c->memory_swap_max, prefix, c->memory_limit, prefix, c->tasks_max, prefix, cgroup_device_policy_to_string(c->device_policy), @@ -617,7 +620,7 @@ static unsigned cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, u } static bool cgroup_context_has_unified_memory_config(CGroupContext *c) { - return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX; + return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX || c->memory_swap_max != CGROUP_LIMIT_MAX; } static void cgroup_apply_unified_memory_limit(Unit *u, const char *file, uint64_t v) { @@ -665,7 +668,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { bool has_weight = cgroup_context_has_cpu_weight(c); bool has_shares = cgroup_context_has_cpu_shares(c); - if (cg_unified() > 0) { + if (cg_all_unified() > 0) { uint64_t weight; if (has_weight) @@ -846,12 +849,14 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { } if ((mask & CGROUP_MASK_MEMORY) && !is_root) { - if (cg_unified() > 0) { + if (cg_all_unified() > 0) { uint64_t max = c->memory_max; + uint64_t swap_max = c->memory_swap_max; - if (cgroup_context_has_unified_memory_config(c)) + if (cgroup_context_has_unified_memory_config(c)) { max = c->memory_max; - else { + swap_max = c->memory_swap_max; + } else { max = c->memory_limit; if (max != CGROUP_LIMIT_MAX) @@ -861,6 +866,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) { cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low); cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high); cgroup_apply_unified_memory_limit(u, "memory.max", max); + cgroup_apply_unified_memory_limit(u, "memory.swap.max", swap_max); } else { char buf[DECIMAL_STR_MAX(uint64_t) + 1]; uint64_t val = c->memory_limit; @@ -1019,7 +1025,7 @@ CGroupMask unit_get_own_mask(Unit *u) { e = unit_get_exec_context(u); if (!e || exec_context_maintains_privileges(e) || - cg_unified() > 0) + cg_all_unified() > 0) return _CGROUP_MASK_ALL; } @@ -1245,7 +1251,7 @@ int unit_watch_cgroup(Unit *u) { return 0; /* Only applies to the unified hierarchy */ - r = cg_unified(); + r = cg_unified(SYSTEMD_CGROUP_CONTROLLER); if (r < 0) return log_unit_error_errno(u, r, "Failed detect whether the unified hierarchy is used: %m"); if (r == 0) @@ -1524,6 +1530,8 @@ void unit_prune_cgroup(Unit *u) { if (!u->cgroup_path) return; + (void) unit_get_cpu_usage(u, NULL); /* Cache the last CPU usage value before we destroy the cgroup */ + is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE); r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice); @@ -1645,7 +1653,7 @@ int unit_watch_all_pids(Unit *u) { if (!u->cgroup_path) return -ENOENT; - if (cg_unified() > 0) /* On unified we can use proper notifications */ + if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) > 0) /* On unified we can use proper notifications */ return 0; return unit_watch_pids_in_path(u, u->cgroup_path); @@ -1718,7 +1726,7 @@ static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, int manager_setup_cgroup(Manager *m) { _cleanup_free_ char *path = NULL; CGroupController c; - int r, unified; + int r, all_unified, systemd_unified; char *e; assert(m); @@ -1755,11 +1763,17 @@ int manager_setup_cgroup(Manager *m) { if (r < 0) return log_error_errno(r, "Cannot find cgroup mount point: %m"); - unified = cg_unified(); - if (unified < 0) - return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m"); - if (unified > 0) + all_unified = cg_all_unified(); + systemd_unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER); + + if (all_unified < 0 || systemd_unified < 0) + return log_error_errno(all_unified < 0 ? all_unified : systemd_unified, + "Couldn't determine if we are running in the unified hierarchy: %m"); + + if (all_unified > 0) log_debug("Unified cgroup hierarchy is located at %s.", path); + else if (systemd_unified > 0) + log_debug("Unified cgroup hierarchy is located at %s. Controllers are on legacy hierarchies.", path); else log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path); @@ -1767,7 +1781,7 @@ int manager_setup_cgroup(Manager *m) { const char *scope_path; /* 3. Install agent */ - if (unified) { + if (systemd_unified) { /* In the unified hierarchy we can get * cgroup empty notifications via inotify. */ @@ -1827,7 +1841,7 @@ int manager_setup_cgroup(Manager *m) { return log_error_errno(errno, "Failed to open pin file: %m"); /* 6. Always enable hierarchical support if it exists... */ - if (!unified) + if (!all_unified) (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1"); } @@ -1953,7 +1967,7 @@ int unit_get_memory_current(Unit *u, uint64_t *ret) { if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0) return -ENODATA; - if (cg_unified() <= 0) + if (cg_all_unified() <= 0) r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v); else r = cg_get_attribute("memory", u->cgroup_path, "memory.current", &v); @@ -1998,7 +2012,7 @@ static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) { if (!u->cgroup_path) return -ENODATA; - if (cg_unified() > 0) { + if (cg_all_unified() > 0) { const char *keys[] = { "usage_usec", NULL }; _cleanup_free_ char *val = NULL; uint64_t us; @@ -2038,7 +2052,21 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) { nsec_t ns; int r; + assert(u); + + /* Retrieve the current CPU usage counter. This will subtract the CPU counter taken when the unit was + * started. If the cgroup has been removed already, returns the last cached value. To cache the value, simply + * call this function with a NULL return value. */ + r = unit_get_cpu_usage_raw(u, &ns); + if (r == -ENODATA && u->cpu_usage_last != NSEC_INFINITY) { + /* If we can't get the CPU usage anymore (because the cgroup was already removed, for example), use our + * cached value. */ + + if (ret) + *ret = u->cpu_usage_last; + return 0; + } if (r < 0) return r; @@ -2047,7 +2075,10 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) { else ns = 0; - *ret = ns; + u->cpu_usage_last = ns; + if (ret) + *ret = ns; + return 0; } @@ -2057,6 +2088,8 @@ int unit_reset_cpu_usage(Unit *u) { assert(u); + u->cpu_usage_last = NSEC_INFINITY; + r = unit_get_cpu_usage_raw(u, &ns); if (r < 0) { u->cpu_usage_base = 0; diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 2fe9cc4039..4cd168f63e 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -101,6 +101,7 @@ struct CGroupContext { uint64_t memory_low; uint64_t memory_high; uint64_t memory_max; + uint64_t memory_swap_max; /* For legacy hierarchies */ uint64_t cpu_shares; diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 2ca80d2996..c4067a95bf 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -233,6 +233,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0), SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0), SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0), + SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0), SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), @@ -875,7 +876,7 @@ int bus_cgroup_set_property( return 1; - } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax")) { + } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax")) { uint64_t v; r = sd_bus_message_read(message, "t", &v); @@ -889,6 +890,8 @@ int bus_cgroup_set_property( c->memory_low = v; else if (streq(name, "MemoryHigh")) c->memory_high = v; + else if (streq(name, "MemorySwapMax")) + c->memory_swap_max = v; else c->memory_max = v; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index ef05a75a8b..ea7ced2fd0 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -643,6 +643,54 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s return bus_unit_method_set_properties(message, u, error); } +static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + r = bus_unit_check_load_state(u, error); + if (r < 0) + return r; + + return bus_unit_method_ref(message, u, error); +} + +static int method_unref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *name; + Unit *u; + int r; + + assert(message); + assert(m); + + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + r = bus_unit_check_load_state(u, error); + if (r < 0) + return r; + + return bus_unit_method_unref(message, u, error); +} + static int reply_unit_info(sd_bus_message *reply, Unit *u) { _cleanup_free_ char *unit_path = NULL, *job_path = NULL; Unit *following; @@ -781,6 +829,13 @@ static int transient_unit_from_message( if (r < 0) return r; + /* If the client asked for it, automatically add a reference to this unit. */ + if (u->bus_track_add) { + r = bus_unit_track_add_sender(u, message); + if (r < 0) + return log_error_errno(r, "Failed to watch sender: %m"); + } + /* Now load the missing bits of the unit we just created */ unit_add_to_load_queue(u); manager_dispatch_load_queue(m); @@ -2211,6 +2266,8 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RefUnit", "s", NULL, method_ref_unit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("UnrefUnit", "s", NULL, method_unref_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c index 3c6bda4073..76a7a7ce97 100644 --- a/src/core/dbus-mount.c +++ b/src/core/dbus-mount.c @@ -116,6 +116,8 @@ const sd_bus_vtable bus_mount_vtable[] = { SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Mount, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Mount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SloppyOptions", "b", bus_property_get_bool, offsetof(Mount, sloppy_options), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LazyUnmount", "b", bus_property_get_bool, offsetof(Mount, lazy_unmount), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ForceUnmount", "b", bus_property_get_bool, offsetof(Mount, force_unmount), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("GID", "u", NULL, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 89e56a2e51..1b86bdde43 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -418,6 +418,7 @@ static int bus_verify_manage_units_async_full( const char *verb, int capability, const char *polkit_message, + bool interactive, sd_bus_message *call, sd_bus_error *error) { @@ -433,7 +434,15 @@ static int bus_verify_manage_units_async_full( details[7] = GETTEXT_PACKAGE; } - return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error); + return bus_verify_polkit_async( + call, + capability, + "org.freedesktop.systemd1.manage-units", + details, + interactive, + UID_INVALID, + &u->manager->polkit_registry, + error); } int bus_unit_method_start_generic( @@ -486,6 +495,7 @@ int bus_unit_method_start_generic( verb, CAP_SYS_ADMIN, job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL, + true, message, error); if (r < 0) @@ -558,6 +568,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error * "kill", CAP_KILL, N_("Authentication is required to kill '$(unit)'."), + true, message, error); if (r < 0) @@ -588,6 +599,7 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus "reset-failed", CAP_SYS_ADMIN, N_("Authentication is required to reset the \"failed\" state of '$(unit)'."), + true, message, error); if (r < 0) @@ -620,6 +632,7 @@ int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_b "set-property", CAP_SYS_ADMIN, N_("Authentication is required to set properties on '$(unit)'."), + true, message, error); if (r < 0) @@ -634,6 +647,53 @@ int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_b return sd_bus_reply_method_return(message, NULL); } +int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Unit *u = userdata; + int r; + + assert(message); + assert(u); + + r = mac_selinux_unit_access_check(u, message, "start", error); + if (r < 0) + return r; + + r = bus_verify_manage_units_async_full( + u, + "ref", + CAP_SYS_ADMIN, + NULL, + false, + message, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + + r = bus_unit_track_add_sender(u, message); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Unit *u = userdata; + int r; + + assert(message); + assert(u); + + r = bus_unit_track_remove_sender(u, message); + if (r == -EUNATCH) + return sd_bus_error_setf(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet."); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_VTABLE_START(0), @@ -715,6 +775,8 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Ref", NULL, NULL, bus_unit_method_ref, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Unref", NULL, NULL, bus_unit_method_unref, SD_BUS_VTABLE_UNPRIVILEGED), /* Obsolete properties or obsolete alias names */ SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), @@ -1318,6 +1380,29 @@ static int bus_unit_set_transient_property( return r; return 1; + + } else if (streq(name, "AddRef")) { + + int b; + + /* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method + * on the Unit interface, and it's probably not a good idea to expose a property and a method on the + * same interface (well, strictly speaking AddRef isn't exposed as full property, we just read it for + * transient units, but still). And "References" and "ReferencedBy" is already used as unit reference + * dependency type, hence let's not confuse things with that. + * + * Note that we don't acually add the reference to the bus track. We do that only after the setup of + * the transient unit is complete, so that setting this property multiple times in the same transient + * unit creation call doesn't count as individual references. */ + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) + u->bus_track_add = b; + + return 1; } return 0; @@ -1422,3 +1507,71 @@ int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id); } + +static int bus_track_handler(sd_bus_track *t, void *userdata) { + Unit *u = userdata; + + assert(t); + assert(u); + + u->bus_track = sd_bus_track_unref(u->bus_track); /* make sure we aren't called again */ + + unit_add_to_gc_queue(u); + return 0; +} + +static int allocate_bus_track(Unit *u) { + int r; + + assert(u); + + if (u->bus_track) + return 0; + + r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_track_handler, u); + if (r < 0) + return r; + + r = sd_bus_track_set_recursive(u->bus_track, true); + if (r < 0) { + u->bus_track = sd_bus_track_unref(u->bus_track); + return r; + } + + return 0; +} + +int bus_unit_track_add_name(Unit *u, const char *name) { + int r; + + assert(u); + + r = allocate_bus_track(u); + if (r < 0) + return r; + + return sd_bus_track_add_name(u->bus_track, name); +} + +int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) { + int r; + + assert(u); + + r = allocate_bus_track(u); + if (r < 0) + return r; + + return sd_bus_track_add_sender(u->bus_track, m); +} + +int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) { + assert(u); + + /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an + * error */ + if (!u->bus_track) + return -EUNATCH; + + return sd_bus_track_remove_sender(u->bus_track, m); +} diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index 4db88dbebc..b280de7a1d 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -33,9 +33,15 @@ int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error); -int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error); int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error); int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error); int bus_unit_check_load_state(Unit *u, sd_bus_error *error); + +int bus_unit_track_add_name(Unit *u, const char *name); +int bus_unit_track_add_sender(Unit *u, sd_bus_message *m); +int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m); diff --git a/src/core/dbus.c b/src/core/dbus.c index 3422a02d68..1e41a42aa6 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -1168,60 +1168,57 @@ int bus_foreach_bus( return ret; } -void bus_track_serialize(sd_bus_track *t, FILE *f) { +void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix) { const char *n; assert(f); + assert(prefix); - for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) - fprintf(f, "subscribed=%s\n", n); -} - -int bus_track_deserialize_item(char ***l, const char *line) { - const char *e; - int r; - - assert(l); - assert(line); - - e = startswith(line, "subscribed="); - if (!e) - return 0; + for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) { + int c, j; - r = strv_extend(l, e); - if (r < 0) - return r; + c = sd_bus_track_count_name(t, n); - return 1; + for (j = 0; j < c; j++) { + fputs(prefix, f); + fputc('=', f); + fputs(n, f); + fputc('\n', f); + } + } } -int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) { +int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l) { + char **i; int r = 0; assert(m); assert(t); - assert(l); - - if (!strv_isempty(*l) && m->api_bus) { - char **i; - if (!*t) { - r = sd_bus_track_new(m->api_bus, t, NULL, NULL); - if (r < 0) - return r; - } + if (strv_isempty(l)) + return 0; - r = 0; - STRV_FOREACH(i, *l) { - int k; + if (!m->api_bus) + return 0; - k = sd_bus_track_add_name(*t, *i); - if (k < 0) - r = k; - } + if (!*t) { + r = sd_bus_track_new(m->api_bus, t, NULL, NULL); + if (r < 0) + return r; } - *l = strv_free(*l); + r = sd_bus_track_set_recursive(*t, recursive); + if (r < 0) + return r; + + r = 0; + STRV_FOREACH(i, l) { + int k; + + k = sd_bus_track_add_name(*t, *i); + if (k < 0) + r = k; + } return r; } diff --git a/src/core/dbus.h b/src/core/dbus.h index 6baaffbd75..a092ed9d76 100644 --- a/src/core/dbus.h +++ b/src/core/dbus.h @@ -28,9 +28,8 @@ void bus_done(Manager *m); int bus_fdset_add_all(Manager *m, FDSet *fds); -void bus_track_serialize(sd_bus_track *t, FILE *f); -int bus_track_deserialize_item(char ***l, const char *line); -int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l); +void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix); +int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l); int manager_sync_bus_names(Manager *m, sd_bus *bus); diff --git a/src/core/execute.c b/src/core/execute.c index 0af8eb5a02..55f15d7e49 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1074,7 +1074,17 @@ static void rename_process_from_path(const char *path) { #ifdef HAVE_SECCOMP -static int apply_seccomp(const ExecContext *c) { +static bool skip_seccomp_unavailable(const Unit* u, const char* msg) { + if (!is_seccomp_available()) { + log_open(); + log_unit_debug(u, "SECCOMP not detected in the kernel, skipping %s", msg); + log_close(); + return true; + } + return false; +} + +static int apply_seccomp(const Unit* u, const ExecContext *c) { uint32_t negative_action, action; scmp_filter_ctx *seccomp; Iterator i; @@ -1083,6 +1093,9 @@ static int apply_seccomp(const ExecContext *c) { assert(c); + if (skip_seccomp_unavailable(u, "syscall filtering")) + return 0; + negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL : SCMP_ACT_ERRNO(c->syscall_errno); seccomp = seccomp_init(c->syscall_whitelist ? negative_action : SCMP_ACT_ALLOW); @@ -1123,13 +1136,16 @@ finish: return r; } -static int apply_address_families(const ExecContext *c) { +static int apply_address_families(const Unit* u, const ExecContext *c) { scmp_filter_ctx *seccomp; Iterator i; int r; assert(c); + if (skip_seccomp_unavailable(u, "RestrictAddressFamilies=")) + return 0; + seccomp = seccomp_init(SCMP_ACT_ALLOW); if (!seccomp) return -ENOMEM; @@ -1244,12 +1260,15 @@ finish: return r; } -static int apply_memory_deny_write_execute(const ExecContext *c) { +static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) { scmp_filter_ctx *seccomp; int r; assert(c); + if (skip_seccomp_unavailable(u, "MemoryDenyWriteExecute=")) + return 0; + seccomp = seccomp_init(SCMP_ACT_ALLOW); if (!seccomp) return -ENOMEM; @@ -1283,7 +1302,7 @@ finish: return r; } -static int apply_restrict_realtime(const ExecContext *c) { +static int apply_restrict_realtime(const Unit* u, const ExecContext *c) { static const int permitted_policies[] = { SCHED_OTHER, SCHED_BATCH, @@ -1296,6 +1315,9 @@ static int apply_restrict_realtime(const ExecContext *c) { assert(c); + if (skip_seccomp_unavailable(u, "RestrictRealtime=")) + return 0; + seccomp = seccomp_init(SCMP_ACT_ALLOW); if (!seccomp) return -ENOMEM; @@ -2403,7 +2425,7 @@ static int exec_child( #ifdef HAVE_SECCOMP if (use_address_families) { - r = apply_address_families(context); + r = apply_address_families(unit, context); if (r < 0) { *exit_status = EXIT_ADDRESS_FAMILIES; return r; @@ -2411,7 +2433,7 @@ static int exec_child( } if (context->memory_deny_write_execute) { - r = apply_memory_deny_write_execute(context); + r = apply_memory_deny_write_execute(unit, context); if (r < 0) { *exit_status = EXIT_SECCOMP; return r; @@ -2419,7 +2441,7 @@ static int exec_child( } if (context->restrict_realtime) { - r = apply_restrict_realtime(context); + r = apply_restrict_realtime(unit, context); if (r < 0) { *exit_status = EXIT_SECCOMP; return r; @@ -2427,7 +2449,7 @@ static int exec_child( } if (use_syscall_filter) { - r = apply_seccomp(context); + r = apply_seccomp(unit, context); if (r < 0) { *exit_status = EXIT_SECCOMP; return r; diff --git a/src/core/job.c b/src/core/job.c index 7557874d4d..7faf2ef686 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -997,7 +997,10 @@ char *job_dbus_path(Job *j) { return p; } -int job_serialize(Job *j, FILE *f, FDSet *fds) { +int job_serialize(Job *j, FILE *f) { + assert(j); + assert(f); + fprintf(f, "job-id=%u\n", j->id); fprintf(f, "job-type=%s\n", job_type_to_string(j->type)); fprintf(f, "job-state=%s\n", job_state_to_string(j->state)); @@ -1008,15 +1011,16 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) { if (j->begin_usec > 0) fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec); - bus_track_serialize(j->clients, f); + bus_track_serialize(j->clients, f, "subscribed"); /* End marker */ fputc('\n', f); return 0; } -int job_deserialize(Job *j, FILE *f, FDSet *fds) { +int job_deserialize(Job *j, FILE *f) { assert(j); + assert(f); for (;;) { char line[LINE_MAX], *l, *v; @@ -1106,7 +1110,7 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) { } else if (streq(l, "subscribed")) { if (strv_extend(&j->deserialized_clients, v) < 0) - return log_oom(); + log_oom(); } } } @@ -1118,9 +1122,8 @@ int job_coldplug(Job *j) { /* After deserialization is complete and the bus connection * set up again, let's start watching our subscribers again */ - r = bus_track_coldplug(j->manager, &j->clients, &j->deserialized_clients); - if (r < 0) - return r; + (void) bus_track_coldplug(j->manager, &j->clients, false, j->deserialized_clients); + j->deserialized_clients = strv_free(j->deserialized_clients); if (j->state == JOB_WAITING) job_add_to_run_queue(j); diff --git a/src/core/job.h b/src/core/job.h index d359e8bb3e..85368f0d30 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -177,8 +177,8 @@ Job* job_install(Job *j); int job_install_deserialized(Job *j); void job_uninstall(Job *j); void job_dump(Job *j, FILE*f, const char *prefix); -int job_serialize(Job *j, FILE *f, FDSet *fds); -int job_deserialize(Job *j, FILE *f, FDSet *fds); +int job_serialize(Job *j, FILE *f); +int job_deserialize(Job *j, FILE *f); int job_coldplug(Job *j); JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 05fe0df7e3..2e6c965aec 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -131,6 +131,7 @@ $1.MemoryAccounting, config_parse_bool, 0, $1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.MemoryMax, config_parse_memory_limit, 0, offsetof($1, cgroup_context) +$1.MemorySwapMax, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context) $1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy) @@ -355,6 +356,8 @@ Mount.Type, config_parse_string, 0, Mount.TimeoutSec, config_parse_sec, 0, offsetof(Mount, timeout_usec) Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) Mount.SloppyOptions, config_parse_bool, 0, offsetof(Mount, sloppy_options) +Mount.LazyUnmount, config_parse_bool, 0, offsetof(Mount, lazy_unmount) +Mount.ForceUnmount, config_parse_bool, 0, offsetof(Mount, force_unmount) EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d5185cf6a0..8f067b5586 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1338,10 +1338,13 @@ int config_parse_timer(const char *unit, void *userdata) { Timer *t = data; - usec_t u = 0; + usec_t usec = 0; TimerValue *v; TimerBase b; CalendarSpec *c = NULL; + Unit *u = userdata; + _cleanup_free_ char *k = NULL; + int r; assert(filename); assert(lvalue); @@ -1360,14 +1363,20 @@ int config_parse_timer(const char *unit, return 0; } + r = unit_full_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue); + return 0; + } + if (b == TIMER_CALENDAR) { - if (calendar_spec_from_string(rvalue, &c) < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", rvalue); + if (calendar_spec_from_string(k, &c) < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", k); return 0; } } else { - if (parse_sec(rvalue, &u) < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", rvalue); + if (parse_sec(k, &usec) < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", k); return 0; } } @@ -1379,7 +1388,7 @@ int config_parse_timer(const char *unit, } v->base = b; - v->value = u; + v->value = usec; v->calendar_spec = c; LIST_PREPEND(value, t->values, v); @@ -2981,8 +2990,12 @@ int config_parse_memory_limit( c->memory_high = bytes; else if (streq(lvalue, "MemoryMax")) c->memory_max = bytes; - else + else if (streq(lvalue, "MemorySwapMax")) + c->memory_swap_max = bytes; + else if (streq(lvalue, "MemoryLimit")) c->memory_limit = bytes; + else + return -EINVAL; return 0; } diff --git a/src/core/main.c b/src/core/main.c index 125cfb28f0..7d8322ebd8 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -72,6 +72,9 @@ #include "process-util.h" #include "raw-clone.h" #include "rlimit-util.h" +#ifdef HAVE_SECCOMP +#include "seccomp-util.h" +#endif #include "selinux-setup.h" #include "selinux-util.h" #include "signal-util.h" @@ -1186,6 +1189,9 @@ static int enforce_syscall_archs(Set *archs) { void *id; int r; + if (!is_seccomp_available()) + return 0; + seccomp = seccomp_init(SCMP_ACT_ALLOW); if (!seccomp) return log_oom(); diff --git a/src/core/manager.c b/src/core/manager.c index 6f2477eef4..b58f68fa7a 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -771,7 +771,7 @@ static int manager_setup_cgroups_agent(Manager *m) { if (!MANAGER_IS_SYSTEM(m)) return 0; - if (cg_unified() > 0) /* We don't need this anymore on the unified hierarchy */ + if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) > 0) /* We don't need this anymore on the unified hierarchy */ return 0; if (m->cgroups_agent_fd < 0) { @@ -1287,10 +1287,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { if (q < 0 && r == 0) r = q; - /* We might have deserialized the kdbus control fd, but if we - * didn't, then let's create the bus now. */ - manager_connect_bus(m, !!serialization); - bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed); + /* We might have deserialized the kdbus control fd, but if we didn't, then let's create the bus now. */ + (void) manager_connect_bus(m, !!serialization); + + (void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed); + m->deserialized_subscribed = strv_free(m->deserialized_subscribed); /* Third, fire things up! */ manager_coldplug(m); @@ -2490,7 +2491,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { fprintf(f, "kdbus-fd=%i\n", copy); } - bus_track_serialize(m->subscribed, f); + bus_track_serialize(m->subscribed, f, "subscribed"); r = dynamic_user_serialize(m, f, fds); if (r < 0) @@ -2693,15 +2694,13 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { manager_deserialize_uid_refs_one(m, l + 16); else if (startswith(l, "destroy-ipc-gid=")) manager_deserialize_gid_refs_one(m, l + 16); - else { - int k; - - k = bus_track_deserialize_item(&m->deserialized_subscribed, l); - if (k < 0) - log_debug_errno(k, "Failed to deserialize bus tracker object: %m"); - else if (k == 0) - log_debug("Unknown serialization item '%s'", l); - } + else if (startswith(l, "subscribed=")) { + + if (strv_extend(&m->deserialized_subscribed, l+11) < 0) + log_oom(); + + } else + log_debug("Unknown serialization item '%s'", l); } for (;;) { diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 5d8ab0ec70..ca63a93e8b 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -99,10 +99,12 @@ static const MountPoint mount_table[] = { cg_is_unified_wanted, MNT_FATAL|MNT_IN_CONTAINER }, { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER }, + { "cgroup", "/sys/fs/cgroup/systemd", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, + cg_is_unified_systemd_controller_wanted, MNT_IN_CONTAINER }, { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV, - cg_is_legacy_wanted, MNT_IN_CONTAINER }, + cg_is_legacy_systemd_controller_wanted, MNT_IN_CONTAINER }, { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, - cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER }, + cg_is_legacy_systemd_controller_wanted, MNT_FATAL|MNT_IN_CONTAINER }, { "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL, MNT_NONE }, #ifdef ENABLE_EFI diff --git a/src/core/mount.c b/src/core/mount.c index f2ac8d171f..04025b83b9 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -677,7 +677,10 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { "%sOptions: %s\n" "%sFrom /proc/self/mountinfo: %s\n" "%sFrom fragment: %s\n" - "%sDirectoryMode: %04o\n", + "%sDirectoryMode: %04o\n" + "%sSloppyOptions: %s\n" + "%sLazyUnmount: %s\n" + "%sForceUnmount: %s\n", prefix, mount_state_to_string(m->state), prefix, mount_result_to_string(m->result), prefix, m->where, @@ -686,7 +689,10 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { prefix, p ? strna(p->options) : "n/a", prefix, yes_no(m->from_proc_self_mountinfo), prefix, yes_no(m->from_fragment), - prefix, m->directory_mode); + prefix, m->directory_mode, + prefix, yes_no(m->sloppy_options), + prefix, yes_no(m->lazy_unmount), + prefix, yes_no(m->force_unmount)); if (m->control_pid > 0) fprintf(f, @@ -846,6 +852,10 @@ static void mount_enter_unmounting(Mount *m) { m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT; r = exec_command_set(m->control_command, UMOUNT_PATH, m->where, NULL); + if (r >= 0 && m->lazy_unmount) + r = exec_command_append(m->control_command, "-l", NULL); + if (r >= 0 && m->force_unmount) + r = exec_command_append(m->control_command, "-f", NULL); if (r < 0) goto fail; diff --git a/src/core/mount.h b/src/core/mount.h index ac27b518cc..9f7326ba6a 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -71,6 +71,9 @@ struct Mount { bool sloppy_options; + bool lazy_unmount; + bool force_unmount; + MountResult result; MountResult reload_result; diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 14f6aec029..647e5f736c 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -184,6 +184,14 @@ <allow send_destination="org.freedesktop.systemd1" send_interface="org.freedesktop.systemd1.Manager" + send_member="RefUnit"/> + + <allow send_destination="org.freedesktop.systemd1" + send_interface="org.freedesktop.systemd1.Manager" + send_member="UnrefUnit"/> + + <allow send_destination="org.freedesktop.systemd1" + send_interface="org.freedesktop.systemd1.Manager" send_member="EnableUnitFiles"/> <allow send_destination="org.freedesktop.systemd1" diff --git a/src/core/scope.c b/src/core/scope.c index b278aed3d6..65fa65493b 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -441,7 +441,7 @@ static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) { /* If the PID set is empty now, then let's finish this off (On unified we use proper notifications) */ - if (cg_unified() <= 0 && set_isempty(u->pids)) + if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) <= 0 && set_isempty(u->pids)) scope_notify_cgroup_empty_event(u); } diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h index 8f1f058a32..f46370d020 100644 --- a/src/core/selinux-access.h +++ b/src/core/selinux-access.h @@ -33,7 +33,7 @@ int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, #define mac_selinux_unit_access_check(unit, message, permission, error) \ ({ \ - Unit *_unit = (unit); \ + const Unit *_unit = (unit); \ mac_selinux_generic_access_check((message), _unit->source_path ?: _unit->fragment_path, (permission), (error)); \ }) diff --git a/src/core/service.c b/src/core/service.c index 1951ba9222..969c62bd83 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -2869,7 +2869,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { /* If the PID set is empty now, then let's finish this off (On unified we use proper notifications) */ - if (cg_unified() <= 0 && set_isempty(u->pids)) + if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) <= 0 && set_isempty(u->pids)) service_notify_cgroup_empty_event(u); } diff --git a/src/core/unit.c b/src/core/unit.c index 4b8d81c3f1..de22f657c6 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -102,6 +102,7 @@ Unit *unit_new(Manager *m, size_t size) { u->job_timeout = USEC_INFINITY; u->ref_uid = UID_INVALID; u->ref_gid = GID_INVALID; + u->cpu_usage_last = NSEC_INFINITY; RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst); RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16); @@ -113,7 +114,7 @@ bool unit_has_name(Unit *u, const char *name) { assert(u); assert(name); - return !!set_get(u->names, (char*) name); + return set_contains(u->names, (char*) name); } static void unit_init(Unit *u) { @@ -329,6 +330,9 @@ bool unit_check_gc(Unit *u) { if (u->refs) return true; + if (sd_bus_track_count(u->bus_track) > 0) + return true; + if (UNIT_VTABLE(u)->check_gc) if (UNIT_VTABLE(u)->check_gc(u)) return true; @@ -509,6 +513,9 @@ void unit_free(Unit *u) { sd_bus_slot_unref(u->match_bus_slot); + sd_bus_track_unref(u->bus_track); + u->deserialized_refs = strv_free(u->deserialized_refs); + unit_free_requires_mounts_for(u); SET_FOREACH(t, u->names, i) @@ -897,6 +904,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { Unit *following; _cleanup_set_free_ Set *following_set = NULL; int r; + const char *n; assert(u); assert(u->type >= 0); @@ -1038,6 +1046,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { else if (u->load_state == UNIT_ERROR) fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error)); + for (n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track)) + fprintf(f, "%s\tBus Ref: %s\n", prefix, n); if (u->job) job_dump(u->job, f, prefix2); @@ -2611,7 +2621,10 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result)); unit_serialize_item(u, f, "transient", yes_no(u->transient)); + unit_serialize_item_format(u, f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base); + if (u->cpu_usage_last != NSEC_INFINITY) + unit_serialize_item_format(u, f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last); if (u->cgroup_path) unit_serialize_item(u, f, "cgroup", u->cgroup_path); @@ -2622,15 +2635,17 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { if (gid_is_valid(u->ref_gid)) unit_serialize_item_format(u, f, "ref-gid", GID_FMT, u->ref_gid); + bus_track_serialize(u->bus_track, f, "ref"); + if (serialize_jobs) { if (u->job) { fprintf(f, "job\n"); - job_serialize(u->job, f, fds); + job_serialize(u->job, f); } if (u->nop_job) { fprintf(f, "job\n"); - job_serialize(u->nop_job, f, fds); + job_serialize(u->nop_job, f); } } @@ -2760,7 +2775,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { if (!j) return log_oom(); - r = job_deserialize(j, f, fds); + r = job_deserialize(j, f); if (r < 0) { job_free(j); return r; @@ -2832,11 +2847,19 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { continue; - } else if (streq(l, "cpu-usage-base") || streq(l, "cpuacct-usage-base")) { + } else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) { r = safe_atou64(v, &u->cpu_usage_base); if (r < 0) - log_unit_debug(u, "Failed to parse CPU usage %s, ignoring.", v); + log_unit_debug(u, "Failed to parse CPU usage base %s, ignoring.", v); + + continue; + + } else if (streq(l, "cpu-usage-last")) { + + r = safe_atou64(v, &u->cpu_usage_last); + if (r < 0) + log_unit_debug(u, "Failed to read CPU usage last %s, ignoring.", v); continue; @@ -2880,6 +2903,12 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { else unit_ref_uid_gid(u, UID_INVALID, gid); + } else if (streq(l, "ref")) { + + r = strv_extend(&u->deserialized_refs, v); + if (r < 0) + log_oom(); + continue; } @@ -2955,7 +2984,8 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep } int unit_coldplug(Unit *u) { - int r = 0, q = 0; + int r = 0, q; + char **i; assert(u); @@ -2966,18 +2996,26 @@ int unit_coldplug(Unit *u) { u->coldplugged = true; - if (UNIT_VTABLE(u)->coldplug) - r = UNIT_VTABLE(u)->coldplug(u); + STRV_FOREACH(i, u->deserialized_refs) { + q = bus_unit_track_add_name(u, *i); + if (q < 0 && r >= 0) + r = q; + } + u->deserialized_refs = strv_free(u->deserialized_refs); - if (u->job) - q = job_coldplug(u->job); + if (UNIT_VTABLE(u)->coldplug) { + q = UNIT_VTABLE(u)->coldplug(u); + if (q < 0 && r >= 0) + r = q; + } - if (r < 0) - return r; - if (q < 0) - return q; + if (u->job) { + q = job_coldplug(u->job); + if (q < 0 && r >= 0) + r = q; + } - return 0; + return r; } static bool fragment_mtime_newer(const char *path, usec_t mtime) { @@ -3726,7 +3764,7 @@ int unit_kill_context( * there we get proper events. Hence rely on * them.*/ - if (cg_unified() > 0 || + if (cg_unified(SYSTEMD_CGROUP_CONTROLLER) > 0 || (detect_container() == 0 && !unit_cgroup_delegate(u))) wait_for_exit = true; diff --git a/src/core/unit.h b/src/core/unit.h index 53875653d7..3584c16d8c 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -108,6 +108,10 @@ struct Unit { /* The slot used for watching NameOwnerChanged signals */ sd_bus_slot *match_bus_slot; + /* References to this unit from clients */ + sd_bus_track *bus_track; + char **deserialized_refs; + /* Job timeout and action to take */ usec_t job_timeout; FailureAction job_timeout_action; @@ -190,6 +194,7 @@ struct Unit { /* Where the cpu.stat or cpuacct.usage was at the time the unit was started */ nsec_t cpu_usage_base; + nsec_t cpu_usage_last; /* the most recently read value */ /* Counterparts in the cgroup filesystem */ char *cgroup_path; @@ -247,6 +252,9 @@ struct Unit { /* Did we already invoke unit_coldplug() for this unit? */ bool coldplugged:1; + + /* For transient units: whether to add a bus track reference after creating the unit */ + bool bus_track_add:1; }; struct UnitStatusMessageFormats { @@ -639,7 +647,7 @@ void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid); #define log_unit_full(unit, level, error, ...) \ ({ \ - Unit *_u = (unit); \ + const Unit *_u = (unit); \ _u ? log_object_internal(level, error, __FILE__, __LINE__, __func__, _u->manager->unit_log_field, _u->id, ##__VA_ARGS__) : \ log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ }) |