Adding a RAID-1 volume to btrfs on LUKS
My laptop is set up as btrfs on a LUKS-encrypted partition. I bought a new M.2 drive, installed it on the extra slot… then wasted most of a day trying to make it work. Here’s a synopsis of why and what I did to resolve the problems. Hope it helps.
Setup
Lenovo Thinkpad P15v with two M.2 slots (only one in use). I bought it in November 2022, installed Gentoo on it, with this layout:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:1 0 953.9G 0 disk
.....
├─nvme0n1p4 259:12 0 1G 0 part /boot
├─nvme0n1p5 259:13 0 900M 0 part /sysrescue
└─nvme0n1p6 259:14 0 887.7G 0 part
└─root 254:1 0 887.7G 0 crypt /home
/snapshots
/.swap
/
That is: nvme0..p6
is LUKS, decrypted at boot time, with a btrfs filesystem
on top of that.
I bought and installed a new M.2 drive, partitioned it similarly (with
an identical-size p6), ran luksFormat
on it, then came to a screeching
halt because:
Problem
There’s no way to tell genkernel that it needs to unlock more than one LUKS device bz694778. That means you can’t do btrfs RAID on LUKS, because the RAID will come up with only one volume.
Also, I want to enter my LUKS passphrase once, not once for each partition.
Solution
The solution requires two parts:
- Patches to
genkernel
- Learning
keyctl
1. Patching genkernel
David Sardari maintains a
set of patches for genkernel
that allow unlocking multiple root and swap devices. Read the docs,
install patches 00
and 01
, re-emerge genkernel
.
(Life is volatile. It’s possible that David’s patches will not apply
to the version of genkernel
you’re installing. Fixing that is left
as an exercise for the reader).
Now edit /etc/default/grub
, pluralizing crypt_root
and adding
your new partition:
-GRUB_CMDLINE_LINUX="crypt_root=/dev/nvme0n1p6 root=LABEL=t ..."
+GRUB_CMDLINE_LINUX="crypt_roots=/dev/nvme0n1p6 crypt_roots=/dev/nvme1n1p6 root=LABEL=t ..."
2. Learning keyctl
This requires genkernel
4.3.2 or greater.
Edit /etc/genkernel.conf
, find the KEYCTL=
line, and set it to "yes"
.
Make up a name for your new keyctl token (replace “potrzebie” below) and run the following magic commands:
# cryptsetup token add --key-description potrzebie /dev/nvme0n1p6
# cryptsetup token add --key-description potrzebie /dev/nvme1n1p6
Edit /etc/default/grub
again and add one more entry to the cmdline:
-GRUB_CMDLINE_LINUX="...root=LABEL=t ..."
+GRUB_CMDLINE_LINUX="...root=LABEL=t keyctl_keydesc=potrzebie ..."
That’s it. You can now run genkernel ramdisk
and whatever scripts
you use for updating /boot/grub/grub.cfg
, and reboot. On boot,
the password prompt will be different:
- Enter passphrase for /dev/nvme0n1p6:
+ Please type the key 'potrzebie' for the user keyring then press Ctrl-D twice:
(DO NOT press Enter! Just type your passphrase, then ^D twice)
If all has gone well, that’s the last prompt you get. When you log in
as root, run ls -l /dev/mapper
and you’ll see the new disk as root_1
.
If you mistype, just Ctrl-Alt-Del to reboot. There’s no retry mechanism.
See genkernel(8)
(search for “keyctl”) and cryptsetup(8)
(search
for “token.*add”) for further info.
Enabling btrfs RAID
Once you’re super-comfy with the boot process, and you’re certain that all LUKS partitions will be unlocked safely before btrfs is activated, add the new partition as a RAID volume:
# btrfs device add /dev/nvme1n1p6 /
# btrfs balance start -dconvert=raid1 -mconvert=raid1 /
Moving further
Get rid of swapfile-on-btrfs. I was doing that solely because of the multiple-passphrase-prompts issue. Now I can use an actual encrypted swap partition. (Be sure to do the cryptsetup-token thing on it).