目前在使用 Arch + Windows 双系统进行工作,但由于是先安装的 Windows,所以默认分配的 efi 分区只有 100MB,而 /boot
这个目录我也挂载到这个分区上,故内核更新时经常空间不足,所以需要对 efi 进行扩容。不过 efi、保留分区以及 Windows 的基本数据分区是紧密相连的,所以需要对后面的分区向右移动才能进行扩容。
准备工作
-
首先需要对分区进行一个压缩,此处主要是数据分区。先在 Windows 里面用磁盘工具,把原来分区的尾部裁出来(右键此电脑 > 管理 > 磁盘管理 > 右键磁盘 > 压缩卷),大小选择为最大。
-
可以准备一个 Linux 的 Live CD,当然直接用磁盘上的 Linux 也可以,不过操作前记得卸载相应的分区(下面的操作基于 Live CD 环境)。
使用 dd 拷贝分区
dd 是一个简单粗暴的工具,不基于文件系统拷贝文件,而是直接复制硬盘上的 0 和 1,可以把分区整个拷贝下来。
fdisk -l # 查看硬盘上的分区信息
mount /dev/nvme0n1p5 /mnt # 挂载Linux主分区
dd if=/dev/nvme0n1p3 of=/mnt/opt/windows.img # 拷贝分区3(数据分区),保存在/opt/windows.img(请根据你实际的分区更改)
dd if=/dev/nvme0n1p2 of=/mnt/opt/msr.img status=progress # 拷贝分区2(保留分区),并且可查看进度
可以把输出进行压缩
dd if=/dev/nvme0n1p3 | gzip > windows.img
使用 fdisk 重新分区
fdisk /dev/nvme0n1 # 选中要操作的磁盘
进入交互环境后,可以用 m
获得帮助。我需要对 efi 进行扩容,所以用 p
先查看原来的情况。
Device Start End Sectors Size Type
/dev/nvme0n1p1 2048 206847 204800 100M EFI System
/dev/nvme0n1p2 206848 239615 32768 16M Microsoft reserved
/dev/nvme0n1p3 239616 ... ... ... Microsoft basic data
/dev/nvme0n1p4 ... ... ... ... Windows recovery environment
/dev/nvme0n1p5 ... ... ... ... Linux filesystem
记住 efi 起始扇区号,然后 d
删除第一个、第二个和第三个分区。再按 n
新建分区,number 是 1,起始扇区号填回原来的,大小选择 +1G
,这样相当于把原来的分区扩容到了 1 GB。
选择大小后会提示是否移除原有签名,选择“否”。
Do you want to remove the signature? [Y]es/[N]o: n
分区 2 的起始扇区号可以紧接着上一个分区,大小 +16M
,不过新建出来的分区默认类型是 Linux filesystem,可以用 t
更改成 Microsoft reserved。分区 3 也是同理。需要注意的是新建的分区不能比原来的小,不然 dd 无法写入。
修改完成后,先用 p
查看是否有误,无误后可以用 w
写入磁盘。
但是出去用 df -h
查看的话,会发现 efi 还是只有原来的大小,因为文件系统并没有进行扩容,需要单独用 fatresize
进行调整。
fatresize -s max /dev/nvme0n1p1
但是却提示。。。
GNU Parted cannot resize this partition to this size.We're working on it.
查了一下,好像是这个工具存在的 bug,我们直接挂载 efi,备份里面的文件,再重新格式化好了。
mkdir /mnt/part1
mount /dev/nvme0n1p1 /mnt/part1
cp -r /mnt/part1 /mnt/opt/
umount /mnt/part1
mkfs.fat -F32 /dev/nvme0n1p1 # 把efi格式化成FAT32
mkfs.ntfs /dev/nvme0n1p3 # 顺便把分区3格式化成NTFS
mount /dev/nvme0n1p1 /mnt/part1
cp -r /mnt/opt/part1/* /mnt/part1/
umount /mnt/part1
dd 复原分区
dd if=/mnt/opt/windows.img of=/dev/nvme0n1p3 # 复原Windows数据分区
dd if=/mnt/opt/msr.img of=/dev/nvme0n1p2 # 复原保留分区
gzip -dc windows.img | dd of=/dev/nvme0n1p3 # 从压缩过的文件进行复原
检查文件系统
fsck -r /dev/nvme0n1p3 # -r参数,如果检查有错则由使用者回答是否修复
修复 GRUB 引导
因为分区的 uuid 已经变了,所以需要更新 grub 配置。
检查一下 /mnt/etc/fstab
,正常来说如果扩容时没移除签名,fstab 则不用更新,否则 /boot
部分要更改成 efi 的新 uuid。
arch-chroot /mnt # 因为grub不在Live CD,需要chroot
mount /dev/nvme0n1p3 /mnt # 挂载Windows分区,不然探测不到。注意这里的/mnt目录是chroot之后的(原本Linux filesystem里面的)
grub-mkconfig -o /boot/grub/grub.cfg # 重新生成grub配置
如果没有探测到,请查看 /etc/default/grub
中是否已经取消下面的注释
GRUB_DISABLE_OS_PROBER=false
修复 Windows 引导
这时候还是不能进入 Windows,查看了一下 bcd 信息,发现 device 的路径丢失了 QAQ
下面的操作都在 Windows 恢复环境中进行
bcdedit /enum
输出如下
Windows 启动管理器
--------------------
标识符 {bootmgr}
device partition=\Device\HarddiskVolume3
path \EFI\Microsoft\Boot\bootmgfw.efi
description Windows Boot Manager
locale zh-CN
inherit {globalsettings}
default {current}
resumeobject {a3d......}
displayorder {current}
toolsdisplayorder {memdiag}
timeout 30
Windows 启动加载器
-------------------
标识符 {current}
device Unknown
path \Windows\system32\winload.efi
description Windows 10
locale zh-CN
inherit {bootloadersettings}
recoverysequence {a3d......}
displaymessageoverride Recovery
recoveryenabled Yes
isolatedcontext Yes
allowedinmemorysettings 0x15000075
osdevice Unknown
systemroot \Windows
resumeobject {a3d......}
nx OptIn
bootmenupolicy Standard
可以看见启动加载器的 device 和 osdevice 的值丢失了,需要手动重设。
打开 diskpart,查看盘符
diskpart # 进入交互模式
DISKPART> list vol # 列出所有卷
卷 ### LTR 标签 FS 类型 大小 状态 信息
---------- --- ----------- ----- ---------- ------- --------- --------
卷 0 C NTFS 磁盘分区 228 GB 正常 启动
... ... ... ... ... ... ... ...
DISKPART> exit
我的卷 0 是系统分区,分配了卷标 C,所以需要重设为 partition=C:
bcdedit /set {current} device partition=C:
bcdedit /set {current} osdevice partition=C:
至此 bcd 修复完成,重启即可恢复正常引导。