From 90989cf9c0381c28a0285320518e570da8a6bd00 Mon Sep 17 00:00:00 2001
From: Laurent Bercot
- The life of a Unix machine has three stages:
+ The life of a Unix machine has four stages:
@@ -87,8 +89,10 @@ Even the runit
program, designed with supervision in mind, remains as process 1 all the
time; at least runit makes things simple by clearly separating the three
stages and delegating every stage's work to a different script that is
-not run as process 1. (This requires very careful handling of the
-kill -9 -1 part of stage 3, though.)
+not run as process 1. (Since runit does not distinguish between
+stage 3 and stage 4, it needs very careful handling of the
+kill -9 -1 part of stage 3: getting /etc/runit/3 killed
+before it unmounts the filesystems would be bad.)
@@ -104,7 +108,7 @@ stages and delegating every stage's work to a different script that is
init does not have the right to die, but fortunately, it has the right
to execve()!
During stage 2, why use precious RAM, or at best, swap space, to store data
-that are only relevant to stages 1 or 3? It only makes sense to have an
+that are only relevant to stages 1 or 3-4? It only makes sense to have an
init process that handles stage 1, then executes into an init process that
handles stage 2, and when told to shutdown, this "stage 2" init executes into
a "stage 3" init which just performs shutdown. Just as runit does with the
@@ -158,7 +162,7 @@ are some general design tips.
- It is very possible, and I even recommend it. If you are using
+ It is very possible, and if you are attempting to write your own stage 1,
+I definitely recommend it. If you are using
s6-svscan as stage 2 init, stage 1 init should be simple enough
that it can be written in any scripting language you want, just
as /etc/runit/1 is if you're using runit. And since it
@@ -229,44 +234,84 @@ and the shell cannot.
- If you're using s6-svscan as stage 2 init on /service, then
-stage 3 init is naturally the /service/.s6-svscan/finish program.
-Of course, /service/.s6-svscan/finish can be a symbolic link
+ If you're using s6-svscan as stage 2 init on /run/service, then
+stage 3 init is naturally the /run/service/.s6-svscan/finish program.
+Of course, /run/service/.s6-svscan/finish can be a symbolic link
to anything else; just make sure it points to something in the root
filesystem (unless your program is an execline script, in which case
it is not even necessary).
- This is also very simple; even simpler than stage 1.
- The only tricky part is the kill -9 -1 phase: you must make sure
-that process 1 regains control and keeps running after it, because
-it will be the only process left alive. But since we're running stage 3
-init directly, it's almost automatic! this is an advantage of running
-the shutdown procedure as process 1, as opposed to, for instance,
-/etc/runit/3.
+ This is seemingly very simple, even simpler than stage 1, but experience
+shows that it's trickier than it looks.
+
+ One tricky part is the kill -9 -1 operation at the end of
+stage 3: you must make sure that process 1 regains control and keeps
+running after it, because it will be the only process left alive. If you
+are running a stage 3 script as process 1, it is almost automatic: your
+script survives the kill and continues running, up into stage 4. If you
+are using another model, the behaviour becomes system-dependent: your
+script may or may not survive the kill, so on systems where it does not,
+you will have to design a way to regain control in order to accomplish
+stage 4 tasks.
+
+ Another tricky part, that is only apparent with practice, is solidity.
+It is even more vital that nothing fails during stages 3 and 4
+than it is in stage 1, because in stage 1, the worst that can happen is
+that the machine does not boot, whereas in stages 3 and 4, the worst that
+can happen is that the machine does not shut down, and that is
+a much bigger issue.
+
+ For these reasons, I now recommend not tearing down the
+supervision tree for stages 3-4. It is easier to work in a stable
+environment, as a regular process, than it is to manage a whole shutdown
+sequence as pid 1: the presence of s6-svscan as pid 1, and of a working
+supervision tree, is a pillar you can rely on, and with experience I find
+it a good idea to keep the supervision infrastructure running until the end.
+Of course, that requires the scandir, and the active supervision directories,
+to be on a RAM filesystem such as tmpfs; that is good policy
+anyway.
- You'd have to be a masochist, or have extremely specific needs, not to
-do so.
+ Yes, definitely, just like stage 1.
+
+ However, you really should leave /run/service/.s6-svscan/finish
+(and the other scripts in /run/service/.s6-svscan) alone, and
+write your shutdown sequence without dismantling the supervision tree.
+You will still have to stop most of the services, but s6-svscan should
+stay. For a more in-depth study of what to do in stages 3-4 and how
+to do it, you can look at the source of s6-linux-init-shutdownd
+in the s6-linux-init
+package.
@@ -58,12 +58,14 @@ to add or remove services. This phase ends when the administrator
requires a shutdown.
Is it possible to write stage 1 init in a scripting language?
How to design a stage 3 init
+ How to design a stage 3-4 init
What stage 3 init must do
+ What stage 3-4 init must do
Is it possible to write stage 3 init in a scripting language?
How to log the supervision tree's messages
@@ -341,9 +386,9 @@ command, which is part of the execline distribution. The
redirfd
command does just the right amount of trickery with FIFOs for you to be
able to properly redirect process 1's stdout and stderr to the logging FIFO
-without blocking: redirfd -w 1 /service/s6-svscan-log/fifo blocks
-if there's no process reading on /service/s6-svscan-log/fifo, but
-redirfd -wnb 1 /service/s6-svscan-log/fifo does not.
+without blocking: redirfd -w 1 /run/service/s6-svscan-log/fifo blocks
+if there's no process reading on /run/service/s6-svscan-log/fifo, but
+redirfd -wnb 1 /run/service/s6-svscan-log/fifo does not.
-- cgit v1.3.1