Skip to content

Instantly share code, notes, and snippets.

@andrewshadura
Last active March 31, 2025 12:20
Migrating the system onto the new SSD with LVM

Introduction

This is a work-in-progress note I’m writing for the future me to make his life easier when the laptop breaks again and just plugging the SSD into the new one isn’t going to work for some reason. It is based on this great post: http://www.voleg.info/lvm2-clone-logical-volume.html.

Recreate the partition table

# sfdisk -d /dev/sda | sfdisk /dev/nvme0n1
# sfdisk -l /dev/nvme0n1
Disk /dev/nvme0n1: 953.87 GiB, 1024209543168 bytes, 2000409264 sectors
Disk model: ...
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: ...

Device           Start        End    Sectors   Size Type
/dev/nvme0n1p1    2048    1366015    1363968   666M Linux filesystem
/dev/nvme0n1p2 1366016    1570815     204800   100M EFI System
/dev/nvme0n1p3      34       2047       2014  1007K BIOS boot
/dev/nvme0n1p5 1570816 2000409230 1998838415 953.1G unknown

Partition table entries are not in disk order.

Copy partitions

# systemctl stop boot-efi.automount boot.mount
# partclone.ext4 -s /dev/sda1 -N -b -o /dev/nvme0n1p1
Cloned successfully.
# partclone.vfat -s /dev/sda2 -N -b -o /dev/nvme0n1p2
Cloned successfully.
# partclone.dd -s /dev/sda3 -N -o /dev/nvme0n1p3
Cloned successfully.

Recreate the encrypted partition

# lsblk /dev/sda
NAME                MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
sda                   8:0    0 953.9G  0 disk  
├─sda1                8:1    0   666M  0 part  
├─sda2                8:2    0   100M  0 part  
├─sda3                8:3    0  1007K  0 part  
└─sda5                8:5    0 953.1G  0 part  
  └─data_crypt      253:0    0 953.1G  0 crypt 
    ├─data--vg-swap 253:1    0     8G  0 lvm   [SWAP]
    └─data--vg-root 253:2    0   940G  0 lvm   /
# cryptsetup luksDump /dev/sda5
# cryptsetup luksHeaderBackup /dev/sda5 --header-backup-file /root/luks.bin
# cryptsetup luksDump /root/luks.bin
# cryptsetup luksHeaderRestore /dev/nvme0n1p5 --header-backup-file /root/luks.bin
# cryptsetup luksOpen /dev/nvme0n1p5 target_crypt
Enter passphrase for /dev/nvme0n1p5: 
# lsblk /dev/nvme0n1
NAME             MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
nvme0n1          259:0    0 953.9G  0 disk  
├─nvme0n1p1      259:5    0   666M  0 part  
├─nvme0n1p2      259:6    0   100M  0 part  
├─nvme0n1p3      259:7    0  1007K  0 part  
└─nvme0n1p5      259:8    0 953.1G  0 part  
  └─target_crypt 253:3    0 953.1G  0 crypt 

Migrate the data using LVM

# pvs
  PV                     VG      Fmt  Attr PSize    PFree
  /dev/mapper/data_crypt data-vg lvm2 a--  <953.12g <5.12g
# vgs
  VG      #PV #LV #SN Attr   VSize    VFree
  data-vg   1   2   0 wz--n- <953.12g <5.12g
# lvs
  LV   VG      Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  root data-vg -wi-ao---- 940.00g
  swap data-vg -wi-ao----   8.00g
# pvcreate /dev/mapper/target_crypt
  Physical volume "/dev/mapper/target_crypt" successfully created.
# vgextend data-vg /dev/mapper/target_crypt
# lvconvert --type mirror -m1 /dev/data-vg/root /dev/mapper/target_crypt
  data-vg/root: Converted: 0.00%
  data-vg/root: Converted: 100.00%
# sync
# lvconvert --splitmirrors 1 --name root-copy /dev/data-vg/root
  Logical volume root converted.
# lvs
  LV        VG      Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  root      data-vg -wi-ao---- 940.00g
  root-copy data-vg -wi-a----- 940.00g
  swap      data-vg -wi-ao----   8.00g
# lvchange -an /dev/data-vg/root-copy
# lvconvert --type mirror -m1 /dev/data-vg/swap /dev/mapper/target_crypt
  data-vg/swap: Converted: 0.00%
  data-vg/swap: Converted: 100.00%
# lvconvert --splitmirrors 1 --name swap-copy /dev/data-vg/swap
  Logical volume swap converted.
# lvs
  LV        VG      Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  root      data-vg -wi-ao---- 940.00g
  root-copy data-vg -wi------- 940.00g
  swap      data-vg -wi-ao----   8.00g
  swap-copy data-vg -wi-a-----   8.00g
# lvchange -an /dev/data-vg/swap-copy
# vgsplit data-vg new-vg /dev/mapper/target_crypt
  New volume group "new-vg" successfully split from "data-vg"
# vgchange -an new-vg
  0 logical volume(s) in volume group "new-vg" now active
# vgexport new-vg
  Volume group "new-vg" successfully exported

At this point, copies of the volumes in new-vg are "exported" and inactive, so they won’t come up at boot automatically.

Reboot into e.g. CloneZilla, run vgimport and lvchange -ay followed by lvrename.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment