The header and keyfile are necessary only for opening the device, not
for closing, so it is not necessary to deactivate the generated
cryptsetup unit when the header or keyfile backing store are removed.
This is especially useful in the case of softreboot, when the new
mount root is setup under /run/nextroot/ but we don't want to close
the cryptsetup devices for encrypted /var/ or so, and we simply
mount it directly on /run/nextroot/var/ before the soft-reboot.
unsuccessful. Note that other units that depend on the unlocked device may still fail. In
particular, if the device is used for a mount point, the mount point itself also needs to
have the <option>nofail</option> option, or the boot will fail if the device is not unlocked
unsuccessful. Note that other units that depend on the unlocked device may still fail. In
particular, if the device is used for a mount point, the mount point itself also needs to
have the <option>nofail</option> option, or the boot will fail if the device is not unlocked
+ successfully. If a keyfile and/or a <option>header</option> are specified, the dependencies on
+ their respective directories will also not be fatal, so that umounting said directories will
+ not cause the generated cryptset unit to be deactivated.</para>
<xi:include href="version-info.xml" xpointer="v186"/></listitem>
</varlistentry>
<xi:include href="version-info.xml" xpointer="v186"/></listitem>
</varlistentry>
static int print_dependencies(FILE *f, const char* device_path, const char* timeout_value, bool canfail) {
int r;
static int print_dependencies(FILE *f, const char* device_path, const char* timeout_value, bool canfail) {
int r;
- assert(!canfail || timeout_value);
+ assert(f);
+ assert(device_path);
if (STR_IN_SET(device_path, "-", "none"))
/* None, nothing to do */
if (STR_IN_SET(device_path, "-", "none"))
/* None, nothing to do */
fprintf(f, "After=%1$s\n", unit);
if (canfail) {
fprintf(f, "Wants=%1$s\n", unit);
fprintf(f, "After=%1$s\n", unit);
if (canfail) {
fprintf(f, "Wants=%1$s\n", unit);
- r = write_drop_in_format(arg_dest, unit, 90, "device-timeout",
- "# Automatically generated by systemd-cryptsetup-generator \n\n"
- "[Unit]\nJobRunningTimeoutSec=%s", timeout_value);
- if (r < 0)
- return log_error_errno(r, "Failed to write device drop-in: %m");
+ if (timeout_value) {
+ r = write_drop_in_format(arg_dest, unit, 90, "device-timeout",
+ "# Automatically generated by systemd-cryptsetup-generator \n\n"
+ "[Unit]\nJobRunningTimeoutSec=%s", timeout_value);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write device drop-in: %m");
+ }
} else
fprintf(f, "Requires=%1$s\n", unit);
} else {
} else
fprintf(f, "Requires=%1$s\n", unit);
} else {
if (!escaped_path)
return log_oom();
if (!escaped_path)
return log_oom();
- fprintf(f, "RequiresMountsFor=%s\n", escaped_path);
+ fprintf(f, "%s=%s\n", canfail ? "WantsMountsFor" : "RequiresMountsFor", escaped_path);
if (key_file && !keydev) {
r = print_dependencies(f, key_file,
keyfile_timeout_value,
if (key_file && !keydev) {
r = print_dependencies(f, key_file,
keyfile_timeout_value,
- /* canfail= */ keyfile_can_timeout > 0);
+ /* canfail= */ keyfile_can_timeout > 0 || nofail);
/* Check if a header option was specified */
if (detached_header > 0 && !headerdev) {
r = print_dependencies(f, header_path,
/* Check if a header option was specified */
if (detached_header > 0 && !headerdev) {
r = print_dependencies(f, header_path,
- NULL,
- /* canfail= */ false); /* header is always necessary */
+ /* timeout_value= */ NULL,
+ /* canfail= */ nofail);
cryptsetup_start_and_check() {
local expect_fail=0
cryptsetup_start_and_check() {
local expect_fail=0
+ local umount_header_and_key=0
local ec volume unit
if [[ "${1:?}" == "-f" ]]; then
local ec volume unit
if [[ "${1:?}" == "-f" ]]; then
+ if [[ "${1:?}" == "-u" ]]; then
+ umount_header_and_key=1
+ shift
+ fi
+
for volume in "$@"; do
unit="systemd-cryptsetup@$volume.service"
for volume in "$@"; do
unit="systemd-cryptsetup@$volume.service"
+ if [[ "$umount_header_and_key" -ne 0 ]]; then
+ umount "$TMPFS_DETACHED_KEYFILE"
+ umount "$TMPFS_DETACHED_HEADER"
+ udevadm settle --timeout=30
+ fi
+
systemctl status "$unit"
test -e "/dev/mapper/$volume"
systemctl stop "$unit"
systemctl status "$unit"
test -e "/dev/mapper/$volume"
systemctl stop "$unit"
mount "/dev/disk/by-partlabel/keyfile_store" /mnt
cp "$IMAGE_DETACHED_KEYFILE2" /mnt/keyfile
umount /mnt
mount "/dev/disk/by-partlabel/keyfile_store" /mnt
cp "$IMAGE_DETACHED_KEYFILE2" /mnt/keyfile
umount /mnt
+
+# Also copy the key and header on a tmpfs that we will umount after unlocking
+TMPFS_DETACHED_KEYFILE="$(mktemp -d)"
+TMPFS_DETACHED_HEADER="$(mktemp -d)"
+mount -t tmpfs -o size=32M tmpfs "$TMPFS_DETACHED_KEYFILE"
+mount -t tmpfs -o size=32M tmpfs "$TMPFS_DETACHED_HEADER"
+cp "$IMAGE_DETACHED_KEYFILE" "$TMPFS_DETACHED_KEYFILE/keyfile"
+cp "$IMAGE_DETACHED_HEADER" "$TMPFS_DETACHED_HEADER/header"
+
udevadm settle --timeout=30
# Prepare our test crypttab
udevadm settle --timeout=30
# Prepare our test crypttab
detached_slot0 $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER
detached_slot1 $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER,key-slot=8
detached_slot_fail $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER,key-slot=0
detached_slot0 $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER
detached_slot1 $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER,key-slot=8
detached_slot_fail $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER,key-slot=0
+detached_nofail $IMAGE_DETACHED $TMPFS_DETACHED_KEYFILE/keyfile headless=1,header=$TMPFS_DETACHED_HEADER/header,keyfile-offset=32,keyfile-size=16,nofail
EOF
# Temporarily drop luks.name=/luks.uuid= from the kernel command line, as it makes
EOF
# Temporarily drop luks.name=/luks.uuid= from the kernel command line, as it makes
cryptsetup_start_and_check -f detached_fail{0..4}
cryptsetup_start_and_check detached_slot{0..1}
cryptsetup_start_and_check -f detached_slot_fail
cryptsetup_start_and_check -f detached_fail{0..4}
cryptsetup_start_and_check detached_slot{0..1}
cryptsetup_start_and_check -f detached_slot_fail
+cryptsetup_start_and_check -u detached_nofail