跳转至

linux 系统迁移

linux 系统迁移

买了一条三星的 PM9A1 SSD,想要把原本的 linux 迁移到新的固态上。

系统信息

  • 原本的系统(windows 和 ubuntu 双系统)安装在固态上,包含 EFI 分区。
  • 系统引导方式:EFI/GPT(其它方式有 BIOS/MBR, BIOS/GPT)

    BIOS system

    On a BIOS/GPT system there is no MBR and therefore no place to store the loader. The GPT partition specification allows for an unformatted partition of the BIOS boot partition type (0xEF02). The size of this partition can be as small as 1 mebibyte. The Calamares installer uses a fixed size of 32 mebibyte. On a BIOS/MBR system a part of the bootloader is written to the Master Boot Record for the primary disk.

步骤

格式化磁盘

在固态上创建两个分区

  • EFI 分区,100MB,格式化为 FAT32
    • gparted 可以设置分区名称命名为 EFI
    • 设置标志为"boot esp"
  • 系统根目录分区,剩余空间,格式化为 ext4

挂载磁盘

mkdir /mnt/ubuntu
sudo mount /dev/nvme0np2 /mnt/ubuntu

备份/复制文件

可以将系统根目录(需要排除一些目录)打包压缩成一个备份文件,然后解压到新固态根目录分区中。好处是以后可以再次从备份中恢复。

也可以直接将系统复制到新的固态上

tar

参考 https://rovo98.github.io/posts/3babee60/

rsync

rsync 用于在两台机器间复制文件,会比较源目录和目的目录内的文件,避免复制重复的文件

不用 cp 主要是 cp 排除目录不太方便。并且万一出现问题需要重新复制,需要重新复制覆盖之前复制过的文件。

