Bug#554506: (ugly) patch which should fix dm-crypt-on-lvm setups

November 03rd, 2010 - 08:50 pm ET by Jonas Meurer | Report spam



Hello,

Again I tried to work on this bugreport. I'm absolutely sure that
different bugs are spotted. Most people are hitting the following bug:

the debian-installer was changed to configure devices in fstab and
crypttab in the 'UUID=...' style some time ago. this works for most
systems, with the exception of 'dm-crypt on lvm' setups, where the
encrypted devices are on top of lvm.
the reason is, that the cryptroot initramfs script tries to determine
the volume group from the source device string if the source device is
not available at boot. in the past that was possible for source devices
like '/dev/mapper/vg01-root_crypt'. the lvm volume group is 'vg01'.
for source devices specified as 'UUID=...' this is not possible any
longer.

the only fix i can see, is make the cryptroot initramfs hook determine
the underlying lvm volume group (if any) at mkinitramfs time, and write
the name of the volume group to /conf/conf.d/cryptroot. this information
can be used by the initramfs script at boot time in order to activate
the volume group before trying to unlock the encrypted (logical volume)
device.

i now prepared some ugly patches against cryptroot-hook and
cryptroot-script, that implement what I described above.

the implementation is still very ugly but on my test systems it works.

please give the attached patches a try and see whether they finally fix
the issue for you.
even better would be suggestions on how to improve the implementations,
i.e. provide a more elegant solution.

comments #15, #40, #45, #82, #87, #113, #118 and #123 are about
different issues, which aren't related to this bug.

greetings,
jonas


/usr/share/initramfs-tools/hooks/cryptroot.orig
+++ /usr/share/initramfs-tools/hooks/cryptroot
@@ -230,6 +230,9 @@
lvm=*)
OPTIONS="$OPTIONS,$opt"
;;
+ lvm_vg=*)
+ OPTIONS="$OPTIONS,$opt"
+ ;;
keyscript=*)
opt=${opt#keyscript=}
if [ ! -x "/lib/cryptsetup/scripts/$opt" ] && [ ! -x "$opt" ]; then
@@ -338,7 +341,7 @@
}

