]> git.ipfire.org Git - thirdparty/systemd.git/blame - docs/AUTOMATIC_BOOT_ASSESSMENT.md
fs-util: no need for fchmod_and_chown() to access /proc/self/fd directly
[thirdparty/systemd.git] / docs / AUTOMATIC_BOOT_ASSESSMENT.md
CommitLineData
c3e270f4
FB
1---
2title: Automatic Boot Assessment
3---
4
0c74648b
LP
5# Automatic Boot Assessment
6
7systemd provides support for automatically reverting back to the previous
8version of the OS or kernel in case the system consistently fails to boot. This
9support is built into various of its components. When used together these
10components provide a complete solution on UEFI systems, built as add-on to the
11[Boot Loader
12Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION). However, the
13different components may also be used independently, and in combination with
14other software, to implement similar schemes, for example with other boot
15loaders or for non-UEFI systems. Here's a brief overview of the complete set of
16components:
17
18* The
19 [`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/systemd-boot.html)
20 boot loader optionally maintains a per-boot-loader-entry counter that is
21 decreased by one on each attempt to boot the entry, prioritizing entries that
22 have non-zero counters over those which already reached a counter of zero
23 when choosing the entry to boot.
24
25* The
26 [`systemd-bless-boot.service(8)`](https://www.freedesktop.org/software/systemd/man/systemd-bless-boot.service.html)
27 service automatically marks a boot loader entry, for which boot counting as
28 mentioned above is enabled, as "good" when a boot has been determined to be
29 successful, thus turning off boot counting for it.
30
31* The
32 [`systemd-bless-boot-generator(8)`](https://www.freedesktop.org/software/systemd/man/systemd-bless-boot-generator.html)
33 generator automatically pulls in `systemd-bless-boot.service` when use of
34 `systemd-boot` with boot counting enabled is detected.
35
36* The
37 [`systemd-boot-check-no-failures.service(8)`](https://www.freedesktop.org/software/systemd/man/systemd-boot-check-no-failures.service.html)
38 service is a simple health check tool that determines whether the boot
b2454670 39 completed successfully. When enabled it becomes an indirect dependency of
0c74648b
LP
40 `systemd-bless-boot.service` (by means of `boot-complete.target`, see
41 below), ensuring that the boot will not be considered successful if there are
42 any failed services.
43
44* The `boot-complete.target` target unit (see
45 [`systemd.special(7)`](https://www.freedesktop.org/software/systemd/man/systemd.special.html))
46 serves as a generic extension point both for units that shall be considered
47 necessary to consider a boot successful on one side (example:
48 `systemd-boot-check-no-failures.service` as described above), and units that
49 want to act only if the boot is successful on the other (example:
50 `systemd-bless-boot.service` as described above).
51
52* The
53 [`kernel-install(8)`](https://www.freedesktop.org/software/systemd/man/kernel-install.html)
54 script can optionally create boot loader entries that carry an initial boot
55 counter (the initial counter is configurable in `/etc/kernel/tries`).
56
57# Details
58
59The boot counting data `systemd-boot` and `systemd-bless-boot.service`
60manage is stored in the name of the boot loader entries. If a boot loader entry
61file name contains `+` followed by one or two numbers (if two numbers, then
62those need to be separated by `-`) right before the `.conf` suffix, then boot
63counting is enabled for it. The first number is the "tries left" counter
64encoding how many attempts to boot this entry shall still be made. The second
65number is the "tries done" counter, encoding how many failed attempts to boot
66it have already been made. Each time a boot loader entry marked this way is
67booted the first counter is decreased by one, and the second one increased by
68one. (If the second counter is missing, then it is assumed to be equivalent to
69zero.) If the "tries left" counter is above zero the entry is still considered
70for booting (the entry's state is considered to be "indeterminate"), as soon as
71it reached zero the entry is not tried anymore (entry state "bad"). If the boot
72attempt completed successfully the entry's counters are removed from the name
73(entry state "good"), thus turning off boot counting for the future.
74
75## Walkthrough
76
77Here's an example walkthrough of how this all fits together.
78
791. The user runs `echo 3 > /etc/kernel/tries` to enable boot counting.
80
812. A new kernel is installed. `kernel-install` is used to generate a new boot
82 loader entry file for it. Let's say the version string for the new kernel is
83 `4.14.11-300.fc27.x86_64`, a new boot loader entry
84 `/boot/loader/entries/4.14.11-300.fc27.x86_64+3.conf` is hence created.
85
863. The system is booted for the first time after the new kernel is
87 installed. The boot loader now sees the `+3` counter in the entry file
88 name. It hence renames the file to `4.14.11-300.fc27.x86_64+2-1.conf`
89 indicating that at this point one attempt has started and thus only one less
90 is left. After the rename completed the entry is booted as usual.
91
924. Let's say this attempt to boot fails. On the following boot the boot loader
93 will hence see the `+2-1` tag in the name, and hence rename the entry file to
94 `4.14.11-300.fc27.x86_64+1-2.conf`, and boot it.
95
965. Let's say the boot fails again. On the subsequent boot the loader hence will
97 see the `+1-2` tag, and rename the file to
98 `4.14.11-300.fc27.x86_64+0-3.conf` and boot it.
99
1006. If this boot also fails, on the next boot the boot loader will see the the
101 tag `+0-3`, i.e. the counter reached zero. At this point the entry will be
102 considered "bad", and ordered to the end of the list of entries. The next
103 newest boot entry is now tried, i.e. the system automatically reverted back
104 to an earlier version.
105
b2454670 106The above describes the walkthrough when the selected boot entry continuously
0c74648b
LP
107fails. Let's have a look at an alternative ending to this walkthrough. In this
108scenario the first 4 steps are the same as above:
109
1101. *as above*
111
1122. *as above*
113
1143. *as above*
115
1164. *as above*
117
1185. Let's say the second boot succeeds. The kernel initializes properly, systemd
119 is started and invokes all generators.
120
1216. One of the generators started is `systemd-bless-boot-generator` which
122 detects that boot counting is used. It hence pulls
123 `systemd-bless-boot.service` into the initial transaction.
124
1257. `systemd-bless-boot.service` is ordered after and `Requires=` the generic
126 `boot-complete.target` unit. This unit is hence also pulled into the initial
127 transaction.
128
1298. The `boot-complete.target` unit is ordered after and pulls in various units
130 that are required to succeed for the boot process to be considered
131 successful. One such unit is `systemd-boot-check-no-failures.service`.
132
1339. `systemd-boot-check-no-failures.service` is run after all its own
134 dependencies completed, and assesses that the boot completed
135 successfully. It hence exits cleanly.
136
13710. This allows `boot-complete.target` to be reached. This signifies to the
138 system that this boot attempt shall be considered successful.
139
14011. Which in turn permits `systemd-bless-boot.service` to run. It now
141 determines which boot loader entry file was used to boot the system, and
142 renames it dropping the counter tag. Thus
143 `4.14.11-300.fc27.x86_64+1-2.conf` is renamed to
144 `4.14.11-300.fc27.x86_64.conf`. From this moment boot counting is turned
145 off.
146
14712. On the following boot (and all subsequent boots after that) the entry is
148 now seen with boot counting turned off, no further renaming takes place.
149
150# How to adapt this scheme to other setups
151
152Of the stack described above many components may be replaced or augmented. Here
153are a couple of recommendations.
154
1551. To support alternative boot loaders in place of `systemd-boot` two scenarios
156 are recommended:
157
158 a. Boot loaders already implementing the Boot Loader Specification can simply
159 implement an equivalent file rename based logic, and thus integrate fully
160 with the rest of the stack.
161
162 b. Boot loaders that want to implement boot counting and store the counters
163 elsewhere can provide their own replacements for
164 `systemd-bless-boot.service` and `systemd-bless-boot-generator`, but should
165 continue to use `boot-complete.target` and thus support any services
166 ordered before that.
167
1682. To support additional components that shall succeed before the boot is
169 considered successful, simply place them in units (if they aren't already)
170 and order them before the generic `boot-complete.target` target unit,
171 combined with `Requires=` dependencies from the target, so that the target
172 cannot be reached when any of the units fail. You may add any number of
173 units like this, and only if they all succeed the boot entry is marked as
174 good. Note that the target unit shall pull in these boot checking units, not
175 the other way around.
176
1773. To support additional components that shall only run on boot success, simply
178 wrap them in a unit and order them after `boot-complete.target`, pulling it
179 in.
180
181# FAQ
182
1831. *Why do you use file renames to store the counter? Why not a regular file?*
184 — Mainly two reasons: it's relatively likely that renames can be implemented
185 atomically even in simpler file systems, while writing to file contents has
186 a much bigger chance to be result in incomplete or corrupt data, as renaming
187 generally avoids allocating or releasing data blocks. Moreover it has the
188 benefit that the boot count metadata is directly attached to the boot loader
189 entry file, and thus the lifecycle of the metadata and the entry itself are
190 bound together. This means no additional clean-up needs to take place to
191 drop the boot loader counting information for an entry when it is removed.
192
1932. *Why not use EFI variables for storing the boot counter?* — The memory chips
194 used to back the persistent EFI variables are generally not of the highest
195 quality, hence shouldn't be written to more than necessary. This means we
196 can't really use it for changes made regularly during boot, but can use it
197 only for seldom made configuration changes.
198
1993. *I have a service which — when it fails — should immediately cause a
200 reboot. How does that fit in with the above?* — Well, that's orthogonal to
201 the above, please use `FailureAction=` in the unit file for this.
202
2034. *Under some condition I want to mark the current boot loader entry as bad
204 right-away, so that it never is tried again, how do I do that?* — You may
205 invoke `/usr/lib/systemd/systemd-bless-boot bad` at any time to mark the
206 current boot loader entry as "bad" right-away so that it isn't tried again
207 on later boots.