[systemd-devel] Boot ordering

Kai Krakow hurikhan77 at gmail.com
Thu Mar 19 15:56:55 PDT 2015

Reindl Harald <h.reindl at thelounge.net> schrieb:

> Am 19.03.2015 um 22:04 schrieb Kai Krakow:
>> Christoph Pleger <Christoph.Pleger at cs.tu-dortmund.de> schrieb:
>>> I am experimenting a little with systemd and trying to define a new
>>> "intermediate" runlevel, a runlevel between basic.target and
>>> multi-user.target. This means that I want the services which are
>>> required by my new runlevel to be started after all services from
>>> basic.target have been started and to be finished before any service
>>> from multi-user.target is started.
>> I think there is still this sysvinit-related misconception that systemd
>> target equal sysvinit runlevels.
>> Systemd uses automatic ordering of units through socket activation and
>> explicitly defined dependencies (which BTW most of the time are not
>> needed). Thus, a target just defines which set of services you want to
>> run asap. Multiple targets can become active in parallel, and systemd
>> will try to reach them in parallel. All dependencies will be thrown into
>> the same soup and systemd works its way through it
> that is all fine but given that you don't know when a service is ready
> to accept connections and the whole world don't turn around systemd it
> is a legit need to control ordering sometimes strictly

Well I don't see where the conflict is. Double-forking services should 
probably just not return to the caller until they are ready to accept 
connections. This is why you should design your service units for systemd to 
not fork but start the process in foreground (most services have a cmdline 
option for that since years). That is a clear signal for systemd that the 
service is ready (other signals are the appearence of a PID file for forking 
processes, but that is not recommended). Forking or double forking only gets 
in the way for that and is a design from sysvinit days to actually speedup 
boot (which you state should not be the priority, and I agree with that) 
and/or decouple the console so the process does not become killed by the HUP 
signal, or can setuid/setgid. If you don't want to trust some of those 
security measures to systemd (or start-stop-daemon in openrc, or whatever) 
then it is probably "your" task to ensure that the process is ready when the 
parent returns to the caller after forking. This is something often done 
"wrong" even for sysvinit - otherwise I cannot explain why we need "sleep 5" 
or "while try-something; do sleep 1; done" in init scripts. And yes, I added 
such fixes myself to init scripts in the past. And not needing it with 
systemd has nothing to do with performance but with reliability, altough I 
appreciate the performance benefit of it and it also looks much cleaner 
without "hacks". This goes along with clever tricks of init script 
maintainers who added "&" to the process spawning "to speed up things" which 
I had to remove sometimes to get a much slower but at least reliable service 

> boot performance is not the only important thing - better said on
> servers it don't matter that much given you don't boot the machine all
> day long - relieable boot in every context is much more important while
> claiming everybody does soemthing wrong and systemd is right with it's
> assumptions don't help much

You cannot simply say "boot performance is not important for servers". I 
actually would easier accept "boot performance is not important for 
desktops" because we have hibernate/suspend/sleep - desktops don't really 
need to reboot except for updates.

With modern servers which offer UEFI boot, POST time can be reduced to 
seconds when we had minutes sometimes in legacy BIOS. So, with the arrival 
of such servers we also have the need for fast boots - because service 
downtime can be a cost factor. In that regard, I cannot agree with you 
although I think that your argument is true for some, maybe most, scenarios.