add_device() {
- local node nodes opts lastopts i count
+ local node nodes node_deps node_maj node_min node_depnode node_vg opts lastopts i count
nodes="$1"
opts="" # Applied to all nodes
lastopts="" # Applied to last node
@@ -374,6 +377,18 @@
nodes="$lvmnodes"
fi

+ # Check for dm-crypt on lvm
+ node_deps=$(dmsetup deps "$nodes" 2>/dev/null | sed 's/[^:]*: *//;s/[ (]//g;s/)/ /g')
+ if [ -n "$node_deps" ]; then
+ node_maj=$(echo ${node_deps%,*} | sed -e "s/^[ \t]*//g")
+ node_min=$(echo ${node_deps#*,} | sed -e "s/[ \t]*$//g")
+ node_depnode=$(dmsetup ls | sed -n "s/\\([^ ]*\\) *($node_maj, $node_min)/\\1/p" | sed -e "s/[ \t]*$//")
+ node_vg=$(lvdisplay "/dev/mapper/$node_depnode" 2>/dev/null | sed -r -e "s|^ +VG Name +([^ ]+) *$|\1|;tx;d;:x")
+ if [ -n "$node_vg" ]; then
+ lastopts="lvm_vg=$node_vg"
+ fi
+ fi
+
# Prepare to setup each node
count=$(echo "$nodes" | wc -w)
i=1


/usr/share/initramfs-tools/scripts/local-top/cryptroot.orig
+++ /usr/share/initramfs-tools/scripts/local-top/cryptroot
@@ -100,6 +100,9 @@
lvm=*)
cryptlvm=${x#lvm=}
;;
+ lvm_vg=*)
+ cryptlvm_vg=${x#lvm_vg=}
+ ;;
keyscript=*)
cryptkeyscript=${x#keyscript=}
;;
@@ -142,28 +145,32 @@
activate_vg()
{
local vg
- vg="${1#/dev/mapper/}"
-
- # Sanity checks
- if [ ! -x /sbin/lvm ]; then
- message "cryptsetup: lvm is not available"
- return 1
- elif [ "$vg" = "$1" ]; then
- message "cryptsetup: lvm device name ($vg) does not begin with /dev/mapper/"
- return 1
- fi
+ if [ -n "$cryptlvm_vg" ]; then
+ vg="$cryptlvm_vg"
+ else
+ vg="${1#/dev/mapper/}"
+
+ # Sanity checks
+ if [ ! -x /sbin/lvm ]; then
+ message "cryptsetup: lvm is not available"
+ return 1
+ elif [ "$vg" = "$1" ]; then
+ message "cryptsetup: lvm device name ($vg) does not begin with /dev/mapper/"
+ return 1
+ fi

- # Make sure that the device contains at least one dash
- if [ "${vg%%-*}" = "$vg" ]; then
- message "cryptsetup: lvm device name ($vg) does not contain a dash"
- return 1
- fi
+ # Make sure that the device contains at least one dash
+ if [ "${vg%%-*}" = "$vg" ]; then
+ message "cryptsetup: lvm device name ($vg) does not contain a dash"
+ return 1
+ fi

- # Split volume group from logical volume.
- vg=$(echo ${vg} | sed -e 's#\(.*\)\([^-]\)-[^-].*#\1\2#')
+ # Split volume group from logical volume.
+ vg=$(echo ${vg} | sed -e 's#\(.*\)\([^-]\)-[^-].*#\1\2#')

- # Reduce padded --'s to -'s
- vg=$(echo ${vg} | sed -e 's#--#-#g')
+ # Reduce padded --'s to -'s
+ vg=$(echo ${vg} | sed -e 's#--#-#g')
+ fi

lvm vgchange -ay ${vg}
return $?







To UNSUBSCRIBE, email to debian-bugs-dist-REQUEST@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.org
email Follow the discussionReplies 4 repliesReplies Make a reply

Similar topics

Replies

#1 Jonas Meurer
November 04th, 2010 - 09:20 am ET | Report spam



Hey Christoph,

On 04/11/2010 Christoph Anton Mitterer wrote:
I haven't fully looked at this so perhaps it's unrelated,...

But one main problem I see here (that may be related), is that lvm's
init-scripts are simply wrong, and abusing some things.
I've already told Bastian this and there are even several bugs open.

The problem is that lvm's init script simply doesn't to an lvchange -ay
but try to detect the LV holding root.
And it does this in a wrong way by using the root= kernel param (which
is the final device, containing the root-fs)

Most lvm/dm-crypt realted I've seen were simply solvable by letting the
lvm initscript just do an lvchange -ay (thereby making all LVs
available) and then using dmcrypt/cryptsetup as normal.



while this bug is not related to init scripts at all, your suggestions
makes a lot of sense to me. after all, i don't see a reason to detect
the volume group with complicated dmsetup, sed and lvdisplay invokations
instead of just activating all volume groups globally in the initramfs.

attached patch removes any vg-guessing magic from the initramfs
cryptroot script, just invoking 'lvm vgchange -ay' instead.

thanks for the comment, Christoph!

greetings,
jonas


/usr/share/initramfs-tools/scripts/local-top/cryptroot.orig
+++ /usr/share/initramfs-tools/scripts/local-top/cryptroot
@@ -141,46 +141,31 @@

activate_vg()
{
- local vg
- vg="${1#/dev/mapper/}"
-
# Sanity checks
if [ ! -x /sbin/lvm ]; then
message "cryptsetup: lvm is not available"
return 1
- elif [ "$vg" = "$1" ]; then
- message "cryptsetup: lvm device name ($vg) does not begin with /dev/mapper/"
- return 1
fi

- # Make sure that the device contains at least one dash
- if [ "${vg%%-*}" = "$vg" ]; then
- message "cryptsetup: lvm device name ($vg) does not contain a dash"
+ # Detect available volume groups
+ vgs=$(lvm vgs --noheadings -o vg_name | sed -e "s/^[ \t]*\(.*\)[ \t]*$/\1/g")
+ if [ -z "$vgs" ]; then
+ message "cryptsetup: no lvm volume groups found"
return 1
fi

- # Split volume group from logical volume.
- vg=$(echo ${vg} | sed -e 's#\(.*\)\([^-]\)-[^-].*#\1\2#')
-
- # Reduce padded --'s to -'s
- vg=$(echo ${vg} | sed -e 's#--#-#g')
-
- lvm vgchange -ay ${vg}
+ lvm vgchange -ay
return $?
}

activate_evms()
{
local dev module
- dev="${1#/dev/evms/}"

# Sanity checks
if [ ! -x /sbin/evms_activate ]; then
message "cryptsetup: evms_activate is not available"
return 1
- elif [ "$dev" = "$1" ]; then
- message "cryptsetup: evms device name ($vg) does not begin with /dev/evms/"
- return 1
fi

# Load modules used by evms
@@ -219,8 +204,8 @@

# Make sure the cryptsource device is available
if [ ! -e $cryptsource ]; then
- activate_vg $cryptsource
- activate_evms $cryptsource
+ activate_vg
+ activate_evms
fi

# If the encrypted source device hasn't shown up yet, give it a
@@ -320,7 +305,7 @@
if [ -z "$cryptlvm" ]; then
message "cryptsetup: lvm fs found but no lvm configured"
return 1
- elif ! activate_vg "/dev/mapper/$cryptlvm"; then
+ elif ! activate_vg; then
# disable error message, LP: #151532
#message "cryptsetup: failed to setup lvm device"
return 1







To UNSUBSCRIBE, email to
with a subject of "unsubscribe". Trouble? Contact
Replies Reply to this message
#2 Jonas Meurer
November 04th, 2010 - 09:20 am ET | Report spam



Hey Christoph,

On 04/11/2010 Christoph Anton Mitterer wrote:
I haven't fully looked at this so perhaps it's unrelated,...

But one main problem I see here (that may be related), is that lvm's
init-scripts are simply wrong, and abusing some things.
I've already told Bastian this and there are even several bugs open.

The problem is that lvm's init script simply doesn't to an lvchange -ay
but try to detect the LV holding root.
And it does this in a wrong way by using the root= kernel param (which
is the final device, containing the root-fs)

Most lvm/dm-crypt realted I've seen were simply solvable by letting the
lvm initscript just do an lvchange -ay (thereby making all LVs
available) and then using dmcrypt/cryptsetup as normal.



while this bug is not related to init scripts at all, your suggestions
makes a lot of sense to me. after all, i don't see a reason to detect
the volume group with complicated dmsetup, sed and lvdisplay invokations
instead of just activating all volume groups globally in the initramfs.

attached patch removes any vg-guessing magic from the initramfs
cryptroot script, just invoking 'lvm vgchange -ay' instead.

thanks for the comment, Christoph!

greetings,
jonas


/usr/share/initramfs-tools/scripts/local-top/cryptroot.orig
+++ /usr/share/initramfs-tools/scripts/local-top/cryptroot
@@ -141,46 +141,31 @@

activate_vg()
{
- local vg
- vg="${1#/dev/mapper/}"
-
# Sanity checks
if [ ! -x /sbin/lvm ]; then
message "cryptsetup: lvm is not available"
return 1
- elif [ "$vg" = "$1" ]; then
- message "cryptsetup: lvm device name ($vg) does not begin with /dev/mapper/"
- return 1
fi

- # Make sure that the device contains at least one dash
- if [ "${vg%%-*}" = "$vg" ]; then
- message "cryptsetup: lvm device name ($vg) does not contain a dash"
+ # Detect available volume groups
+ vgs=$(lvm vgs --noheadings -o vg_name | sed -e "s/^[ \t]*\(.*\)[ \t]*$/\1/g")
+ if [ -z "$vgs" ]; then
+ message "cryptsetup: no lvm volume groups found"
return 1
fi

- # Split volume group from logical volume.
- vg=$(echo ${vg} | sed -e 's#\(.*\)\([^-]\)-[^-].*#\1\2#')
-
- # Reduce padded --'s to -'s
- vg=$(echo ${vg} | sed -e 's#--#-#g')
-
- lvm vgchange -ay ${vg}
+ lvm vgchange -ay
return $?
}

activate_evms()
{
local dev module
- dev="${1#/dev/evms/}"

# Sanity checks
if [ ! -x /sbin/evms_activate ]; then
message "cryptsetup: evms_activate is not available"
return 1
- elif [ "$dev" = "$1" ]; then
- message "cryptsetup: evms device name ($vg) does not begin with /dev/evms/"
- return 1
fi

# Load modules used by evms
@@ -219,8 +204,8 @@

# Make sure the cryptsource device is available
if [ ! -e $cryptsource ]; then
- activate_vg $cryptsource
- activate_evms $cryptsource
+ activate_vg
+ activate_evms
fi

# If the encrypted source device hasn't shown up yet, give it a
@@ -320,7 +305,7 @@
if [ -z "$cryptlvm" ]; then
message "cryptsetup: lvm fs found but no lvm configured"
return 1
- elif ! activate_vg "/dev/mapper/$cryptlvm"; then
+ elif ! activate_vg; then
# disable error message, LP: #151532
#message "cryptsetup: failed to setup lvm device"
return 1







To UNSUBSCRIBE, email to
with a subject of "unsubscribe". Trouble? Contact
Replies Reply to this message
#3 Alasdair G Kergon
November 04th, 2010 - 09:40 am ET | Report spam
If the complex processing doesn't work for everyone then yes, simplify
it and activate everything always.

To do it the other way you need logic something like:
Every time you boot, check if the stack of devices necessary to be
activated has changed, and if so, update the information for use next
time it boots.
At boot time, try the last stack known to work first. If it doesn't
work, try any other different saved stacks from earlier boots. If none
of them work then fall back to activating everything.

In other words make the initramfs code robust enough to cope with
the unexpected!

Alasdair




To UNSUBSCRIBE, email to
with a subject of "unsubscribe". Trouble? Contact
Replies Reply to this message
#4 Jonas Meurer
November 08th, 2010 - 06:20 am ET | Report spam

Hey Alasdair,

thanks for your comments.

On 04/11/2010 Alasdair G Kergon wrote:
If the complex processing doesn't work for everyone then yes, simplify
it and activate everything always.

To do it the other way you need logic something like:
Every time you boot, check if the stack of devices necessary to be
activated has changed, and if so, update the information for use next
time it boots.
At boot time, try the last stack known to work first. If it doesn't
work, try any other different saved stacks from earlier boots. If none
of them work then fall back to activating everything.

In other words make the initramfs code robust enough to cope with
the unexpected!



I now changed the initramfs code to always activate all volume groups:
both before cryptsetup in case the source device is not available, and
after cryptsetup in case the unlocked device contains lvm data.

this way, the complicated and error-prone volume group -guessing code is
not needed anymore.

greetings,
jonas






To UNSUBSCRIBE, email to
with a subject of "unsubscribe". Trouble? Contact
email Follow the discussion Replies Reply to this message
Help Create a new topicReplies Make a reply
Search Make your own search