0x01: 现状
一块硬盘上同时装有Windows 10和Arch Linux。数日前,Windows在一次更新中崩溃并无法恢复,我计划不再保留其于硬盘,而使用虚拟机运行Windows,以便在这不稳定的操作系统再次崩溃时利用虚拟机的快照(snapshot)功能迅速将其恢复至可用状态。
由此地,我希望将Windows所使用的数个分区全部删除,并将空余之空间供Arch Linux的rootfs用。然而,我不能直接使用 resize2fs
完成这个操作,原因如下:
- 该文件系统位于一个LVM逻辑卷(LV)上,且该卷组(VG)所包含的(唯一一个)物理卷(PV)是一个被LUKS加密的分区。
- 上述的被加密分区在整个硬盘靠后的位置。(这是先安装Windows 10,后安装Arch Linux造成的)
前者或许能通过[扩大LUKS卷->扩大LUKS容器->扩大LVM PV->扩大LVM LV->扩大ext4]来完成,但后者直接令扩大LUKS卷不可行。
Arch Linux仅包含了三个卷:
Block device FS Mount
/dev/nvme0n1p6 FAT32 /boot
/dev/nvme0n1p7 LUKS
|_vg0 LVM VG
|_arch-rootfs ext4 /
|_swap swap (swap)
0x02: 方案
鉴于此,我决定将Arch Linux的rootfs备份,抹掉该硬盘,重新分区(包括LUKS和LVM),再将数据恢复。
0x03: 操作
首先准备另一块硬盘以存储备份,如有固态硬盘则更好。
准备写入archiso的U盘,并以该U盘启动系统。登入后,给用于存储备份的硬盘(下简称:备份盘)分区,划分一个ext4分区即可。将这个分区挂载至 /mnt/backup
:
archiso # parted /dev/sda
(parted) mktable gpt
(parted) mkpart primary 0 100%
(parted) quit
archiso # mkfs.ext4 /dev/sda1
archiso # mkdir /mnt/backup
archiso # mount /dev/sda1 /mnt/backup
(可选) 在Block-device层级备份,这是为了确保万无一失——如发生意外,可用此过程产生的备份恢复。需要确保备份盘有足够的容量。
archiso # dd if=/dev/nvme0n1 of=/mnt/backup/nvme0n1_image.bin bs=256M conv=sync,noerror status=progress
挂载Arch Linux的rootfs至 /mnt/arch
:
archiso # cryptsetup luksOpen /dev/nvme0n1p7 dm0
archiso # pvscan
archiso # lvscan
archiso # mkdir /mnt/arch
archiso # mount /dev/vg0/arch-rootfs /mnt/arch
备份Arch Linux的rootfs:
archiso # cd /mnt/arch
archiso # tar -zcpvf /mnt/backup/arch-rootfs.tar.gz --one-file-system ./
事实上,对于熵较高的文件(如ELF,经压缩的媒体文件等)使用 gzip
并不能显著地减少其体积,但却耗费大量时间。故可不使用 gzip
,将第二行命令换做:
archiso # tar -cpvf /mnt/backup/arch-rootfs.tar --one-file-system ./
解除挂载并抹掉系统盘,重新建立分区:
archiso # cd /
archiso # umount /mnt/arch
archiso # cryptsetup close dm0
archiso # parted /dev/nvme0n1
(parted) mktable gpt
(parted) mkpart primary 0 1024M
(parted) mkpart primary 1024M 100%
(parted) quit
archiso # mkfs.fat -F32 /dev/nvme0n1p1
archiso # cryptsetup luksFormat /dev/nvme0n1p2
archiso # cryptsetup luksOpen /dev/nvme0n1p2 dm0
archiso # lvmdiskscan
archiso # pvcreate /dev/mapper/dm0
archiso # pvscan
archiso # vgcreate vg0 /dev/mapper/dm0
archiso # vgscan
archiso # lvcreate -L 225G vg0 -n arch-rootfs
archiso # lvcreate -l 100%FREE vg0 -n swap
archiso # lvscan
archiso # mkfs.ext4 /dev/mapper/vg0-arch-rootfs
archiso # mkswap /dev/mapper/vg0-swap
挂载分区并为 /dev
, /run
, /sys
及 /proc
建立符号链接:
archiso # mkdir -p /mnt/arch/boot
archiso # mount /dev/mapper/vg0-arch-rootfs /mnt/arch
archiso # mount /dev/nvme0n1p1 /mnt/arch/boot
archiso # swapon /dev/mapper/vg0-swap
archiso # ln -s /dev /mnt/arch/dev
archiso # ln -s /run /mnt/arch/run
archiso # ln -s /sys /mnt/arch/sys
archiso # ln -s /proc /mnt/arch/proc
由备份恢复系统, chroot
到恢复后的系统,重新生成内核的initramfs并安装bootloader(我的系统使用的是grub):
archiso # cd /mnt/arch
archiso # tar -zxpvf /mnt/backup/arch-rootfs_image.tar.gz
//如果你在建立镜像时未使用gzip...
archiso # tar -xpvf /mnt/backup/arch-rootfs_image.tar
archiso # cd ..
archiso # arch-chroot /mnt/arch
arch # pacman -S linux grub efibootmgr os-prober
arch # mkinitcpio -p linux
arch # grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub
通过 lsblk -o +UUID
找到新的三个卷(挂载与 /
, /boot
及 swap
)的UUID,并根据此修改 /etc/fstab
;找到LUKS卷 dm0
的UUID,并修改 /etc/default/grub
所包含的如下行:
GRUB_CMDLINE_LINUX="cryptdevice=UUID={uuid_of_dm0}:dm0"
重新生成grub配置文件:
grub-mkconfig -o /boot/grub/grub.cfg
解除挂载所有文件系统,关机,拔下U盘并重启:
arch # exit
archiso # cd /
archiso # umount -R /mnt/arch
archiso # umount /mnt/backup
archiso # swapoff -a
archiso # cryptsetup close dm0
archiso # poweroff
可能还需要在BIOS中添加grub的EFI文件(位于 {nvme0n1p1}/efi/boot/bootx64.efi
).