From Arch Wiki, Btrfs is a modern copy on write (CoW) filesystem for Linux aimed at implementing advanced features while also focusing on fault tolerance, repair and easy administration.
.
Situation: You have full disk encrypted (LUKS) with LVM RootFS with unencrypted boot partition and you want to transfer it to a new Hard Disk Drive or Solid State Drive, the drive partition table is Master Boot Record (MBR) and you are using Debian Stable. You do not want to install a new OS and reconfigure everything from scratch.
Note: The latest Debian Stable at the time of writing uses the Linux kernel 4.19. Swap can be used with btrfs with Kernel 5.1, so the LVM is not needed at all.
ATTENTION ATTENTION ATTENTION: PLEASE BACKUP YOUR VALUABLE DATA BEFORE ATTEMPTING TO DO THIS TUTORIAL! I WILL NOT BE RESPONSIBLE FOR THE LOSS OF YOUR DATA.
Installation of BTRFS tools
# apt update
# apt install btrfs-progs duperemover
Sample output:
# apt install btrfs-progs duperemove
Reading package lists... Done
Building dependency tree
Reading state information... Done
btrfs-progs is already the newest version (4.20.1-2).
duperemove is already the newest version (0.11.1-3).
Partitioning
You can use gparted
to make partitions easily.
The old partition layout:
Type: Master Boot Record (MBR)
Partition 1 - /boot (ext4) 1GB
Parition 2 - LUKS (LVM inside)
LVM name: OLD
OLD/root - / (root partition with EXT4 filesystem)
OLD/swap - swap partition
The new partition layout:
Type: Master Boot Record (MBR)
Partition 1 - /boot (ext4) 1GB
Partition 2 - LUKS (LVM inside, BTRFS doesn't support swap on <5.1 linux kernel (Debian stable is currently at 4.19)
LVM Name: NEW
NEW/btrfs - btrfs volume
NEW/swap - swap partition
Creating the filesystems
This assumes that your second disk is at /dev/sdb
, the primary disk is at /dev/sda
.
Make the /boot
filesystem to be ext4
: # mkfs.ext4 /dev/sda1
Making the LUKS partition:
# cryptsetup -c aes-xts-plain -s 256 luksFormat /dev/sdb2
WARNING!
========
This will overwrite data on /dev/sdb2 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
Open the LUKS partition
# cryptsetup luksOpen /dev/sdb2 NEW
Enter passphrase for /dev/sdb2:
Create a new physical volume
# pvcreate /dev/mapper/sdb2
Physical volume "/dev/mapper/sdb2" successfully created.
Display physical volumes:
# pvdisplay
Create volume group named NEW
# vgcreate NEW /dev/mapper/sdb2
Display volume group to show the usable space (Free PE)
# vgdisplay
...
Free PE / Size 25620 / 100.08 GiB
Create our logical volumes: (Encrypted SWAP Partition for btrfs)
At the time of writing the latest Debian 10 uses 4.19 kernel, so we need to setup LVM for our swap.
# lvcreate -L 4G -n swap NEW
Logical volume "swap" created.
Show the logical volumes:
# vgdisplay
...
Free PE / Size 25108 / 98.08 GiB
The free space is now 98GB or 25108
Create the partition for our btrfs root:
# lvcreate -l 25108 -n rootfs NEW
Logical volume "rootfs" created.
Setting up the Linux swap partition:
# mkswap /dev/NEW/swap
Setting up swapspace version 1, size = 4 GiB
no label, UUID=9xx-xx-x
Setting up the BTRFS:
Create our top level btrfs root:
# mkfs.btrfs -L btrfs /dev/NEW/rootfs
Mounting the newly created btrfs:
# mount /dev/NEW/rootfs /mnt
Creating btrfs subvolume for home
and /
:
# btrfs subv cr /mnt/root
Create subvolume '/mnt/root'
# btrfs subv cr /mnt/home
Create subvolume '/mnt/home
Unmounting and Mounting with subvol:
# umount /mnt
# mount -o subvol=root,noatime,compress=lzo /dev/NEW/rootfs /mnt
# mkdir /mnt/{boot,home}
# mount -o subvol=home,noatime,compress=lzo /dev/NEW/rootfs /mnt/home
compress=lzo
tells btrfs to use Lzo compression algorithm.
We will do a rsync of a running system, this is not recommended but for testing purposes this works. Be sure to stop all essential services that does disk writes in the background like MariaDB server, Prometheus, InfluxDB and Grafana.
Assume, sda = HDD Source (our currently running system) sdb = HDD Destination
sdb1 = boot partition with ext4 sdb2 = physical volume for encryption with LVM root and swap partitions inside (VG name NEW)
Volume group name – logical volume name: NEW-rootfs = the destination rootfs with btrfs NEW-swap = the created swap area partition
The source system is running, so we just start the cloning process:
This will take a while depending on the number of files and the speed of you disk. Also, be sure to close all programs and stop running services that does disk writes. Alternatively, you can do this on a Live USB/CD which is much preferred.
# rsync --progress -avhPHAXx --exclude={/dev/*,/proc/*,/sys/*,/tmp/*,/run/*,/mnt/*,/media/*,/lost+found} / /mnt
sending incremental file list
./
.autorelabel
.
.
sent 26.49G bytes received 36.42M bytes 3.80M bytes/sec
total size is 49.82G speedup is 1.80
The command above rsync’s the running system to the btrfs volume, excluded directories are dev, proc, run, sys, tmp, mnt, media and lost+found.
chrooting to the new btrfs system
We now need to chroot to the new btrfs drive, before doing that we need to note the UUIDs of each disks.
Display the blkids or just use GNOME Disk utility to determine the UUID of each partitions:
# blikd
/dev/sda1: UUID="source-boot" TYPE="ext4" PARTUUID=""
/dev/sda2: UUID="source-pv-luks" TYPE="crypto_LUKS" PARTUUID=""
/dev/mapper/OLD: UUID="bla" TYPE="LVM2_member"
/dev/mapper/OLD-swap: UUID="my-source-swap-UUID" TYPE="swap"
/dev/mapper/OLD-rootfss: LABEL="root" UUID="my-source-rootfs-UUID" TYPE="ext4"
/dev/sdb1: UUID="dest-boot" TYPE="ext4" PARTUUID=""
/dev/sdb2: UUID="dest-pv-luks" TYPE="crypto_LUKS" PARTUUID=""
/dev/mapper/NEW: UUID="bla2" TYPE="LVM2_member"
/dev/mapper/NEW-swap: UUID="my-dest-uuid-swap" TYPE="swap"
/dev/mapper/NEW-rootfs: UUID="my-dest-uuid-rootfs" TYPE="btrfs"
Chroot and mount the /boot
partition inside the chroot environment.
# for i in /sys /proc /run /dev; do mount --bind "$i" "/mnt$i"; done
# chroot /media/user/root/
# mount /dev/sdb1 /boot
Edit the crypttab
and replace the OLD
to our NEW
blkid and dm name:
# nano /etc/crypttab
OLD UUID=this-is-my-encrypted-luks-sda2-source none luks
TO
NEW UUID=this-is-my-encrypted-luks-sdb2-dest none luks
Whereas, OLD
is the device mapper name from /dev/mapper/
directory, and NEW
is also our cryptsetup luksOpen
mapper name.
Edit the fstab (replace the old entries with our ‘destination’ entries):
# nano /etc/fstab
The old fstab entries:
UUID=source-boot /boot ext4 defaults 0 2
UUID=my-source-swap-UUID none swap sw 0 0
UUID=my-source-rootfs-UUID / ext4 errors=remount-ro 0 1
The new fstab with btrfs:
UUID=my-dest-uuid-rootfs / btrfs rw,noatime,compress=lzo,space_cache,subvol=root 0 0
UUID=my-dest-uuid-rootfs /home btrfs rw,noatime,compress=lzo,space_cache,subvol=home 0 0
UUID=dest-boot /boot ext4 defaults,noatime 0 2
UUID=my-dest-uuid-swap none swap sw 0 0
Update the initramfs:
# update-initramfs -u -k all
[sudo] password for user:
update-initramfs: Generating /boot/initrd.img-4.19.0-14-amd64
...
live-boot: core filesystems devices utils udev wget blockdev dns.
Install the GRUB bootloader to the Master Boot Record of the target drive, in our case /dev/sdb
.
# grub-install /dev/sdb
Installing for i386-pc platform.
Update GRUB configuration:
# update-grub
Generating grub configuration file ...
Found background image: .background_cache.png
...
done
Exit Chroot and Unmount:
# for i in /sys /proc /run /dev; do umount "/mnt$i"; done
# umount /mnt/boot
# umount /mnt/home
# umount /mnt
PS. If you can’t unmount cleanly execute them with the -lf
command (eg. umount -lf /path
).
Close volume groups, LUKS and reboot to the new drive with btrfs.
# sync
# vgchange -an
# cryptsetup luksClose /dev/mapper/NEW
# reboot
This is tested on Master Boot Record, not on GPT. If you cannot still boot, please double check the crypttab entry and the /dev/mapper name.
References and interesting read:
Rsync command stackoverflow
https://btrfs.wiki.kernel.org/index.php/Getting_started
https://wiki.archlinux.org/index.php/Btrfs
https://www.paritybit.ca/blog/debian-with-btrfs
https://fogelholk.io/installing-arch-with-lvm-on-luks-and-btrfs/
https://gist.github.com/urwx/738e40217c4c7fd4ac896c7a4b71ba9e
Except where otherwise noted, this work is licensed under Creative Commons Attribution-ShareAlike 4.0 International License (http://creativecommons.org/licenses/by-sa/4.0/). I hope that this post is useful to you, if you liked this post you may support me via Patreon or liberapay. Thank you for your support.