But let's also elaborate on "reliable boot": This is, what systemd actually 
offers and even can guarantee, in a much better way traditional sysvinit 
could ever do. It provides well defined targets telling me if a set of 
services is up (sysvinit doesn't). It provides supervising, and it provides 
socket activation with automatic blocking. For services designed to support 
systemd (and I don't think that is such a big deal for most services), you 
could even restart services without service interruption because socket 
activation can guaratee uninterrupted (though delayed) service provision. 
You may argue there are supervising managers like supervise, runit, etc. But 
first most of them cannot use socket activation and thus do not give the 
same guarantees, and if they do, they need to use the same or very similar 
modifications to your service as they need to use for supporting systemd. 
And after all one can still argue that using facilities like supervise is no 
longer traditional sysvinit - so where's the point?

Noone claims that everyone is doing it wrong, neither that systemd is the 
only one doing it right. Everything is fine with traditional sysvinit, with 
its double-forking, early returns before a service is ready, unreliable 
dependency startup (if something goes wrong it really goes wrong), more or 
less random sleep commands to solve that very problem, artificial runlevels 
to unreliably "ensure" a set of services running... Well, it is just not the 
same quality of what systemd could do better (and in a different way, yes I 
heard you, that can be a painful learning curve). And what stops you from 
setting up a minimal systemd runlevel/target, and finally in the end start a 
service unit which runs all your nifty sysvinit'ish initializations from a 
traditional sysvinit script?

If run sysvinit-style servers for 15+ years now - and sysvinit startup _IS_ 
unreliable. Services sometimes randomly fail to start or dependent services 
timeout for no obvious reason... Most times it was fixed by inserting sleeps 
before or after service spawning, or inserting some unexpected dependencies 
or moving services between different runlevels. This has ended with systemd. 
If it works, it reliably works throughout the complete dependency chain or 
at least can clearly tell me what went wrong through the journal without 
mixing up error messages and console output of the boot process (which is a 
PITA on headless systems anyways) or either distributing logs across various 
different text log files or putting everything in one monolithic log file 
without serious tools to filter and sort that stuff (c'mon, grep, really?). 
And it also clearly knows when and why a service died while sysvinit often 
happily announced it still running and even refused to restart it because 
the PID file was still there (PID files are broken by design anyways). 
Sorry, I cannot accept that as "reliable". It even is not reliable if you 
follow the rule "if it works never touch it". BTW: You need security updates 
one time or another.

I can agree, however, with the fact that systemd is the only init system 
currently offering those features and that this is taking away freedom of 
choice in a way. But every service that is systemd compliant is still able 
to run without systemd, from traditional sysvinit - at least I yet didn't 
see anything that wouldn't. Integrating dbus, udev, or other things (and 
also the vice-versa: integrating systemd as runtime dependency into other 
ecosystems like Gnome) should clearly not become subject of this discussion, 
that's a whole different point.

But on the other hand, I think it is not that bad having systemd around and 
its "wide acceptance": For (probably) the first time in a long row of years 
Linux sees some reliable, consistent API between different distributions (I 
think its diversity is equally one of its greatest strengths and at the same 
time its biggest opponent). But this "milestone" now is IMHO a good thing 
because developers can concentrate on creating great tools building on it 
("it" being the API, I clearly don't want to say "systemd" here) instead of 
solving always the same problems over and over again. And let's just say: 
Why should systemd take the sole role of implementing this API? I think 
other, yet to come, init systems could also implement it. The design behind 
systemd and its API is not that bad, I'm sure you could agree with it. If it 
has to be systemd or an alternate implementation in the end, that's a matter 
of taste.

We wouldn't be here if new technology had always been rejected. We are here 
because new technology was adopted, by different people, in different ways, 
and most successfully with common standards, in the last 150 years and even 

I don't want to get out of scope here. But I think the problem is that 
humans naturally refuse to accept change. Even more if they weren't asked. 
And I can agree with that: it can feel that systemd was forced on us. But I 
cannot count myself to those people because I eagerly wanted to try this 
technology and it worked for me, and with Gentoo I still had choice to use 
openrc. I remember when dbus "was forced on us", I hated it because the 
migration in my DE didn't work well for me. Nothing seemed to work reliably 
for a long time. But now it's everywhere and integral part of every distro. 
Similar to udev though I never had a problem with it - but in the end it 
looked very useful to me although I had some hickups with device naming etc.

The point is: Let's just find out why the "intuitive" way to solve the OPs 
problem doesn't work out and find the right solution. Let's face it: Trying 
to use targets as sysvinit runlevels equivalent is obviously not the working 
way although it looks promising and intuitive at first (I'd probably tried 
the same first). That kind of problem (in a common sense) is something one 
will face over and over again, unrelated to systemd. What is so special, so 
different, when it's related to systemd?

Replies to list only preferred.

More information about the systemd-devel mailing list