diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | man/systemd-detect-virt.xml | 6 | ||||
-rw-r--r-- | man/systemd.unit.xml | 129 | ||||
-rw-r--r-- | src/basic/virt.c | 22 | ||||
-rw-r--r-- | src/core/job.c | 2 | ||||
-rw-r--r-- | src/core/unit.c | 33 | ||||
-rw-r--r-- | src/libsystemd-network/sd-ipv4acd.c | 2 | ||||
-rw-r--r-- | src/nss-resolve/nss-resolve.c | 14 | ||||
-rw-r--r-- | src/test/test-ipcrm.c | 2 |
9 files changed, 120 insertions, 94 deletions
@@ -35,6 +35,10 @@ CHANGES WITH 233 in spe names of remote hosts and to reply to mDNS's A and AAAA requests from the hosts. + * When units are about to be started an additional check is now done to + ensure that all dependencies of type BindsTo= (when used in + combination with After=) have been started. + CHANGES WITH 232: * The new RemoveIPC= option can be used to remove IPC objects owned by diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml index dc10b4dd43..72ea35892f 100644 --- a/man/systemd-detect-virt.xml +++ b/man/systemd-detect-virt.xml @@ -96,7 +96,8 @@ <row> <entry><varname>kvm</varname></entry> - <entry>Linux KVM kernel virtual machine, from within QEMU</entry> + <entry>Linux KVM kernel virtual machine, with whatever software, except + Oracle Virtualbox</entry> </row> <row> @@ -116,7 +117,8 @@ <row> <entry><varname>oracle</varname></entry> - <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems)</entry> + <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems), + for legacy and KVM hypervisor</entry> </row> <row> diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 417840e6c2..2208b6a287 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -436,32 +436,30 @@ <varlistentry> <term><varname>Requires=</varname></term> - <listitem><para>Configures requirement dependencies on other - units. If this unit gets activated, the units listed here will - be activated as well. If one of the other units gets - deactivated or its activation fails, this unit will be - deactivated. This option may be specified more than once or - multiple space-separated units may be specified in one option - in which case requirement dependencies for all listed names - will be created. Note that requirement dependencies do not - influence the order in which services are started or stopped. - This has to be configured independently with the - <varname>After=</varname> or <varname>Before=</varname> - options. If a unit <filename>foo.service</filename> requires a - unit <filename>bar.service</filename> as configured with - <varname>Requires=</varname> and no ordering is configured - with <varname>After=</varname> or <varname>Before=</varname>, - then both units will be started simultaneously and without any - delay between them if <filename>foo.service</filename> is - activated. Often, it is a better choice to use - <varname>Wants=</varname> instead of - <varname>Requires=</varname> in order to achieve a system that - is more robust when dealing with failing services.</para> - - <para>Note that dependencies of this type may also be - configured outside of the unit configuration file by adding a - symlink to a <filename>.requires/</filename> directory - accompanying the unit file. For details, see + <listitem><para>Configures requirement dependencies on other units. If this unit gets activated, the units + listed here will be activated as well. If one of the other units gets deactivated or its activation fails, this + unit will be deactivated. This option may be specified more than once or multiple space-separated units may be + specified in one option in which case requirement dependencies for all listed names will be created. Note that + requirement dependencies do not influence the order in which services are started or stopped. This has to be + configured independently with the <varname>After=</varname> or <varname>Before=</varname> options. If a unit + <filename>foo.service</filename> requires a unit <filename>bar.service</filename> as configured with + <varname>Requires=</varname> and no ordering is configured with <varname>After=</varname> or + <varname>Before=</varname>, then both units will be started simultaneously and without any delay between them + if <filename>foo.service</filename> is activated. Often, it is a better choice to use <varname>Wants=</varname> + instead of <varname>Requires=</varname> in order to achieve a system that is more robust when dealing with + failing services.</para> + + <para>Note that this dependency type does not imply that the other unit always has to be in active state when + this unit is running. Specifically: failing condition checks (such as <varname>ConditionPathExists=</varname>, + <varname>ConditionPathExists=</varname>, … — see below) do not cause the start job of a unit with a + <varname>Requires=</varname> dependency on it to fail. Also, some unit types may deactivate on their own (for + example, a service process may decide to exit cleanly, or a device may be unplugged by the user), which is not + propagated to units having a <varname>Requires=</varname> dependency. Use the <varname>BindsTo=</varname> + dependency type together with <varname>After=</varname> to ensure that a unit may never be in active state + without a specific other unit also in active state (see below).</para> + + <para>Note that dependencies of this type may also be configured outside of the unit configuration file by + adding a symlink to a <filename>.requires/</filename> directory accompanying the unit file. For details, see above.</para></listitem> </varlistentry> @@ -495,14 +493,21 @@ <varlistentry> <term><varname>BindsTo=</varname></term> - <listitem><para>Configures requirement dependencies, very - similar in style to <varname>Requires=</varname>, however in - addition to this behavior, it also declares that this unit is - stopped when any of the units listed suddenly disappears. - Units can suddenly, unexpectedly disappear if a service - terminates on its own choice, a device is unplugged or a mount - point unmounted without involvement of - systemd.</para></listitem> + <listitem><para>Configures requirement dependencies, very similar in style to + <varname>Requires=</varname>. However, this dependency type is stronger: in addition to the effect of + <varname>Requires=</varname> it declares that if the unit bound to is stopped, this unit will be stopped + too. This means a unit bound to another unit that suddenly enters inactive state will be stopped too. + Units can suddenly, unexpectedly enter inactive state for different reasons: the main process of a service unit + might terminate on its own choice, the backing device of a device unit might be unplugged or the mount point of + a mount unit might be unmounted without involvement of the system and service manager.</para> + + <para>When used in conjunction with <varname>After=</varname> on the same unit the behaviour of + <varname>BindsTo=</varname> is even stronger. In this case, the unit bound to strictly has to be in active + state for this unit to also be in active state. This not only means a unit bound to another unit that suddenly + enters inactive state, but also one that is bound to another unit that gets skipped due to a failed condition + check (such as <varname>ConditionPathExists=</varname>, <varname>ConditionPathIsSymbolicLink=</varname>, … — + see below) will be stopped, should it be running. Hence, in many cases it is best to combine + <varname>BindsTo=</varname> with <varname>After=</varname>.</para></listitem> </varlistentry> <varlistentry> @@ -541,42 +546,26 @@ <term><varname>Before=</varname></term> <term><varname>After=</varname></term> - <listitem><para>A space-separated list of unit names. - Configures ordering dependencies between units. If a unit - <filename>foo.service</filename> contains a setting - <option>Before=bar.service</option> and both units are being - started, <filename>bar.service</filename>'s start-up is - delayed until <filename>foo.service</filename> is started up. - Note that this setting is independent of and orthogonal to the - requirement dependencies as configured by - <varname>Requires=</varname>. It is a common pattern to - include a unit name in both the <varname>After=</varname> and - <varname>Requires=</varname> option, in which case the unit - listed will be started before the unit that is configured with - these options. This option may be specified more than once, in - which case ordering dependencies for all listed names are - created. <varname>After=</varname> is the inverse of - <varname>Before=</varname>, i.e. while - <varname>After=</varname> ensures that the configured unit is - started after the listed unit finished starting up, - <varname>Before=</varname> ensures the opposite, i.e. that the - configured unit is fully started up before the listed unit is - started. Note that when two units with an ordering dependency - between them are shut down, the inverse of the start-up order - is applied. i.e. if a unit is configured with - <varname>After=</varname> on another unit, the former is - stopped before the latter if both are shut down. Given two units - with any ordering dependency between them, if one unit is shut - down and the other is started up, the shutdown is ordered - before the start-up. It doesn't matter if the ordering - dependency is <varname>After=</varname> or - <varname>Before=</varname>. It also doesn't matter which of the - two is shut down, as long as one is shut down and the other is - started up. The shutdown is ordered before the start-up in all - cases. If two units have no ordering dependencies between them, - they are shut down or started up simultaneously, and no ordering - takes place. - </para></listitem> + <listitem><para>A space-separated list of unit names. Configures ordering dependencies between units. If a + unit <filename>foo.service</filename> contains a setting <option>Before=bar.service</option> and both units are + being started, <filename>bar.service</filename>'s start-up is delayed until <filename>foo.service</filename> is + started up. Note that this setting is independent of and orthogonal to the requirement dependencies as + configured by <varname>Requires=</varname>, <varname>Wants=</varname> or <varname>BindsTo=</varname>. It is a + common pattern to include a unit name in both the <varname>After=</varname> and <varname>Requires=</varname> + option, in which case the unit listed will be started before the unit that is configured with these + options. This option may be specified more than once, in which case ordering dependencies for all listed names + are created. <varname>After=</varname> is the inverse of <varname>Before=</varname>, i.e. while + <varname>After=</varname> ensures that the configured unit is started after the listed unit finished starting + up, <varname>Before=</varname> ensures the opposite, i.e. that the configured unit is fully started up before + the listed unit is started. Note that when two units with an ordering dependency between them are shut down, + the inverse of the start-up order is applied. i.e. if a unit is configured with <varname>After=</varname> on + another unit, the former is stopped before the latter if both are shut down. Given two units with any ordering + dependency between them, if one unit is shut down and the other is started up, the shutdown is ordered before + the start-up. It doesn't matter if the ordering dependency is <varname>After=</varname> or + <varname>Before=</varname>, in this case. It also doesn't matter which of the two is shut down, as long as one + is shut down and the other is started up. The shutdown is ordered before the start-up in all cases. If two + units have no ordering dependencies between them, they are shut down or started up simultaneously, and no + ordering takes place. </para></listitem> </varlistentry> <varlistentry> diff --git a/src/basic/virt.c b/src/basic/virt.c index 0fbbdea602..830dc655e3 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -316,31 +316,29 @@ static int detect_vm_zvm(void) { /* Returns a short identifier for the various VM implementations */ int detect_vm(void) { static thread_local int cached_found = _VIRTUALIZATION_INVALID; - int r, cpuid; + int r, dmi; if (cached_found >= 0) return cached_found; /* We have to use the correct order here: * - * -> First try to detect qemu/kvm and return 'kvm'. - * -> Some virtualization technologies do use KVM hypervisor but are - * expected to be detected as something else. Virtualbox since - * version 5.0 is an example. So detect DMI next. - * -> Get infos from CPUID third. */ + * -> First try to detect Oracle Virtualbox, even if it uses KVM. + * -> Second try to detect from cpuid, this will report KVM for + * whatever software is used even if info in dmi is overwritten. + * -> Third try to detect from dmi. */ - cpuid = detect_vm_cpuid(); - r = detect_vm_dmi(); - - if (r == VIRTUALIZATION_QEMU && cpuid == VIRTUALIZATION_KVM) - return cpuid; + dmi = detect_vm_dmi(); + if (dmi == VIRTUALIZATION_ORACLE) + return dmi; + r = detect_vm_cpuid(); if (r < 0) return r; if (r != VIRTUALIZATION_NONE) goto finish; - r = cpuid; + r = dmi; if (r < 0) return r; if (r != VIRTUALIZATION_NONE) diff --git a/src/core/job.c b/src/core/job.c index d5943d3713..e2349830a8 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -627,6 +627,8 @@ int job_run_and_invalidate(Job *j) { r = job_finish_and_invalidate(j, JOB_ASSERT, true, false); else if (r == -EOPNOTSUPP) r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false); + else if (r == -ENOLINK) + r = job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false); else if (r == -EAGAIN) job_set_state(j, JOB_WAITING); else if (r < 0) diff --git a/src/core/unit.c b/src/core/unit.c index 9221412c48..bb05d2abfb 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1526,6 +1526,7 @@ int unit_start_limit_test(Unit *u) { } bool unit_shall_confirm_spawn(Unit *u) { + assert(u); if (manager_is_confirm_spawn_disabled(u->manager)) return false; @@ -1536,6 +1537,31 @@ bool unit_shall_confirm_spawn(Unit *u) { return !unit_get_exec_context(u)->same_pgrp; } +static bool unit_verify_deps(Unit *u) { + Unit *other; + Iterator j; + + assert(u); + + /* Checks whether all BindsTo= dependencies of this unit are fulfilled — if they are also combined with + * After=. We do not check Requires= or Requisite= here as they only should have an effect on the job + * 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) { + + if (!set_contains(u->dependencies[UNIT_AFTER], other)) + continue; + + if (!UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(other))) { + log_unit_notice(u, "Bound to unit %s, but unit isn't active.", other->id); + return false; + } + } + + return true; +} + /* Errors: * -EBADR: This unit type does not support starting. * -EALREADY: Unit is already started. @@ -1544,6 +1570,7 @@ bool unit_shall_confirm_spawn(Unit *u) { * -EPROTO: Assert failed * -EINVAL: Unit not loaded * -EOPNOTSUPP: Unit type not supported + * -ENOLINK: The necessary dependencies are not fulfilled. */ int unit_start(Unit *u) { UnitActiveState state; @@ -1589,6 +1616,12 @@ int unit_start(Unit *u) { if (!unit_supported(u)) return -EOPNOTSUPP; + /* Let's make sure that the deps really are in order before we start this. Normally the job engine should have + * taken care of this already, but let's check this here again. After all, our dependencies might not be in + * effect anymore, due to a reload or due to a failed condition. */ + if (!unit_verify_deps(u)) + return -ENOLINK; + /* Forward to the main object, if we aren't it. */ following = unit_following(u); if (following) { diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 4dd343c101..2ebc00f247 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -242,8 +242,6 @@ static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); if (r < 0) goto fail; - - acd->n_conflict = 0; } else { r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC); if (r < 0) diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index ce8d59d390..d155625e11 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -118,7 +118,7 @@ static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) { /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */ - assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET)); + assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET6)); memcpy(&in6, a, sizeof(struct in6_addr)); return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0; @@ -206,8 +206,8 @@ enum nss_status _nss_resolve_gethostbyname4_r( l = strlen(canonical); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c; if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = TRY_AGAIN; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } @@ -394,8 +394,8 @@ enum nss_status _nss_resolve_gethostbyname3_r( ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = TRY_AGAIN; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } @@ -615,8 +615,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( c * sizeof(char*); /* pointers to aliases, plus trailing NULL */ if (buflen < ms) { - *errnop = ENOMEM; - *h_errnop = TRY_AGAIN; + *errnop = ERANGE; + *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 463e135e2b..ce6c7aa18a 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) { uid_t uid; int r; - const char* name = argv[1] ?: "nfsnobody"; + const char* name = argv[1] ?: NOBODY_USER_NAME; r = get_user_creds(&name, &uid, NULL, NULL, NULL); if (r < 0) { |