记录一次linux系统迁移过程

就在最近,终于为自己的电脑加装了固态。在装完固态之后,首先面临的问题就是如何将原先安装在机械硬盘上的linux系统迁移到固态上。还要考虑后续配置的问题。

本文主要讲述在迁移Linux系统到新的固态硬盘上所遇到的问题以及找到的相应的解决方法。

这里先给出系统迁移以及相关配置完成之后的机械硬盘和固态硬盘的简单测速对比:

引入

拆开电脑,直接加装固态,顺便清清灰尘,换一下硅脂(ps: 这不知道是我第几次拆电脑了…,表示以后再也不买GPU风扇了,这已经是第二次失败的购买经历了(除非得到与原来匹配的风扇一致的风扇,不然我是不再换了).

清尘换硅脂:

install-ssd-01
加装固态和散热板:

install-ssd-01

迁移系统

准备

进入原先的linux系统,对已经安装上的固态硬盘进行分区。因为我之前在没有固态之前,在机械硬盘上就已经安装了三个系统(win10, manjaro, kali),因此在分区时,我是考虑只把两个linux迁移到固态上,毕竟win10现在已经基本不使用了,并将机械硬盘上的EFI分区也迁移到固态上。分区这里,可以按照自己的需求对固态硬盘进行分区。

分区工具的选择,随意,哪个顺手用哪个,例如:gparted, fdisk, parted,还有各种桌面自带的分区工具。我是使用的是fdisk:
例如:

1
sudo fdisk /dev/nvme0n1

diskparted

这里我已经分好区了的,具体的操作在fdisk中进行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Generic
d delete a partition
F list free unpartitioned space
l list known partition types
n add a new partition
p print the partition table
t change a partition type
v verify the partition table
i print information about a partition

Misc
m print this menu
x extra functionality (experts only)

Script
I load disk layout from sfdisk script file
O dump disk layout to sfdisk script file

Save & Exit
w write table to disk and exit
q quit without saving changes

Create a new label
g create a new empty GPT partition table
G create a new empty SGI (IRIX) partition table
o create a new empty DOS partition table
s create a new empty Sun partition table

例如创建EFI分区:

1
2
3
4
5
6
7
8
9
10
Command (m for help): n
Partition number (2-128, default 2): 2 # 创建一个分区作为EFI分区
First sector (xxxxx-xxxxxxxxxxx, default xxxxx):
Last sector, +sectors or +size{K,M,G,T,P} (34-2047, default xxxxxxx): +200M
Created a new partition 2 of type 'Linux filesystem' and of size 200 Mb.
Command (m for help): t # 修改EFI分区的分区类型为EFI系统分区
...

# 最后保存设置
Command (m for help): w

请注意先查看所执行的分区操作是不是你想要的再进行最后的保存设置

其他的分区创建类似EFI的创建,swap分区需要指定为Linux swap分区,作为linux数据分区的分区在创建时默认就是linux filesystem类型了,不需要更改,之后对创建的分区进行格式化:将EFI格式化为fat32,将linux数据分区格式化ext4; 先通过sudo fdisk -llsblk查看已经创建分区对应的设备名,例如:
sudo fdisk -l:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Disk /dev/nvme0n1: 238.5 GiB, 256060514304 bytes, 500118192 sectors
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: 6D071E80-FF82-420B-A2D8-7A0BC4759F06

Device Start End Sectors Size Type
/dev/nvme0n1p1 34 262177 262144 128M Microsoft reserved
/dev/nvme0n1p2 264192 673791 409600 200M EFI System
/dev/nvme0n1p3 673792 9062399 8388608 4G Linux swap
/dev/nvme0n1p4 9062400 428492799 419430400 200G Linux filesystem
/dev/nvme0n1p5 428492800 500117503 71624704 34.2G Linux filesystem


Disk /dev/sda: 931.5 GiB, 1000204886016 bytes, 1953525168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: D5CB68A7-96DA-4C61-84E2-61C98489BFF1

Device Start End Sectors Size Type
/dev/sda1 64 125829183 125829120 60G Microsoft basic data
/dev/sda2 125829184 880802416 754973233 360G Microsoft basic data
/dev/sda3 880803904 1596575151 715771248 341.3G Microsoft basic data
/dev/sda4 1596575744 1953521663 356945920 170.2G Microsoft basic data

lsblk 查看分好的磁盘分区:

1
2
3
4
5
6
7
8
9
10
11
12
13
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda 8:0 0 931.5G 0 disk
├─sda1 8:1 0 60G 0 part /run/media/rovo98/System
├─sda2 8:2 0 360G 0 part /run/media/rovo98/Mshinoda
├─sda3 8:3 0 341.3G 0 part /run/media/rovo98/Chester bennington
└─sda4 8:4 0 170.2G 0 part /run/media/rovo98/LSR
sr0 11:0 1 1024M 0 rom
nvme0n1 259:0 0 238.5G 0 disk
├─nvme0n1p1 259:1 0 128M 0 part
├─nvme0n1p2 259:2 0 200M 0 part /boot/efi
├─nvme0n1p3 259:3 0 4G 0 part [SWAP]
├─nvme0n1p4 259:4 0 200G 0 part /
└─nvme0n1p5 259:5 0 34.2G 0 part /run/media/rovo98/a002d542-c8c4-4c98-85af-8a4446dbaa1b

对特定的分区进行格式化,例如:

1
2
3
4
5
# 对于linux数据分区
mkfs.ext4 /dev/nvme0n1p4
mkfs.ext4 /dev/nvme0n1p5
# EFI分区
mkfs.fat /dev/nvme0n1p2

注意: 执行每条格式化命令前,必须确认指定的分区是否是你想要格式化的分区

做好这些准备之后,就可以进行系统的迁移了

系统迁移操作

对于Linux系统,我们只需要知道Linux一切皆文件就行了。因此对于系统的迁移就变得简单了,可以使用dd,打包压缩然后解压缩,有关系统备份和恢复可以参看Arch wiki给出的:https://wiki.archlinux.org/index.php/System_backup.这里我是使用的是tar结合pigz(什么是pigz?)解压缩工具进行备份和恢复:

备份(打包压缩)

1
sudo tar --use-compress-program=pigz -cvpf /run/media/rovo98/Chester\ bennington/LP/GHOST/manjaro_backup_2018.10.7.tgz --exclude=/proc --exclude=/sys --exclude=/mnt --exclude=/run/media --exclude=/lost+found /

恢复到目标硬盘分区上(解包解压缩):
先目标分区挂载到/mnt下,如:/mnt/manjaro

1
mount /dev/nvme0n1p4 /mnt/manjaro
1
sudo tar --use-compress-program=pigz -xvpf /run/media/rovo98/Chester\ bennington/LP/GHOST/manjaro_backup_2018.10.7.tgz -C /mnt/manjaro

完成后需要手动创建,上面打包压缩是排除的文件夹:/proc, /sys, /mnt, /run, /lost+found.

详细备份和恢复过程可以参考查看:Arch上的备份还原

修复Grub、fstab文件以及refind引导管理

首先将/proc,/run,/dev,/sys重新挂载,让目标分区上的系统也拥有这些内容:

1
2
3
4
mount /proc /mnt/manjaro/proc
mount /sys /mnt/manjaro/sys
mount /run /mnt/manjaro/run
mount /dev /mnt/manjaro/dev

这些目录必须重新挂载,不然,当chroot切换进入目标系统之后,将无法获取一些系统信息,如:设备, 磁盘分区信息等.

chroot到目标系统之前,需要挂载EFI分区到/mnt/manjaro/boot/efi(refind管理文件默认位置)下:

1
mount /dev/nvme0n1p2 /mnt/manjaro/boot/efi

chroot到目标系统中,进行之后的操作

1
chroot /mnt/manjaro

更新fstab文件

获取相应分区的UUID,以更新fstab文件和/etc/default/grub文件:
blkid:

ls -l /dev/disk/by-uuid:

更新fstab文件:

主要修改挂载项以及对应的UUID,有关fstab文件的详细内容可以参考https://wiki.archlinux.org/index.php/Fstab

修复Grub

  1. 重新生成Grub
1
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader=Manjaro --recheck
  1. 更新Grub配置文件
1
2
3
sudo update-grub

sudo grub-mkconfig -o /boot/grub/grub.cfg

注意:如果此过程中出现以下提示信息:

EFI variables are not supported on this system.

需要先安装efibootmgr, dosfstools以及grub包,然后重新尝试重新生成Grub并更新其配置文件.

若仍出现该信息,则先退出chroot环境,并加载efivarfs模块:

1
sudo modprobe efivarfs

然后再进入chroot环境,执行:

1
mount -t efivarfs efivarfs /sys/firmware/efi/efivars

再重新生成Grub并更新Grub配置文件就好了。

重新配置refind

对之前的refind配置文件进行备份,保留主题文件themesrefind.conf就好了,其余的文件在执行refind-install时会自动生成.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 已经生成过了的,打印信息如下
ShimSource is none
Installing rEFInd on Linux....
ESP was found at /boot/efi using vfat
Found rEFInd installation in /boot/efi/EFI/refind; upgrading it.
Installing driver for ext4 (ext4_x64.efi)
Copied rEFInd binary files

Notice: Backed up existing icons directory as icons-backup.
Existing refind.conf file found; copying sample file as refind.conf-sample
to avoid overwriting your customizations.

Keeping existing NVRAM entry
rEFInd is set as the default boot manager.
Existing //boot/refind_linux.conf found; not overwriting.

可以使用efibootmgr管理启动项,例如:
efibootmgr查看当前所有的启动项,efibootmgr -Bb xxxx来删除不要的启动项,详细使用可以man efibootmgr来查看。

其中的windows系统启动项通过PEUEFI引导修复生成即可(需要注意的是老旧的PE识别不了nvme固态)。

以上就是迁移Linux系统的完整过程了

遇到的问题

在做完上面的所有操作,并将之前机械硬盘上的EFI分区等等(除Win10系统之外)都删除之后,重新启动进入固态盘上的系统,在Grub引导过程出现UUID=***************找不到的信息,经过查看之后发现,在Grub引导时居然没有挂载我那块nvme固态。

通过了解发现Grub2.2版本并不支持nvme的固态,可以使用安装bootloader来进行引导。PS: 但我Manjaro安装的Grub2.3版本的,理论上是支持的。

通过一番查找之后,终于找到了解决方法:

  1. 添加加载模块 sudo vim /etc/mkinitcpio.conf
1
2
3
4
5
6
...

- MODULES = ""
+ MODULES="nvme"

...
  1. 更新mkinitcpio
1
2
3
#参数说明,详细可以通过man查看
-p, --preset preset
Build initramfs image(s) according to specified preset. This may be a file in /etc/mkinitcpio.d (without the .preset extension) or a full, absolute path to a file. This option may be specified multiple times to process multiple presets.
  1. 更新Grub
1
2
3
sudo update-grub

sudo grub-mkocnfig -o /boot/grub/grub.cfg

再次重启之后,便可以成功进入系统了。

参考链接:http://blog.51cto.com/shenfly231/1918426, 若要安装bootloader也可以参考该链接。

SSD优化

开启Trim功能

关于什么是TRIM?:

SSD TRIM is an Advanced Technology Attachment (ATA) command that enables an operating system to inform a NAND flash solid-state drive (SSD) which data blocks it can erase because they are no longer in use. The use of TRIM can improve the performance of writing data to SSDs and contribute to longer SSD life.

Most SSDs support the ATA_TRIM command for sustained long-term performance and wear-leveling. A techspot article shows performance benchmark examples of before and after filling an SSD with data.

As of Linux kernel version 3.8 onwards, support for TRIM was continually added for the different filesystems. See the following table for an indicative overview:

在使用Trim功能之前需要查看固态硬盘是否支持,否则可能造成数据丢失:

1
lsblk --discard

DISC-GRANDISC-MAX不为0则表示支持,详细查看上面的Arch Wiki给出的文章。

关于使用的Trim方式,Nvme 协议固态是不推荐使用的Continuous TRIM方式的。(详见Arch Wiki)

所以使用的定期执行fstrim的方式,即添加一个定时任务或服务让其自动执行,如每周执行一次trim操作。 参考Periodic TRIM

1
2
3
sudo systemctl enable fstrim.service

sudo systemctl enable fstrim.timer
fstrim.service
1
2
3
4
5
6
7
[Unit]
Description=Discard unused blocks on filesystems from /etc/fstab
Documentation=man:fstrim(8)

[Service]
Type=oneshot
ExecStart=/sbin/fstrim -Av

启用fstrim.timer服务则会自动每周做一次trim.

fstrim.timer
1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=Discard unused blocks once a week
Documentation=man:fstrim

[Timer]
OnCalendar=weekly
AccuracySec=1h
Persistent=true

[Install]
WantedBy=timers.target

IO调度器选择

一般来说,IO调度算法是为低速硬盘准备的,对于固态,最好是不使用任何IO调度器,或使用对硬盘干预程度最低的调度算法。

  1. 查看当前固态的IO调度器:

    可以看到我当前固态没有使用任何调度器,而机械硬盘使用的是bfq-sq.
  2. 修改IO调度器(临时的):
1
echo noop > /sys/block/sda/queue/scheduler
  1. 要永久生效则需要添加编写开机自启动脚本
    详见参考链接.

另外

更多有关Linux VM性能调优的可以参考:
https://lonesysadmin.net/tag/linux-vm-performance-tuning/