rsync -aP --delete --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/swapfile","/home/yfy/D/*","/home/yfy/Disk/*"} / /mnt/ubuntu/ | tee /tmp/rsync_backup.log
 mount -o compress=zstd,subvol=/root /dev/nvme0n1p2 /mnt/ryzen
 mount -o compress=zstd,subvol=/home /dev/nvme0n1p2 /mnt/ryzen/home

rsync -aP --delete --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found","/swapfile"} / /mnt/ryzen/ | tee /tmp/rsync_backup.log

选项说明

  • -a:保持文件属性
  • -P:显示进度条
  • --delete:删除目的目录比源目录多出的文件
  • --exclude:排除文件列表。"/dev/*"中的"*"用于在目的目录中保留空的 dev 目录
    • 排除项中间,不能接空格,否则格式错误
    • 排除项表示匹配模式。rsync exclude directory not working - Unix & Linux Stack Exchange
      • 根目录是 transfer root 作为根目录
      • 不从根目录开始,则会排除所有同名的目录
    • 坑:如果--exclude 只用于排除一个项的话,不要用花括号。
  • 有无斜线:src dst/表示将src目录自身复制到dst目录下,src/ dst/则将src目录下内容复制到dst目录下
  • 建议使用 --dry-run 先看看会复制什么

建议阅读 man rsync 下面两个部分

INCLUDE/EXCLUDE PATTERN RULES

ANCHORING INCLUDE/EXCLUDE PATTERNS

ANCHORING INCLUDE/EXCLUDE PATTERNS
       As mentioned earlier, global include/exclude patterns are anchored at the "root of the transfer" (as opposed to per-directory patterns, which are
       anchored  at  the  merge-file's  directory).  If you think of the transfer as a subtree of names that are being sent from sender to receiver, the
       transfer-root is where the tree starts to be duplicated in the destination directory.  This root governs where  patterns  that  start  with  a  /
       match.

       Because the matching is relative to the transfer-root, changing the trailing slash on a source path or changing your use of the --relative option
       affects the path you need to use in your matching (in addition to changing how much of the file tree is duplicated on the destination host).  The
       following examples demonstrate this.

       Let's  say  that  we want to match two source files, one with an absolute path of "/home/me/foo/bar", and one with a path of "/home/you/bar/baz".
       Here is how the various command choices differ for a 2-source transfer:

           Example cmd: rsync -a /home/me /home/you /dest
           +/- pattern: /me/foo/bar
           +/- pattern: /you/bar/baz
           Target file: /dest/me/foo/bar
           Target file: /dest/you/bar/baz

           Example cmd: rsync -a /home/me/ /home/you/ /dest
           +/- pattern: /foo/bar               (note missing "me")
           +/- pattern: /bar/baz               (note missing "you")
           Target file: /dest/foo/bar
           Target file: /dest/bar/baz

           Example cmd: rsync -a --relative /home/me/ /home/you /dest
           +/- pattern: /home/me/foo/bar       (note full path)
           +/- pattern: /home/you/bar/baz      (ditto)
           Target file: /dest/home/me/foo/bar
           Target file: /dest/home/you/bar/baz

           Example cmd: cd /home; rsync -a --relative me/foo you/ /dest
           +/- pattern: /me/foo/bar      (starts at specified path)
           +/- pattern: /you/bar/baz     (ditto)
           Target file: /dest/me/foo/bar
           Target file: /dest/you/bar/baz

mount EFI

之后需要修改 efi 分区,先将分区挂载到备份系统对应目录

sudo mount /dev/nvme0np1 /mnt/ubuntu/boot/efi

chroot

chroot 后新的进程以及子进程都只能访问新的根文件系统内的文件。不知道 chroot 被发明的原本目的是什么,但是现在我们可以很方便切换到备份的系统中,进行修改。

sudo chroot /mnt/ubuntu
mount proc,sys etc

在 chroot 的系统中,执行以下命令,否则无法执行程序以及一些操作,更具体的作用还不清楚。

sudo su
cd /mnt/arch # or where you are preparing the chroot dir
mount -t proc /proc proc/
mount --rbind /sys sys/
mount --rbind /dev dev/

修复 fstab

修改 fstab 文件中根目录和 EFI 目录挂载点设备的 UUID 为新固态的 UUID

sudo vim /etc/fstab
  • 通过 blkid 查看 UUID

    blkid
    

修复 grub

root@ubuntu:/boot# update-grub

Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/init-select.cfg'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-5.19.0-35-generic
Found initrd image: /boot/initrd.img-5.19.0-35-generic
Found linux image: /boot/vmlinuz-5.19.0-32-generic
Found initrd image: /boot/initrd.img-5.19.0-32-generic
Memtest86+ needs a 16-bit boot, that is not available on EFI, exiting
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding boot menu entry for UEFI Firmware Settings ...
done

此步骤会检测 linux image, initrd image 的位置,修改/boot/grub/grub.cfg菜单项。

如果遇到

EFI variables are not supported on this system.
  1. 退出 chroot
  2. load efi filesystem

    modprobe efivarfs
    
  3. 进入 chroot, mount the efi filesystem

    mount -t efivarfs efivarfs /sys/firmware/efi/efivars
    
  4. 验证

    ls /sys/firmware/efi
    

安装 grub 到 EFI 分区

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB

会在/boot/efi 下创建

root@ubuntu:/boot/efi# grub-install
Installing for x86_64-efi platform.
Installation finished. No error reported.


root@ubuntu:/boot/efi# tree .
.
└── EFI
    ├── BOOT
    │   ├── BOOTX64.EFI
    │   ├── fbx64.efi
    │   └── mmx64.efi
    └── ubuntu
        ├── BOOTX64.CSV
        ├── grub.cfg
        ├── grubx64.efi
        ├── mmx64.efi
        └── shimx64.efi

遇到问题

启动进入 grub 命令行

刚开始重启后,会进入 grub>命令行,而非 grub 菜单。搜索后知道这是 grub 没有找到 grub.cfg 文件(但是明明是有的)

When you boot up your system and it stops at the grub> prompt, that is the full GRUB 2 command shell. That means GRUB 2 started normally and loaded the normal.mod module (and other modules which are located in /boot/grub/[arch]/), but it didn’t find your grub.cfg file. If you see grub rescue> that means it couldn’t find normal.mod, so it probably couldn’t find any of your boot files.

可以手动引导进入系统

  1. 找到系统位置。可以通过 ls 知道有哪些磁盘和分区。然后再通过列出目录内容判断,如

    ls (hdd1,gpt5)/
    
  2. 设置 prefix,root

    set prefix=(hd1,gpt5)/boot/grub
    set root=(hd1,gpt5)/
    
  3. 启动

    normal
    

进入系统后再重新修复 grub

参考