diff --git a/src/core/automount.c b/src/core/automount.c index 9b0d1ca429..befa3131ee 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -130,7 +130,20 @@ static void automount_done(Unit *u) { a->expire_event_source = sd_event_source_unref(a->expire_event_source); } -static int automount_add_mount_links(Automount *a) { +static int automount_add_trigger_dependencies(Automount *a) { + Unit *x; + int r; + + assert(a); + + r = unit_load_related_unit(UNIT(a), ".mount", &x); + if (r < 0) + return r; + + return unit_add_two_dependencies(UNIT(a), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT); +} + +static int automount_add_mount_dependencies(Automount *a) { _cleanup_free_ char *parent = NULL; assert(a); @@ -139,7 +152,7 @@ static int automount_add_mount_links(Automount *a) { if (!parent) return -ENOMEM; - return unit_require_mounts_for(UNIT(a), parent); + return unit_require_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT); } static int automount_add_default_dependencies(Automount *a) { @@ -153,7 +166,7 @@ static int automount_add_default_dependencies(Automount *a) { if (!MANAGER_IS_SYSTEM(UNIT(a)->manager)) return 0; - r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; @@ -215,21 +228,15 @@ static int automount_load(Unit *u) { return r; if (u->load_state == UNIT_LOADED) { - Unit *x; - r = automount_set_where(a); if (r < 0) return r; - r = unit_load_related_unit(u, ".mount", &x); + r = automount_add_trigger_dependencies(a); if (r < 0) return r; - r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true); - if (r < 0) - return r; - - r = automount_add_mount_links(a); + r = automount_add_mount_dependencies(a); if (r < 0) return r; diff --git a/src/core/cgroup.c b/src/core/cgroup.c index e9f9447118..dff7d1dddc 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1095,10 +1095,11 @@ CGroupMask unit_get_members_mask(Unit *u) { u->cgroup_members_mask = 0; if (u->type == UNIT_SLICE) { + void *v; Unit *member; Iterator i; - SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) { + HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i) { if (member == u) continue; @@ -1575,8 +1576,9 @@ static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) { while ((slice = UNIT_DEREF(u->slice))) { Iterator i; Unit *m; + void *v; - SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) { + HASHMAP_FOREACH_KEY(v, m, u->dependencies[UNIT_BEFORE], i) { if (m == u) continue; @@ -2426,8 +2428,9 @@ void unit_invalidate_cgroup_bpf(Unit *u) { if (u->type == UNIT_SLICE) { Unit *member; Iterator i; + void *v; - SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) { + HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i) { if (member == u) continue; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index a9a68826b4..8fc02ab744 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -100,9 +100,10 @@ static int property_get_dependencies( void *userdata, sd_bus_error *error) { - Set *s = *(Set**) userdata; + Hashmap *h = *(Hashmap**) userdata; Iterator j; Unit *u; + void *v; int r; assert(bus); @@ -112,7 +113,7 @@ static int property_get_dependencies( if (r < 0) return r; - SET_FOREACH(u, s, j) { + HASHMAP_FOREACH_KEY(v, u, h, j) { r = sd_bus_message_append(reply, "s", u->id); if (r < 0) return r; @@ -1395,7 +1396,7 @@ static int bus_unit_set_transient_property( if (mode != UNIT_CHECK) { _cleanup_free_ char *label = NULL; - r = unit_add_dependency_by_name(u, d, other, NULL, true); + r = unit_add_dependency_by_name(u, d, other, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) return r; diff --git a/src/core/device.c b/src/core/device.c index 3915b2637d..63933baf85 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -279,7 +279,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) { if (r < 0) return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word); - r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true); + r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true, UNIT_DEPENDENCY_UDEV); if (r < 0) return log_unit_error_errno(u, r, "Failed to add wants dependency: %m"); } @@ -303,13 +303,16 @@ static bool device_is_bound_by_mounts(Unit *d, struct udev_device *dev) { static int device_upgrade_mount_deps(Unit *u) { Unit *other; Iterator i; + void *v; int r; - SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) { + /* Let's upgrade Requires= to BindsTo= on us. (Used when SYSTEMD_MOUNT_DEVICE_BOUND is set) */ + + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRED_BY], i) { if (other->type != UNIT_MOUNT) continue; - r = unit_add_dependency(other, UNIT_BINDS_TO, u, true); + r = unit_add_dependency(other, UNIT_BINDS_TO, u, true, UNIT_DEPENDENCY_UDEV); if (r < 0) return r; } @@ -380,11 +383,9 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa (void) device_add_udev_wants(u, dev); } - /* So the user wants the mount units to be bound to the device but a - * mount unit might has been seen by systemd before the device appears - * on its radar. In this case the device unit is partially initialized - * and includes the deps on the mount unit but at that time the "bind - * mounts" flag wasn't not present. Fix this up now. */ + /* So the user wants the mount units to be bound to the device but a mount unit might has been seen by systemd + * before the device appears on its radar. In this case the device unit is partially initialized and includes + * the deps on the mount unit but at that time the "bind mounts" flag wasn't not present. Fix this up now. */ if (dev && device_is_bound_by_mounts(u, dev)) device_upgrade_mount_deps(u); diff --git a/src/core/job.c b/src/core/job.c index d441453839..606b6422ab 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -437,6 +437,7 @@ int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) { static bool job_is_runnable(Job *j) { Iterator i; Unit *other; + void *v; assert(j); assert(j->installed); @@ -459,13 +460,12 @@ static bool job_is_runnable(Job *j) { return true; if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) { - /* Immediate result is that the job is or might be * started. In this case let's wait for the * dependencies, regardless whether they are * starting or stopping something. */ - SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) + HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) if (other->job) return false; } @@ -473,7 +473,7 @@ static bool job_is_runnable(Job *j) { /* Also, if something else is being stopped and we should * change state after it, then let's wait. */ - SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) + HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) if (other->job && IN_SET(other->job->type, JOB_STOP, JOB_RESTART)) return false; @@ -832,10 +832,11 @@ static void job_emit_status_message(Unit *u, JobType t, JobResult result) { static void job_fail_dependencies(Unit *u, UnitDependency d) { Unit *other; Iterator i; + void *v; assert(u); - SET_FOREACH(other, u->dependencies[d], i) { + HASHMAP_FOREACH_KEY(v, other, u->dependencies[d], i) { Job *j = other->job; if (!j) @@ -852,6 +853,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr Unit *other; JobType t; Iterator i; + void *v; assert(j); assert(j->installed); @@ -919,12 +921,12 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr finish: /* Try to start the next jobs that can be started */ - SET_FOREACH(other, u->dependencies[UNIT_AFTER], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_AFTER], i) if (other->job) { job_add_to_run_queue(other->job); job_add_to_gc_queue(other->job); } - SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BEFORE], i) if (other->job) { job_add_to_run_queue(other->job); job_add_to_gc_queue(other->job); @@ -1273,6 +1275,7 @@ int job_get_timeout(Job *j, usec_t *timeout) { bool job_check_gc(Job *j) { Unit *other; Iterator i; + void *v; assert(j); @@ -1301,7 +1304,7 @@ bool job_check_gc(Job *j) { /* If a job is ordered after ours, and is to be started, then it needs to wait for us, regardless if we stop or * start, hence let's not GC in that case. */ - SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) { + HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) { if (!other->job) continue; @@ -1314,7 +1317,7 @@ bool job_check_gc(Job *j) { /* If we are going down, but something else is ordered After= us, then it needs to wait for us */ if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) - SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) { + HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) { if (!other->job) continue; @@ -1392,6 +1395,7 @@ int job_get_before(Job *j, Job*** ret) { size_t n = 0, n_allocated = 0; Unit *other = NULL; Iterator i; + void *v; /* Returns a list of all pending jobs that need to finish before this job may be started. */ @@ -1405,7 +1409,7 @@ int job_get_before(Job *j, Job*** ret) { if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) { - SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) { + HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) { if (!other->job) continue; @@ -1415,7 +1419,7 @@ int job_get_before(Job *j, Job*** ret) { } } - SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) { + HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) { if (!other->job) continue; @@ -1439,6 +1443,7 @@ int job_get_after(Job *j, Job*** ret) { _cleanup_free_ Job** list = NULL; size_t n = 0, n_allocated = 0; Unit *other = NULL; + void *v; Iterator i; assert(j); @@ -1446,7 +1451,7 @@ int job_get_after(Job *j, Job*** ret) { /* Returns a list of all pending jobs that are waiting for this job to finish. */ - SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) { + HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) { if (!other->job) continue; @@ -1463,7 +1468,7 @@ int job_get_after(Job *j, Job*** ret) { if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) { - SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) { + HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) { if (!other->job) continue; diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index 00f09ce60a..948d1bc248 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -115,7 +115,7 @@ static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suff log_unit_warning(u, "%s dependency dropin %s target %s has different name", unit_dependency_to_string(dependency), *p, target); - r = unit_add_dependency_by_name(u, dependency, entry, *p, true); + r = unit_add_dependency_by_name(u, dependency, entry, *p, true, UNIT_DEPENDENCY_FILE); if (r < 0) log_unit_error_errno(u, r, "cannot add %s dependency on %s, ignoring: %m", unit_dependency_to_string(dependency), entry); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a4e39a84ea..125fef6d49 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -142,7 +142,7 @@ int config_parse_unit_deps( continue; } - r = unit_add_dependency_by_name(u, d, k, NULL, true); + r = unit_add_dependency_by_name(u, d, k, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } @@ -1538,7 +1538,7 @@ int config_parse_trigger_unit( assert(rvalue); assert(data); - if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) { + if (!hashmap_isempty(u->dependencies[UNIT_TRIGGERS])) { log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue); return 0; } @@ -1560,7 +1560,7 @@ int config_parse_trigger_unit( return 0; } - r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true); + r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p); return 0; @@ -1760,11 +1760,11 @@ int config_parse_service_sockets( continue; } - r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); - r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true); + r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } @@ -2569,7 +2569,7 @@ int config_parse_unit_requires_mounts_for( continue; } - r = unit_require_mounts_for(u, resolved); + r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount \"%s\", ignoring: %m", resolved); continue; diff --git a/src/core/manager.c b/src/core/manager.c index d501182f22..c89dadc108 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -967,21 +967,23 @@ enum { }; static void unit_gc_mark_good(Unit *u, unsigned gc_marker) { - Iterator i; Unit *other; + Iterator i; + void *v; u->gc_marker = gc_marker + GC_OFFSET_GOOD; /* Recursively mark referenced units as GOOD as well */ - SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCES], i) if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE) unit_gc_mark_good(other, gc_marker); } static void unit_gc_sweep(Unit *u, unsigned gc_marker) { - Iterator i; Unit *other; bool is_bad; + Iterator i; + void *v; assert(u); @@ -999,7 +1001,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) { is_bad = true; - SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) { + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCED_BY], i) { unit_gc_sweep(other, gc_marker); if (other->gc_marker == gc_marker + GC_OFFSET_GOOD) diff --git a/src/core/mount.c b/src/core/mount.c index 9b582072c6..343e17fa10 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -280,8 +280,7 @@ _pure_ static MountParameters* get_mount_parameters(Mount *m) { return get_mount_parameters_fragment(m); } -static int mount_add_mount_links(Mount *m) { - _cleanup_free_ char *parent = NULL; +static int mount_add_mount_dependencies(Mount *m) { const char *fstype; MountParameters *pm; Unit *other; @@ -292,33 +291,32 @@ static int mount_add_mount_links(Mount *m) { assert(m); if (!path_equal(m->where, "/")) { - /* Adds in links to other mount points that might lie further - * up in the hierarchy */ + _cleanup_free_ char *parent = NULL; + + /* Adds in links to other mount points that might lie further up in the hierarchy */ parent = dirname_malloc(m->where); if (!parent) return -ENOMEM; - r = unit_require_mounts_for(UNIT(m), parent); + r = unit_require_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT); if (r < 0) return r; } - /* Adds in links to other mount points that might be needed - * for the source path (if this is a bind mount or a loop mount) to be - * available. */ + /* Adds in dependencies to other mount points that might be needed for the source path (if this is a bind mount + * or a loop mount) to be available. */ pm = get_mount_parameters_fragment(m); if (pm && pm->what && path_is_absolute(pm->what) && (mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) { - r = unit_require_mounts_for(UNIT(m), pm->what); + r = unit_require_mounts_for(UNIT(m), pm->what, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } - /* Adds in links to other units that use this path or paths - * further down in the hierarchy */ + /* Adds in dependencies to other units that use this path or paths further down in the hierarchy */ s = manager_get_units_requiring_mounts_for(UNIT(m)->manager, m->where); SET_FOREACH(other, s, i) { @@ -328,13 +326,13 @@ static int mount_add_mount_links(Mount *m) { if (other == UNIT(m)) continue; - r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true); + r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true, UNIT_DEPENDENCY_PATH); if (r < 0) return r; if (UNIT(m)->fragment_path) { /* If we have fragment configuration, then make this dependency required */ - r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true); + r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true, UNIT_DEPENDENCY_PATH); if (r < 0) return r; } @@ -343,7 +341,7 @@ static int mount_add_mount_links(Mount *m) { /* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */ fstype = mount_get_fstype(m); if (streq(fstype, "tmpfs")) { - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true, UNIT_DEPENDENCY_IMPLICIT); if (r < 0) return r; } @@ -351,9 +349,10 @@ static int mount_add_mount_links(Mount *m) { return 0; } -static int mount_add_device_links(Mount *m) { - MountParameters *p; +static int mount_add_device_dependencies(Mount *m) { bool device_wants_mount = false; + UnitDependencyMask mask; + MountParameters *p; UnitDependency dep; int r; @@ -391,16 +390,19 @@ static int mount_add_device_links(Mount *m) { * automatically stopped when the device disappears suddenly. */ dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES; - r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, dep); + mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT; + + r = unit_add_node_dependency(UNIT(m), p->what, device_wants_mount, dep, mask); if (r < 0) return r; return 0; } -static int mount_add_quota_links(Mount *m) { - int r; +static int mount_add_quota_dependencies(Mount *m) { + UnitDependencyMask mask; MountParameters *p; + int r; assert(m); @@ -414,11 +416,13 @@ static int mount_add_quota_links(Mount *m) { if (!needs_quota(p)) return 0; - r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true); + mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT; + + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true, mask); if (r < 0) return r; - r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true, mask); if (r < 0) return r; @@ -457,9 +461,10 @@ static bool mount_is_extrinsic(Mount *m) { } static int mount_add_default_dependencies(Mount *m) { + UnitDependencyMask mask; + int r; MountParameters *p; const char *after; - int r; assert(m); @@ -476,6 +481,8 @@ static int mount_add_default_dependencies(Mount *m) { if (!p) return 0; + mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT; + if (mount_is_network(p)) { /* We order ourselves after network.target. This is * primarily useful at shutdown: services that take @@ -483,7 +490,7 @@ static int mount_add_default_dependencies(Mount *m) { * network.target, so that they are shut down only * after this mount unit is stopped. */ - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true, mask); if (r < 0) return r; @@ -494,7 +501,7 @@ static int mount_add_default_dependencies(Mount *m) { * whose purpose it is to delay this until the network * is "up". */ - r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true, mask); if (r < 0) return r; @@ -502,11 +509,11 @@ static int mount_add_default_dependencies(Mount *m) { } else after = SPECIAL_LOCAL_FS_PRE_TARGET; - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true); + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true, mask); if (r < 0) return r; - r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, mask); if (r < 0) return r; @@ -577,15 +584,15 @@ static int mount_add_extras(Mount *m) { return r; } - r = mount_add_device_links(m); + r = mount_add_device_dependencies(m); if (r < 0) return r; - r = mount_add_mount_links(m); + r = mount_add_mount_dependencies(m); if (r < 0) return r; - r = mount_add_quota_links(m); + r = mount_add_quota_dependencies(m); if (r < 0) return r; @@ -1453,11 +1460,11 @@ static int mount_setup_new_unit( int r; target = mount_is_network(p) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET; - r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true); + r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); if (r < 0) return r; - r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); if (r < 0) return r; } @@ -1515,7 +1522,7 @@ static int mount_setup_existing_unit( * in the dependency "Set*" objects who created a * dependency), we can only add deps, never lose them, * until the next full daemon-reload. */ - unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true); + unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT); load_extras = true; } diff --git a/src/core/path.c b/src/core/path.c index 44831f5803..6b0768505a 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -277,14 +277,14 @@ static void path_done(Unit *u) { path_free_specs(p); } -static int path_add_mount_links(Path *p) { +static int path_add_mount_dependencies(Path *p) { PathSpec *s; int r; assert(p); LIST_FOREACH(spec, s, p->specs) { - r = unit_require_mounts_for(UNIT(p), s->path); + r = unit_require_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } @@ -314,17 +314,33 @@ static int path_add_default_dependencies(Path *p) { if (!UNIT(p)->default_dependencies) return 0; - r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) { - r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; } - return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); + return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); +} + +static int path_add_trigger_dependencies(Path *p) { + Unit *x; + int r; + + assert(p); + + if (!hashmap_isempty(UNIT(p)->dependencies[UNIT_TRIGGERS])) + return 0; + + r = unit_load_related_unit(UNIT(p), ".service", &x); + if (r < 0) + return r; + + return unit_add_two_dependencies(UNIT(p), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT); } static int path_load(Unit *u) { @@ -340,19 +356,11 @@ static int path_load(Unit *u) { if (u->load_state == UNIT_LOADED) { - if (set_isempty(u->dependencies[UNIT_TRIGGERS])) { - Unit *x; + r = path_add_trigger_dependencies(p); + if (r < 0) + return r; - r = unit_load_related_unit(u, ".service", &x); - if (r < 0) - return r; - - r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true); - if (r < 0) - return r; - } - - r = path_add_mount_links(p); + r = path_add_mount_dependencies(p); if (r < 0) return r; diff --git a/src/core/scope.c b/src/core/scope.c index 7e789ed147..073b216ea2 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -124,7 +124,8 @@ static int scope_add_default_dependencies(Scope *s) { r = unit_add_two_dependencies_by_name( UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, - SPECIAL_SHUTDOWN_TARGET, NULL, true); + SPECIAL_SHUTDOWN_TARGET, NULL, true, + UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; diff --git a/src/core/service.c b/src/core/service.c index 78f315ad18..f42f1effb7 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -562,7 +562,7 @@ static int service_add_default_dependencies(Service *s) { * require it, so that we fail if we can't acquire * it. */ - r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; } else { @@ -570,7 +570,7 @@ static int service_add_default_dependencies(Service *s) { /* In the --user instance there's no sysinit.target, * in that case require basic.target instead. */ - r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; } @@ -578,12 +578,12 @@ static int service_add_default_dependencies(Service *s) { /* Second, if the rest of the base system is in the same * transaction, order us after it, but do not pull it in or * even require it. */ - r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; /* Third, add us in for normal shutdown. */ - return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); + return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); } static void service_fix_output(Service *s) { @@ -612,12 +612,12 @@ static int service_setup_bus_name(Service *s) { if (!s->bus_name) return 0; - r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true); + r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); /* We always want to be ordered against dbus.socket if both are in the transaction. */ - r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true); + r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); @@ -1103,11 +1103,12 @@ static int service_collect_fds(Service *s, rn_socket_fds = 1; } else { Iterator i; + void *v; Unit *u; /* Pass all our configured sockets for singleton services */ - SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) { + HASHMAP_FOREACH_KEY(v, u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) { _cleanup_free_ int *cfds = NULL; Socket *sock; int cn_fds; @@ -3617,7 +3618,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context return r; } - r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false); + r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false, UNIT_DEPENDENCY_IMPLICIT); if (r < 0) return r; diff --git a/src/core/slice.c b/src/core/slice.c index b15f751c82..e4faa1cdbd 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -97,7 +97,7 @@ static int slice_add_default_dependencies(Slice *s) { r = unit_add_two_dependencies_by_name( UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, - SPECIAL_SHUTDOWN_TARGET, NULL, true); + SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; diff --git a/src/core/socket.c b/src/core/socket.c index c0f4030302..0686de1d1b 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -250,7 +250,7 @@ int socket_instantiate_service(Socket *s) { unit_ref_set(&s->service, u); - return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false); + return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false, UNIT_DEPENDENCY_IMPLICIT); } static bool have_non_accept_socket(Socket *s) { @@ -273,7 +273,7 @@ static bool have_non_accept_socket(Socket *s) { return false; } -static int socket_add_mount_links(Socket *s) { +static int socket_add_mount_dependencies(Socket *s) { SocketPort *p; int r; @@ -290,7 +290,7 @@ static int socket_add_mount_links(Socket *s) { if (!path) continue; - r = unit_require_mounts_for(UNIT(s), path); + r = unit_require_mounts_for(UNIT(s), path, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } @@ -298,7 +298,7 @@ static int socket_add_mount_links(Socket *s) { return 0; } -static int socket_add_device_link(Socket *s) { +static int socket_add_device_dependencies(Socket *s) { char *t; assert(s); @@ -307,7 +307,7 @@ static int socket_add_device_link(Socket *s) { return 0; t = strjoina("/sys/subsystem/net/devices/", s->bind_to_device); - return unit_add_node_link(UNIT(s), t, false, UNIT_BINDS_TO); + return unit_add_node_dependency(UNIT(s), t, false, UNIT_BINDS_TO, UNIT_DEPENDENCY_FILE); } static int socket_add_default_dependencies(Socket *s) { @@ -317,17 +317,17 @@ static int socket_add_default_dependencies(Socket *s) { if (!UNIT(s)->default_dependencies) return 0; - r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) { - r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; } - return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); + return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); } _pure_ static bool socket_has_exec(Socket *s) { @@ -378,16 +378,16 @@ static int socket_add_extras(Socket *s) { unit_ref_set(&s->service, x); } - r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true); + r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true, UNIT_DEPENDENCY_IMPLICIT); if (r < 0) return r; } - r = socket_add_mount_links(s); + r = socket_add_mount_dependencies(s); if (r < 0) return r; - r = socket_add_device_link(s); + r = socket_add_device_dependencies(s); if (r < 0) return r; @@ -2261,13 +2261,14 @@ static void socket_enter_running(Socket *s, int cfd) { } if (cfd < 0) { - Iterator i; - Unit *other; bool pending = false; + Unit *other; + Iterator i; + void *v; /* If there's already a start pending don't bother to * do anything */ - SET_FOREACH(other, UNIT(s)->dependencies[UNIT_TRIGGERS], i) + HASHMAP_FOREACH_KEY(v, other, UNIT(s)->dependencies[UNIT_TRIGGERS], i) if (unit_active_or_pending(other)) { pending = true; break; diff --git a/src/core/swap.c b/src/core/swap.c index f475755572..42d91ba3f7 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -197,7 +197,7 @@ static int swap_arm_timer(Swap *s, usec_t usec) { return 0; } -static int swap_add_device_links(Swap *s) { +static int swap_add_device_dependencies(Swap *s) { assert(s); if (!s->what) @@ -207,12 +207,12 @@ static int swap_add_device_links(Swap *s) { return 0; if (is_device_path(s->what)) - return unit_add_node_link(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO); + return unit_add_node_dependency(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO, UNIT_DEPENDENCY_FILE); else /* File based swap devices need to be ordered after * systemd-remount-fs.service, since they might need a * writable file system. */ - return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true); + return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true, UNIT_DEPENDENCY_FILE); } static int swap_add_default_dependencies(Swap *s) { @@ -231,11 +231,11 @@ static int swap_add_default_dependencies(Swap *s) { /* swap units generated for the swap dev links are missing the * ordering dep against the swap target. */ - r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; - return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); + return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); } static int swap_verify(Swap *s) { @@ -323,11 +323,11 @@ static int swap_load(Unit *u) { return r; } - r = unit_require_mounts_for(UNIT(s), s->what); + r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT); if (r < 0) return r; - r = swap_add_device_links(s); + r = swap_add_device_dependencies(s); if (r < 0) return r; diff --git a/src/core/target.c b/src/core/target.c index 2a58dd394d..7083813459 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -56,8 +56,6 @@ static int target_add_default_dependencies(Target *t) { UNIT_PART_OF }; - Iterator i; - Unit *other; int r; unsigned k; @@ -66,23 +64,26 @@ static int target_add_default_dependencies(Target *t) { if (!UNIT(t)->default_dependencies) return 0; - /* Imply ordering for requirement dependencies on target - * units. Note that when the user created a contradicting - * ordering manually we won't add anything in here to make - * sure we don't create a loop. */ + /* Imply ordering for requirement dependencies on target units. Note that when the user created a contradicting + * ordering manually we won't add anything in here to make sure we don't create a loop. */ - for (k = 0; k < ELEMENTSOF(deps); k++) - SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i) { + for (k = 0; k < ELEMENTSOF(deps); k++) { + Unit *other; + Iterator i; + void *v; + + HASHMAP_FOREACH_KEY(v, other, UNIT(t)->dependencies[deps[k]], i) { r = unit_add_default_target_dependency(other, UNIT(t)); if (r < 0) return r; } + } if (unit_has_name(UNIT(t), SPECIAL_SHUTDOWN_TARGET)) return 0; /* Make sure targets are unloaded on shutdown */ - return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); + return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); } static int target_load(Unit *u) { diff --git a/src/core/timer.c b/src/core/timer.c index 9ea5f322d8..5f50576999 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -105,18 +105,18 @@ static int timer_add_default_dependencies(Timer *t) { if (!UNIT(t)->default_dependencies) return 0; - r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) { - r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; LIST_FOREACH(value, v, t->values) { if (v->base == TIMER_CALENDAR) { - r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true); + r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; break; @@ -124,7 +124,23 @@ static int timer_add_default_dependencies(Timer *t) { } } - return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); + return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); +} + +static int timer_add_trigger_dependencies(Timer *t) { + Unit *x; + int r; + + assert(t); + + if (!hashmap_isempty(UNIT(t)->dependencies[UNIT_TRIGGERS])) + return 0; + + r = unit_load_related_unit(UNIT(t), ".service", &x); + if (r < 0) + return r; + + return unit_add_two_dependencies(UNIT(t), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT); } static int timer_setup_persistent(Timer *t) { @@ -137,7 +153,7 @@ static int timer_setup_persistent(Timer *t) { if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) { - r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers"); + r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE); if (r < 0) return r; @@ -179,17 +195,9 @@ static int timer_load(Unit *u) { if (u->load_state == UNIT_LOADED) { - if (set_isempty(u->dependencies[UNIT_TRIGGERS])) { - Unit *x; - - r = unit_load_related_unit(u, ".service", &x); - if (r < 0) - return r; - - r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true); - if (r < 0) - return r; - } + r = timer_add_trigger_dependencies(t); + if (r < 0) + return r; r = timer_setup_persistent(t); if (r < 0) diff --git a/src/core/transaction.c b/src/core/transaction.c index 46c2fa452e..52014c634f 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -361,6 +361,7 @@ static char* merge_unit_ids(const char* unit_log_field, char **pairs) { static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) { Iterator i; Unit *u; + void *v; int r; assert(tr); @@ -452,7 +453,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi /* We assume that the dependencies are bidirectional, and * hence can ignore UNIT_AFTER */ - SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) { + HASHMAP_FOREACH_KEY(v, u, j->unit->dependencies[UNIT_BEFORE], i) { Job *o; /* Is there a job for this unit? */ @@ -860,14 +861,15 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen void transaction_add_propagate_reload_jobs(Transaction *tr, Unit *unit, Job *by, bool ignore_order, sd_bus_error *e) { Iterator i; - Unit *dep; JobType nt; + Unit *dep; + void *v; int r; assert(tr); assert(unit); - SET_FOREACH(dep, unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) { + HASHMAP_FOREACH_KEY(v, dep, unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) { nt = job_type_collapse(JOB_TRY_RELOAD, dep); if (nt == JOB_NOP) continue; @@ -892,11 +894,13 @@ int transaction_add_job_and_dependencies( bool ignore_requirements, bool ignore_order, sd_bus_error *e) { - Job *ret; + + bool is_new; Iterator i; Unit *dep; + Job *ret; + void *v; int r; - bool is_new; assert(tr); assert(type < _JOB_TYPE_MAX); @@ -969,7 +973,7 @@ int transaction_add_job_and_dependencies( /* Finally, recursively add in all dependencies. */ if (IN_SET(type, JOB_START, JOB_RESTART)) { - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { + HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_REQUIRES], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e); if (r < 0) { if (r != -EBADR) /* job type not applicable */ @@ -979,7 +983,7 @@ int transaction_add_job_and_dependencies( } } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) { + HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_BINDS_TO], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e); if (r < 0) { if (r != -EBADR) /* job type not applicable */ @@ -989,7 +993,7 @@ int transaction_add_job_and_dependencies( } } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { + HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_WANTS], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e); if (r < 0) { /* unit masked, job type not applicable and unit not found are not considered as errors. */ @@ -1001,7 +1005,7 @@ int transaction_add_job_and_dependencies( } } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) { + HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_REQUISITE], i) { r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e); if (r < 0) { if (r != -EBADR) /* job type not applicable */ @@ -1011,7 +1015,7 @@ int transaction_add_job_and_dependencies( } } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { + HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e); if (r < 0) { if (r != -EBADR) /* job type not applicable */ @@ -1021,7 +1025,7 @@ int transaction_add_job_and_dependencies( } } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) { + HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) { r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e); if (r < 0) { log_unit_warning(dep, @@ -1050,7 +1054,7 @@ int transaction_add_job_and_dependencies( ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type; for (j = 0; j < ELEMENTSOF(propagate_deps); j++) - SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) { + HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[propagate_deps[j]], i) { JobType nt; nt = job_type_collapse(ptype, dep); diff --git a/src/core/unit.c b/src/core/unit.c index f6b281b285..76902cca90 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -421,25 +421,25 @@ void unit_add_to_dbus_queue(Unit *u) { u->in_dbus_queue = true; } -static void bidi_set_free(Unit *u, Set *s) { - Iterator i; +static void bidi_set_free(Unit *u, Hashmap *h) { Unit *other; + Iterator i; + void *v; assert(u); - /* Frees the set and makes sure we are dropped from the - * inverse pointers */ + /* Frees the hashmap and makes sure we are dropped from the inverse pointers */ - SET_FOREACH(other, s, i) { + HASHMAP_FOREACH_KEY(v, other, h, i) { UnitDependency d; for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) - set_remove(other->dependencies[d], u); + hashmap_remove(other->dependencies[d], u); unit_add_to_gc_queue(other); } - set_free(s); + hashmap_free(h); } static void unit_remove_transient(Unit *u) { @@ -474,30 +474,37 @@ static void unit_remove_transient(Unit *u) { } static void unit_free_requires_mounts_for(Unit *u) { - char **j; + assert(u); - STRV_FOREACH(j, u->requires_mounts_for) { - char s[strlen(*j) + 1]; + for (;;) { + _cleanup_free_ char *path; - PATH_FOREACH_PREFIX_MORE(s, *j) { - char *y; - Set *x; + path = hashmap_steal_first_key(u->requires_mounts_for); + if (!path) + break; + else { + char s[strlen(path) + 1]; - x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y); - if (!x) - continue; + PATH_FOREACH_PREFIX_MORE(s, path) { + char *y; + Set *x; - set_remove(x, u); + x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y); + if (!x) + continue; - if (set_isempty(x)) { - hashmap_remove(u->manager->units_requiring_mounts_for, y); - free(y); - set_free(x); + (void) set_remove(x, u); + + if (set_isempty(x)) { + (void) hashmap_remove(u->manager->units_requiring_mounts_for, y); + free(y); + set_free(x); + } } } } - u->requires_mounts_for = strv_free(u->requires_mounts_for); + u->requires_mounts_for = hashmap_free(u->requires_mounts_for); } static void unit_done(Unit *u) { @@ -651,20 +658,33 @@ const char* unit_sub_state_to_string(Unit *u) { return UNIT_VTABLE(u)->sub_state_to_string(u); } -static int complete_move(Set **s, Set **other) { - int r; +static int set_complete_move(Set **s, Set **other) { + assert(s); + assert(other); + if (!other) + return 0; + + if (*s) + return set_move(*s, *other); + else { + *s = *other; + *other = NULL; + } + + return 0; +} + +static int hashmap_complete_move(Hashmap **s, Hashmap **other) { assert(s); assert(other); if (!*other) return 0; - if (*s) { - r = set_move(*s, *other); - if (r < 0) - return r; - } else { + if (*s) + return hashmap_move(*s, *other); + else { *s = *other; *other = NULL; } @@ -680,7 +700,7 @@ static int merge_names(Unit *u, Unit *other) { assert(u); assert(other); - r = complete_move(&u->names, &other->names); + r = set_complete_move(&u->names, &other->names); if (r < 0) return r; @@ -710,48 +730,73 @@ static int reserve_dependencies(Unit *u, Unit *other, UnitDependency d) { return 0; /* merge_dependencies() will skip a u-on-u dependency */ - n_reserve = set_size(other->dependencies[d]) - !!set_get(other->dependencies[d], u); + n_reserve = hashmap_size(other->dependencies[d]) - !!hashmap_get(other->dependencies[d], u); - return set_reserve(u->dependencies[d], n_reserve); + return hashmap_reserve(u->dependencies[d], n_reserve); } static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitDependency d) { Iterator i; Unit *back; + void *v; int r; + /* Merges all dependencies of type 'd' of the unit 'other' into the deps of the unit 'u' */ + assert(u); assert(other); assert(d < _UNIT_DEPENDENCY_MAX); - /* Fix backwards pointers */ - SET_FOREACH(back, other->dependencies[d], i) { + /* Fix backwards pointers. Let's iterate through all dependendent units of the other unit. */ + HASHMAP_FOREACH_KEY(v, back, other->dependencies[d], i) { UnitDependency k; + /* Let's now iterate through the dependencies of that dependencies of the other units, looking for + * pointers back, and let's fix them up, to instead point to 'u'. */ + for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++) { - /* Do not add dependencies between u and itself */ if (back == u) { - if (set_remove(back->dependencies[k], other)) + /* Do not add dependencies between u and itself. */ + if (hashmap_remove(back->dependencies[k], other)) maybe_warn_about_dependency(u, other_id, k); } else { - r = set_remove_and_put(back->dependencies[k], other, u); - if (r == -EEXIST) - set_remove(back->dependencies[k], other); - else - assert(r >= 0 || r == -ENOENT); + UnitDependencyInfo di_u, di_other, di_merged; + + /* Let's drop this dependency between "back" and "other", and let's create it between + * "back" and "u" instead. Let's merge the bit masks of the dependency we are moving, + * and any such dependency which might already exist */ + + di_other.data = hashmap_get(back->dependencies[k], other); + if (!di_other.data) + continue; /* dependency isn't set, let's try the next one */ + + di_u.data = hashmap_get(back->dependencies[k], u); + + di_merged = (UnitDependencyInfo) { + .origin_mask = di_u.origin_mask | di_other.origin_mask, + .destination_mask = di_u.destination_mask | di_other.destination_mask, + }; + + r = hashmap_remove_and_replace(back->dependencies[k], other, u, di_merged.data); + if (r < 0) + log_warning_errno(r, "Failed to remove/replace: back=%s other=%s u=%s: %m", back->id, other_id, u->id); + assert(r >= 0); + + /* assert_se(hashmap_remove_and_replace(back->dependencies[k], other, u, di_merged.data) >= 0); */ } } + } /* Also do not move dependencies on u to itself */ - back = set_remove(other->dependencies[d], u); + back = hashmap_remove(other->dependencies[d], u); if (back) maybe_warn_about_dependency(u, other_id, d); /* The move cannot fail. The caller must have performed a reservation. */ - assert_se(complete_move(&u->dependencies[d], &other->dependencies[d]) == 0); + assert_se(hashmap_complete_move(&u->dependencies[d], &other->dependencies[d]) == 0); - other->dependencies[d] = set_free(other->dependencies[d]); + other->dependencies[d] = hashmap_free(other->dependencies[d]); } int unit_merge(Unit *u, Unit *other) { @@ -876,19 +921,19 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { assert(c); if (c->working_directory) { - r = unit_require_mounts_for(u, c->working_directory); + r = unit_require_mounts_for(u, c->working_directory, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } if (c->root_directory) { - r = unit_require_mounts_for(u, c->root_directory); + r = unit_require_mounts_for(u, c->root_directory, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } if (c->root_image) { - r = unit_require_mounts_for(u, c->root_image); + r = unit_require_mounts_for(u, c->root_image, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } @@ -904,7 +949,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { if (!p) return -ENOMEM; - r = unit_require_mounts_for(u, p); + r = unit_require_mounts_for(u, p, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } @@ -917,12 +962,12 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { const char *p; FOREACH_STRING(p, "/tmp", "/var/tmp") { - r = unit_require_mounts_for(u, p); + r = unit_require_mounts_for(u, p, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } - r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_TMPFILES_SETUP_SERVICE, NULL, true); + r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_TMPFILES_SETUP_SERVICE, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) return r; } @@ -940,7 +985,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { /* If syslog or kernel logging is requested, make sure our own * logging daemon is run first. */ - r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true); + r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) return r; @@ -956,6 +1001,48 @@ const char *unit_description(Unit *u) { return strna(u->id); } +static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) { + const struct { + UnitDependencyMask mask; + const char *name; + } table[] = { + { UNIT_DEPENDENCY_FILE, "file" }, + { UNIT_DEPENDENCY_IMPLICIT, "implicit" }, + { UNIT_DEPENDENCY_DEFAULT, "default" }, + { UNIT_DEPENDENCY_UDEV, "udev" }, + { UNIT_DEPENDENCY_PATH, "path" }, + { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" }, + { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" }, + { UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" }, + }; + size_t i; + + assert(f); + assert(kind); + assert(space); + + for (i = 0; i < ELEMENTSOF(table); i++) { + + if (mask == 0) + break; + + if ((mask & table[i].mask) == table[i].mask) { + if (*space) + fputc(' ', f); + else + *space = true; + + fputs(kind, f); + fputs("-", f); + fputs(table[i].name, f); + + mask &= ~table[i].mask; + } + } + + assert(mask == 0); +} + void unit_dump(Unit *u, FILE *f, const char *prefix) { char *t, **j; UnitDependency d; @@ -1084,20 +1171,35 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(u->assert_result)); for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { + UnitDependencyInfo di; Unit *other; - SET_FOREACH(other, u->dependencies[d], i) - fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id); + HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d], i) { + bool space = false; + + fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id); + + print_unit_dependency_mask(f, "origin", di.origin_mask, &space); + print_unit_dependency_mask(f, "destination", di.destination_mask, &space); + + fputs(")\n", f); + } } - if (!strv_isempty(u->requires_mounts_for)) { - fprintf(f, - "%s\tRequiresMountsFor:", prefix); + if (!hashmap_isempty(u->requires_mounts_for)) { + UnitDependencyInfo di; + const char *path; - STRV_FOREACH(j, u->requires_mounts_for) - fprintf(f, " %s", *j); + HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for, i) { + bool space = false; - fputs("\n", f); + fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path); + + print_unit_dependency_mask(f, "origin", di.origin_mask, &space); + print_unit_dependency_mask(f, "destination", di.destination_mask, &space); + + fputs(")\n", f); + } } if (u->load_state == UNIT_LOADED) { @@ -1198,10 +1300,10 @@ int unit_add_default_target_dependency(Unit *u, Unit *target) { return 0; /* Don't create loops */ - if (set_get(target->dependencies[UNIT_BEFORE], u)) + if (hashmap_get(target->dependencies[UNIT_BEFORE], u)) return 0; - return unit_add_dependency(target, UNIT_AFTER, u, true); + return unit_add_dependency(target, UNIT_AFTER, u, true, UNIT_DEPENDENCY_DEFAULT); } static int unit_add_target_dependencies(Unit *u) { @@ -1213,48 +1315,59 @@ static int unit_add_target_dependencies(Unit *u) { UNIT_BOUND_BY }; - Unit *target; - Iterator i; unsigned k; int r = 0; assert(u); - for (k = 0; k < ELEMENTSOF(deps); k++) - SET_FOREACH(target, u->dependencies[deps[k]], i) { + for (k = 0; k < ELEMENTSOF(deps); k++) { + Unit *target; + Iterator i; + void *v; + + HASHMAP_FOREACH_KEY(v, target, u->dependencies[deps[k]], i) { r = unit_add_default_target_dependency(u, target); if (r < 0) return r; } + } return r; } static int unit_add_slice_dependencies(Unit *u) { + UnitDependencyMask mask; assert(u); if (!UNIT_HAS_CGROUP_CONTEXT(u)) return 0; + /* Slice units are implicitly ordered against their parent slices (as this relationship is encoded in the + name), while all other units are ordered based on configuration (as in their case Slice= configures the + relationship). */ + mask = u->type == UNIT_SLICE ? UNIT_DEPENDENCY_IMPLICIT : UNIT_DEPENDENCY_FILE; + if (UNIT_ISSET(u->slice)) - return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true); + return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true, mask); if (unit_has_name(u, SPECIAL_ROOT_SLICE)) return 0; - return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true); + return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true, mask); } static int unit_add_mount_dependencies(Unit *u) { - char **i; + UnitDependencyInfo di; + const char *path; + Iterator i; int r; assert(u); - STRV_FOREACH(i, u->requires_mounts_for) { - char prefix[strlen(*i) + 1]; + HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for, i) { + char prefix[strlen(path) + 1]; - PATH_FOREACH_PREFIX_MORE(prefix, *i) { + PATH_FOREACH_PREFIX_MORE(prefix, path) { _cleanup_free_ char *p = NULL; Unit *m; @@ -1278,12 +1391,12 @@ static int unit_add_mount_dependencies(Unit *u) { if (m->load_state != UNIT_LOADED) continue; - r = unit_add_dependency(u, UNIT_AFTER, m, true); + r = unit_add_dependency(u, UNIT_AFTER, m, true, di.origin_mask); if (r < 0) return r; if (m->fragment_path) { - r = unit_add_dependency(u, UNIT_REQUIRES, m, true); + r = unit_add_dependency(u, UNIT_REQUIRES, m, true, di.origin_mask); if (r < 0) return r; } @@ -1369,7 +1482,7 @@ int unit_load(Unit *u) { if (r < 0) goto fail; - if (u->on_failure_job_mode == JOB_ISOLATE && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) { + if (u->on_failure_job_mode == JOB_ISOLATE && hashmap_size(u->dependencies[UNIT_ON_FAILURE]) > 1) { log_unit_error(u, "More than one OnFailure= dependencies specified but OnFailureJobMode=isolate set. Refusing."); r = -EINVAL; goto fail; @@ -1584,6 +1697,7 @@ bool unit_shall_confirm_spawn(Unit *u) { static bool unit_verify_deps(Unit *u) { Unit *other; Iterator j; + void *v; assert(u); @@ -1592,9 +1706,9 @@ static bool unit_verify_deps(Unit *u) { * processing, but do not have any effect afterwards. We don't check BindsTo= dependencies that are not used in * conjunction with After= as for them any such check would make things entirely racy. */ - SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], j) { + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], j) { - if (!set_contains(u->dependencies[UNIT_AFTER], other)) + if (!hashmap_contains(u->dependencies[UNIT_AFTER], other)) continue; if (!UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(other))) { @@ -1797,7 +1911,7 @@ bool unit_can_reload(Unit *u) { if (UNIT_VTABLE(u)->can_reload) return UNIT_VTABLE(u)->can_reload(u); - if (!set_isempty(u->dependencies[UNIT_PROPAGATES_RELOAD_TO])) + if (!hashmap_isempty(u->dependencies[UNIT_PROPAGATES_RELOAD_TO])) return true; return UNIT_VTABLE(u)->reload; @@ -1814,8 +1928,6 @@ static void unit_check_unneeded(Unit *u) { UNIT_BOUND_BY, }; - Unit *other; - Iterator i; unsigned j; int r; @@ -1830,10 +1942,15 @@ static void unit_check_unneeded(Unit *u) { if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) return; - for (j = 0; j < ELEMENTSOF(needed_dependencies); j++) - SET_FOREACH(other, u->dependencies[needed_dependencies[j]], i) + for (j = 0; j < ELEMENTSOF(needed_dependencies); j++) { + Unit *other; + Iterator i; + void *v; + + HASHMAP_FOREACH_KEY(v, other, u->dependencies[needed_dependencies[j]], i) if (unit_active_or_pending(other)) return; + } /* If stopping a unit fails continuously we might enter a stop * loop here, hence stop acting on the service being @@ -1856,6 +1973,7 @@ static void unit_check_binds_to(Unit *u) { bool stop = false; Unit *other; Iterator i; + void *v; int r; assert(u); @@ -1866,7 +1984,7 @@ static void unit_check_binds_to(Unit *u) { if (unit_active_state(u) != UNIT_ACTIVE) return; - SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) { + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i) { if (other->job) continue; @@ -1904,65 +2022,68 @@ static void unit_check_binds_to(Unit *u) { static void retroactively_start_dependencies(Unit *u) { Iterator i; Unit *other; + void *v; assert(u); assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))); - SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i) - if (!set_get(u->dependencies[UNIT_AFTER], other) && + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i) + if (!hashmap_get(u->dependencies[UNIT_AFTER], other) && !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL); - SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) - if (!set_get(u->dependencies[UNIT_AFTER], other) && + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i) + if (!hashmap_get(u->dependencies[UNIT_AFTER], other) && !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL); - SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) - if (!set_get(u->dependencies[UNIT_AFTER], other) && + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i) + if (!hashmap_get(u->dependencies[UNIT_AFTER], other) && !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL); - SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTS], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL); - SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTED_BY], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL); } static void retroactively_stop_dependencies(Unit *u) { - Iterator i; Unit *other; + Iterator i; + void *v; assert(u); assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))); /* Pull down units which are bound to us recursively if enabled */ - SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BOUND_BY], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL); } static void check_unneeded_dependencies(Unit *u) { - Iterator i; Unit *other; + Iterator i; + void *v; assert(u); assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))); /* Garbage collect services that might not be needed anymore, if enabled */ - SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); - SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); - SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUISITE], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); - SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); } @@ -1970,15 +2091,16 @@ static void check_unneeded_dependencies(Unit *u) { void unit_start_on_failure(Unit *u) { Unit *other; Iterator i; + void *v; assert(u); - if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0) + if (hashmap_size(u->dependencies[UNIT_ON_FAILURE]) <= 0) return; log_unit_info(u, "Triggering OnFailure= dependencies."); - SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) { + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_ON_FAILURE], i) { int r; r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, NULL); @@ -1990,10 +2112,11 @@ void unit_start_on_failure(Unit *u) { void unit_trigger_notify(Unit *u) { Unit *other; Iterator i; + void *v; assert(u); - SET_FOREACH(other, u->dependencies[UNIT_TRIGGERED_BY], i) + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_TRIGGERED_BY], i) if (UNIT_VTABLE(other)->trigger_notify) UNIT_VTABLE(other)->trigger_notify(other, u); } @@ -2465,7 +2588,59 @@ static void maybe_warn_about_dependency(Unit *u, const char *other, UnitDependen log_unit_warning(u, "Dependency %s=%s dropped, merged into %s", unit_dependency_to_string(dependency), strna(other), u->id); } -int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) { +static int unit_add_dependency_hashmap( + Hashmap **h, + Unit *other, + UnitDependencyMask origin_mask, + UnitDependencyMask destination_mask) { + + UnitDependencyInfo info; + int r; + + assert(h); + assert(other); + assert(origin_mask < _UNIT_DEPENDENCY_MASK_FULL); + assert(destination_mask < _UNIT_DEPENDENCY_MASK_FULL); + assert(origin_mask > 0 || destination_mask > 0); + + r = hashmap_ensure_allocated(h, NULL); + if (r < 0) + return r; + + assert_cc(sizeof(void*) == sizeof(info)); + + info.data = hashmap_get(*h, other); + if (info.data) { + /* Entry already exists. Add in our mask. */ + + if ((info.origin_mask & origin_mask) == info.origin_mask && + (info.destination_mask & destination_mask) == info.destination_mask) + return 0; /* NOP */ + + info.origin_mask |= origin_mask; + info.destination_mask |= destination_mask; + + r = hashmap_update(*h, other, info.data); + } else { + info = (UnitDependencyInfo) { + .origin_mask = origin_mask, + .destination_mask = destination_mask, + }; + + r = hashmap_put(*h, other, info.data); + } + if (r < 0) + return r; + + return 1; +} + +int unit_add_dependency( + Unit *u, + UnitDependency d, + Unit *other, + bool add_reference, + UnitDependencyMask mask) { static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUIRES] = UNIT_REQUIRED_BY, @@ -2491,8 +2666,8 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO, [UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF, }; - int r, q = 0, v = 0, w = 0; - Unit *orig_u = u, *orig_other = other; + Unit *original_u = u, *original_other = other; + int r; assert(u); assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX); @@ -2504,85 +2679,50 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen /* We won't allow dependencies on ourselves. We will not * consider them an error however. */ if (u == other) { - maybe_warn_about_dependency(orig_u, orig_other->id, d); + maybe_warn_about_dependency(original_u, original_other->id, d); return 0; } - if (d == UNIT_BEFORE && other->type == UNIT_DEVICE) { + if ((d == UNIT_BEFORE && other->type == UNIT_DEVICE) || + (d == UNIT_AFTER && u->type == UNIT_DEVICE)) { log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id); return 0; } - r = set_ensure_allocated(&u->dependencies[d], NULL); + r = unit_add_dependency_hashmap(u->dependencies + d, other, mask, 0); if (r < 0) return r; - if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) { - r = set_ensure_allocated(&other->dependencies[inverse_table[d]], NULL); - if (r < 0) - return r; - } - - if (add_reference) { - r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], NULL); - if (r < 0) - return r; - - r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], NULL); - if (r < 0) - return r; - } - - q = set_put(u->dependencies[d], other); - if (q < 0) - return q; - if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID && inverse_table[d] != d) { - v = set_put(other->dependencies[inverse_table[d]], u); - if (v < 0) { - r = v; - goto fail; - } + r = unit_add_dependency_hashmap(other->dependencies + inverse_table[d], u, 0, mask); + if (r < 0) + return r; } if (add_reference) { - w = set_put(u->dependencies[UNIT_REFERENCES], other); - if (w < 0) { - r = w; - goto fail; - } - - r = set_put(other->dependencies[UNIT_REFERENCED_BY], u); + r = unit_add_dependency_hashmap(u->dependencies + UNIT_REFERENCES, other, mask, 0); if (r < 0) - goto fail; + return r; + + r = unit_add_dependency_hashmap(other->dependencies + UNIT_REFERENCED_BY, u, 0, mask); + if (r < 0) + return r; } unit_add_to_dbus_queue(u); return 0; - -fail: - if (q > 0) - set_remove(u->dependencies[d], other); - - if (v > 0) - set_remove(other->dependencies[inverse_table[d]], u); - - if (w > 0) - set_remove(u->dependencies[UNIT_REFERENCES], other); - - return r; } -int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference) { +int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference, UnitDependencyMask mask) { int r; assert(u); - r = unit_add_dependency(u, d, other, add_reference); + r = unit_add_dependency(u, d, other, add_reference, mask); if (r < 0) return r; - return unit_add_dependency(u, e, other, add_reference); + return unit_add_dependency(u, e, other, add_reference, mask); } static int resolve_template(Unit *u, const char *name, const char*path, char **buf, const char **ret) { @@ -2620,7 +2760,7 @@ static int resolve_template(Unit *u, const char *name, const char*path, char **b return 0; } -int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { +int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference, UnitDependencyMask mask) { _cleanup_free_ char *buf = NULL; Unit *other; int r; @@ -2636,10 +2776,10 @@ int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, con if (r < 0) return r; - return unit_add_dependency(u, d, other, add_reference); + return unit_add_dependency(u, d, other, add_reference, mask); } -int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) { +int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference, UnitDependencyMask mask) { _cleanup_free_ char *buf = NULL; Unit *other; int r; @@ -2655,7 +2795,7 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency if (r < 0) return r; - return unit_add_two_dependencies(u, d, e, other, add_reference); + return unit_add_two_dependencies(u, d, e, other, add_reference, mask); } int set_unit_path(const char *p) { @@ -3365,7 +3505,7 @@ void unit_deserialize_skip(FILE *f) { } -int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) { +int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency dep, UnitDependencyMask mask) { Unit *device; _cleanup_free_ char *e = NULL; int r; @@ -3397,12 +3537,12 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep r = unit_add_two_dependencies(u, UNIT_AFTER, MANAGER_IS_SYSTEM(u->manager) ? dep : UNIT_WANTS, - device, true); + device, true, mask); if (r < 0) return r; if (wants) { - r = unit_add_dependency(device, UNIT_WANTS, u, false); + r = unit_add_dependency(device, UNIT_WANTS, u, false, mask); if (r < 0) return r; } @@ -4222,23 +4362,26 @@ int unit_kill_context( return wait_for_exit; } -int unit_require_mounts_for(Unit *u, const char *path) { +int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) { char prefix[strlen(path) + 1], *p; + UnitDependencyInfo di; int r; assert(u); assert(path); - /* Registers a unit for requiring a certain path and all its - * prefixes. We keep a simple array of these paths in the - * unit, since its usually short. However, we build a prefix - * table for all possible prefixes so that new appearing mount - * units can easily determine which units to make themselves a - * dependency of. */ + /* Registers a unit for requiring a certain path and all its prefixes. We keep a hashtable of these paths in + * the unit (from the path to the UnitDependencyInfo structure indicating how to the dependency came to + * be). However, we build a prefix table for all possible prefixes so that new appearing mount units can easily + * determine which units to make themselves a dependency of. */ if (!path_is_absolute(path)) return -EINVAL; + r = hashmap_ensure_allocated(&u->requires_mounts_for, &string_hash_ops); + if (r < 0) + return r; + p = strdup(path); if (!p) return -ENOMEM; @@ -4250,14 +4393,20 @@ int unit_require_mounts_for(Unit *u, const char *path) { return -EPERM; } - if (strv_contains(u->requires_mounts_for, p)) { + if (hashmap_contains(u->requires_mounts_for, p)) { free(p); return 0; } - r = strv_consume(&u->requires_mounts_for, p); - if (r < 0) + di = (UnitDependencyInfo) { + .origin_mask = mask + }; + + r = hashmap_put(u->requires_mounts_for, p, di.data); + if (r < 0) { + free(p); return r; + } PATH_FOREACH_PREFIX_MORE(prefix, p) { Set *x; @@ -4299,8 +4448,9 @@ int unit_require_mounts_for(Unit *u, const char *path) { int unit_setup_exec_runtime(Unit *u) { ExecRuntime **rt; size_t offset; - Iterator i; Unit *other; + Iterator i; + void *v; offset = UNIT_VTABLE(u)->exec_runtime_offset; assert(offset > 0); @@ -4311,7 +4461,7 @@ int unit_setup_exec_runtime(Unit *u) { return 0; /* Try to get it from somebody else */ - SET_FOREACH(other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) { + HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) { *rt = unit_get_exec_runtime(other); if (*rt) { diff --git a/src/core/unit.h b/src/core/unit.h index 8c5c92ecd9..5b9dce3d0b 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -61,6 +61,53 @@ static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) { return IN_SET(t, UNIT_INACTIVE, UNIT_FAILED); } +/* Stores the 'reason' a dependency was created as a bit mask, i.e. due to which configuration source it came to be. We + * use this so that we can selectively flush out parts of dependencies again. Note that the same dependency might be + * created as a result of multiple "reasons", hence the bitmask. */ +typedef enum UnitDependencyMask { + /* Configured directly by the unit file, .wants/.requries symlink or drop-in, or as an immediate result of a + * non-dependency option configured that way. */ + UNIT_DEPENDENCY_FILE = 1 << 0, + + /* As unconditional implicit dependency (not affected by unit configuration — except by the unit name and + * type) */ + UNIT_DEPENDENCY_IMPLICIT = 1 << 1, + + /* A dependency effected by DefaultDependencies=yes. Note that dependencies marked this way are conceptually + * just a subset of UNIT_DEPENDENCY_FILE, as DefaultDependencies= is itself a unit file setting that can only + * be set in unit files. We make this two separate bits only to help debugging how dependencies came to be. */ + UNIT_DEPENDENCY_DEFAULT = 1 << 2, + + /* A dependency created from udev rules */ + UNIT_DEPENDENCY_UDEV = 1 << 3, + + /* A dependency created because of some unit's RequiresMountsFor= setting */ + UNIT_DEPENDENCY_PATH = 1 << 4, + + /* A dependency created because of data read from /proc/self/mountinfo and no other configuration source */ + UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT = 1 << 5, + + /* A dependency created because of data read from /proc/self/mountinfo, but conditionalized by + * DefaultDependencies= and thus also involving configuration from UNIT_DEPENDENCY_FILE sources */ + UNIT_DEPENDENCY_MOUNTINFO_DEFAULT = 1 << 6, + + /* A dependency created because of data read from /proc/swaps and no other configuration source */ + UNIT_DEPENDENCY_PROC_SWAP = 1 << 7, + + _UNIT_DEPENDENCY_MASK_FULL = (1 << 8) - 1, +} UnitDependencyMask; + +/* The Unit's dependencies[] hashmaps use this structure as value. It has the same size as a void pointer, and thus can + * be stored directly as hashmap value, without any indirection. Note that this stores two masks, as both the origin + * and the destination of a dependency might have created it. */ +typedef union UnitDependencyInfo { + void *data; + struct { + UnitDependencyMask origin_mask:16; + UnitDependencyMask destination_mask:16; + } _packed_; +} UnitDependencyInfo; + #include "job.h" struct UnitRef { @@ -89,9 +136,13 @@ struct Unit { char *instance; Set *names; - Set *dependencies[_UNIT_DEPENDENCY_MAX]; - char **requires_mounts_for; + /* For each dependency type we maintain a Hashmap whose key is the Unit* object, and the value encodes why the + * dependency exists, using the UnitDependencyInfo type */ + Hashmap *dependencies[_UNIT_DEPENDENCY_MAX]; + + /* Similar, for RequiresMountsFor= path dependencies. The key is the path, the value the UnitDependencyInfo type */ + Hashmap *requires_mounts_for; char *description; char **documentation; @@ -492,7 +543,7 @@ extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX]; #define UNIT_HAS_CGROUP_CONTEXT(u) (UNIT_VTABLE(u)->cgroup_context_offset > 0) #define UNIT_HAS_KILL_CONTEXT(u) (UNIT_VTABLE(u)->kill_context_offset > 0) -#define UNIT_TRIGGER(u) ((Unit*) set_first((u)->dependencies[UNIT_TRIGGERS])) +#define UNIT_TRIGGER(u) ((Unit*) hashmap_first_key((u)->dependencies[UNIT_TRIGGERS])) DEFINE_CAST(SERVICE, Service); DEFINE_CAST(SOCKET, Socket); @@ -512,11 +563,11 @@ void unit_free(Unit *u); int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret); int unit_add_name(Unit *u, const char *name); -int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference); -int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference); +int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference, UnitDependencyMask mask); +int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference, UnitDependencyMask mask); -int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); -int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); +int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference, UnitDependencyMask mask); +int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference, UnitDependencyMask mask); int unit_add_exec_dependencies(Unit *u, ExecContext *c); @@ -596,7 +647,7 @@ int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *v int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd); void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5); -int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d); +int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency d, UnitDependencyMask mask); int unit_coldplug(Unit *u); @@ -651,7 +702,7 @@ int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, int unit_make_transient(Unit *u); -int unit_require_mounts_for(Unit *u, const char *path); +int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask); bool unit_type_supported(UnitType t);