1. 为什么我把分区扩容这件事交给 GParted Live
先把话说明白:GParted 是一个图形化的分区编辑器,跑在独立的小型系统里,专门用来干“改分区表、调文件系统大小、挪分区位置”这些在正常运行的系统里不敢碰的活。所谓 Live ISO,就是把它做成一张可启动光盘镜像,写进 U 盘后从 U 盘引导,整个操作过程目标硬盘一块都没挂载,改哪儿都不会被内核缓存绊住。分区扩容这件事,本质上是“先让文件系统认识更大的地盘,再让分区表把地盘划给它”,顺序错一步,轻则报错,重则整块盘的数据结构对不上号。
我接触这个工具是从一次很典型的窘境开始的:一台跑测试服务的机器,根分区给了 40 GiB,日志和容器镜像一涨,天天告警;旁边的 /home 分了 460 GiB,实际只用了 60 GiB。想把 /home 的闲置空间匀 30 GiB 给根分区,用系统自带的磁盘工具根本做不到——它只能扩,不能缩,更不会帮你把分区整体挪个位置。最后是靠 GParted Live 的“缩小、移动、扩展”三连解决的。
这篇东西写给谁看?一类是有点 Linux 底子、能看懂lsblk和fstab,但从没亲手动过分区的朋友;一类是运维、测试岗,手上机器多、磁盘告警频繁,需要一个能照着做的流程;还有一类是折腾双系统的玩家,Windows 那边磁盘管理划不出相邻未分配空间时,得靠外部工具救场。我会把原理、步骤、参数计算和踩过的坑都摊开讲,能直接抄的部分尽量给到命令和数值。
1.1 一个具体到扇区的需求场景
还是上面那台机器,布局是这样的:/dev/sda1是 EFI 分区 512 MiB,/dev/sda2是 /boot 1 GiB,/dev/sda3是根分区 40 GiB,/dev/sda4是 /home 占了剩下全部空间。目标是根分区变成 70 GiB。
很多人第一反应是“把 sda4 缩小 30 GiB 不就行了”。缩完你会发现,空出来的 30 GiB 落在 sda4 的右边,也就是磁盘末尾,而根分区 sda3 在 sda4 左边,中间隔着整个 /home,这块空闲空间跟 sda3 根本不挨着。分区扩容有一条铁律:空闲空间必须紧邻目标分区的边界,否则没法合并。所以真正要做的动作是三步:先把 sda4 从右侧缩小 30 GiB,再把缩小后的 sda4 整体向右平移 30 GiB,让空闲空间“挪”到 sda3 的屁股后面,最后把 sda3 的右边界推过去吃掉这 30 GiB。
为什么不能反过来先扩 sda3?因为 sda3 右边紧挨着 sda4 的起始扇区,那里没有一字节空闲。分区是磁盘上一段连续扇区区间,不是文件,不能“挤一挤”。这个约束听起来笨,但它恰恰是分区表这种数据结构的本质:一张表记录“第几号分区从第几个逻辑块开始、到第几个逻辑块结束”,想改长度,只能改边界,而边界不能重叠。
顺便把单位的事说清楚,免得后面看参数犯迷糊。分区工具里显示的是 MiB/GiB,进制是 1024;硬盘厂商标的是 GB/TB,进制是 1000。一个标称 512 GB 的盘,在 GParted 里看到的大约是 476.94 GiB。40 GiB 的分区,在系统df -h里显示约 39G,在 Windows 磁盘管理里显示约 42.9 GB,三个数字说的是同一块地方。做扩容计算时统一用 MiB,别在 GB 和 GiB 之间来回换算,很容易多划或少划几百兆。
1.2 分区扩容到底改了哪几样东西
把一次扩容拆开看,磁盘上真正发生变化的东西只有三处。第一处是分区表项:起始 LBA 和扇区数量这两个字段被改写,GPT 情况下还要重算分区表头与表项的 CRC32 校验和。第二处是文件系统的元数据:以 ext4 为例,超级块里记录块总数、每个块组的块位图和 inode 位图、备份超级块的位置,扩容就意味着在末尾追加新的块组,并把超级块里的总块数改大。第三处是可能被动到的引导相关数据——如果分区被移动,分区起始扇区变了,那些靠物理位置找引导代码的老式引导方式就会失联。
顺序上有个容易搞反的地方。扩容是“先动分区表,再动文件系统”:分区表先把地盘划大,文件系统再去做“我地盘变大了”的登记。缩小正好相反:得先让文件系统把自己缩到目标大小以内,确认没有数据落在将被切掉的那段扇区上,然后才敢改分区表。GParted 在图形界面里把这两件事封装好了,你看到的是一个“Resize/Move”对话框,背后它按正确顺序调用e2fsck、resize2fs、ntfsresize和 libparted 的接口。但你在命令行手工做的时候,顺序错了就是灾难。
还有一个几乎所有人都关心的问题:扩容会不会改 UUID?不会。ext4 的 UUID 存在超级块里,跟着文件系统走,分区边界变化不影响它;GPT 分区的 PARTUUID 是分区表里的 GUID,只要不删除重建分区,也不变。这意味着/etc/fstab里用 UUID 挂载的条目扩容后照常生效。真正会变 UUID 的操作是“删除分区再新建一个占住同样位置”,这也是我一直劝人别用这种“土办法”扩容的原因。
1.3 为什么必须在 Live 环境里动刀
根分区正在被挂载使用的时候,内核手里握着一份分区表和文件系统的缓存视图。你在另一个终端里把分区表改了,内核不会立刻感知,它仍然按旧表去读写块设备。结果就是写入的偏移量全部错位,文件系统当场崩掉,而且这种崩不是“报个错”那么客气,是超级块和实际数据对不上,恢复起来极其痛苦。ext4 支持在线扩容(挂载状态下resize2fs可以变大),但不支持在线缩小,这是文件系统设计的硬限制,不是工具不给力。
Live 环境的价值就在这儿:从 U 盘启动后,目标磁盘处于完全未挂载状态,没有内核缓存,没有日志回放,没有某个进程正在写文件。GParted 可以放心地对分区表做修改,改完再让文件系统自己去认。同一个思路的替代方案还有几种:进救援模式(rescue mode)、用另一块盘上的系统启动、把盘拆下来挂到别的机器上。但对绝大多数人来说,U 盘 Live 是最省事的路径,不需要拆机,不需要第二套系统。
还有个细节值得提一句:GParted Live 自带的那套系统非常小,启动后全部加载进内存,运行起来对硬盘零写入。这意味你操作过程中如果拔掉 U 盘,系统照样跑(当然别这么干)。它的内核版本相对较新,对 NVMe、新芯片组主板、USB4 硬盘盒的兼容性比很多老发行版的安装镜像要好,这也是我建议尽量用最新版镜像的原因——用两年前的镜像去认今年的笔记本,大概率看不到硬盘。
2. 动手前的认知准备:分区表、文件系统与对齐
很多人失败不是因为手抖,是因为对底层结构没概念,界面上一顿拖,拖完不知道发生了什么。这一节把三个必须先搞明白的东西讲透:分区表类型决定了你能划几个分区、能支持多大盘;文件系统类型决定了你能不能缩、能缩到多小;对齐方式决定了扩容后性能会不会莫名其妙掉一截。
2.1 MBR 与 GPT 的分水岭
MBR 是老结构,分区表就存在磁盘最前面那 512 字节里,其中 446 字节是引导代码,64 字节是四个分区表项,每个 16 字节。四个表项,就是四个主分区的由来。想超过四个,只能把其中一个主分区做成“扩展分区”,里面再套逻辑分区,逻辑分区的表项用链表串起来。这套设计在几十年前够用,现在处处掣肘:单盘最大寻址 2 TiB,分区数量受链表结构限制,分区表本身没有校验,坏了就是坏了。
GPT 是后来者,分区表头在 LBA 1,表项从 LBA 2 开始,默认留 128 个表项、每项 128 字节;磁盘末尾还存了一份备份表头和备份表项,两边都有 CRC32 校验。好处很直接:分区数量基本够用,容量上限大到没有实际意义,分区表损坏时可以用备份恢复,每个分区有独立 GUID,不依赖“第几号分区”这种脆弱的编号。代价是老式 BIOS 不认 GPT,需要一块很小的保护性 MBR 来做兼容。
这里有个特别容易踩的坑:磁盘末尾的备份 GPT。你把最后一个分区一直扩到磁盘物理末尾,备份表头原本待的那个位置就被占了,分区表结构变得不自洽。GParted 一般会自己处理,把备份表挪到新位置,但如果中途出过异常,parted -l会报 “fix the GPT to use the backup” 之类的提示。命令行下用sgdisk -e /dev/sda把备份表移到磁盘末尾,或者sgdisk -v先做一次体检。你要是用fdisk看到 “GPT PMBR size mismatch”,基本就是这个症状。
| 对比项 | MBR | GPT |
|---|---|---|
| 主分区数量 | 最多 4 个,超出需扩展分区 | 默认 128 个 |
| 单盘容量上限 | 2 TiB | 极大,实际不受限 |
| 分区表校验 | 无 | CRC32,头与表项各一份 |
| 备份位置 | 无备份 | 磁盘末尾存备份表 |
| 引导依赖 | BIOS + 引导代码写在 MBR | UEFI + EFI 系统分区 |
| 扩容到 2 TiB 以上 | 不支持,必须先转换 | 支持 |
MBR 转 GPT 不是改个标志位那么简单。有数据的盘转换,得靠sgdisk或 GParted 的转换功能重建表结构,过程涉及把逻辑分区“提升”为主分区,中途任何一步出错都可能丢分区。我的做法是:能不动就不动,如果盘小于 2 TiB 且没有扩容到 2 TiB 以上的需求,MBR 继续用着也没问题;真要转,先做全盘镜像,别信“无损转换”四个字。
2.2 文件系统决定你能不能“缩”
分区表只管“这块地从哪到哪”,真正存数据的是文件系统。扩容和缩小这两个动作,文件系统的支持程度天差地别。同样是“调大小”,有的文件系统只能长大,有的能缩但要满足一堆前提,有的干脆不支持离线缩。
ext4 是最常见也最好说话的:能扩能缩,缩之前必须做一次强制检查(e2fsck -f),确保没有残留的日志事务和错误标记,否则resize2fs会拒绝干活。它的最小尺寸取决于现有数据分布,尤其是 inode 表和块位图的位置,所以实际能缩到多少,得让工具自己算,别自己拍脑袋填数字。XFS 只能扩不能缩,这是它设计时就定下的规矩,扩容必须在挂载状态下用xfs_growfs执行,靠的是文件系统内部的分配组机制。Btrfs 能扩,缩只能在挂载状态下操作,离线环境里反而没法缩,跟 ext4 正好反过来。NTFS 两头都能动,但前提是文件系统必须“干净”——Windows 快速启动、休眠、没做完的 chkdsk 都会让它拒绝被处理。
| 文件系统 | 扩大 | 缩小 | 关键前提 |
|---|---|---|---|
| ext4 | 支持,在线或离线 | 支持,需离线 | 缩前e2fsck -f,不可小于数据占用量 |
| XFS | 支持,必须挂载状态 | 不支持 | 用xfs_growfs,不能离线扩 |
| Btrfs | 支持,可在线 | 支持,仅挂载状态 | 离线环境不能缩 |
| NTFS | 支持 | 支持 | 关闭快速启动与休眠,chkdsk /f通过 |
| FAT32 / exFAT | 支持 | 支持 | 基本无额外前提 |
| swap | 不建议调整 | 不建议调整 | 直接重建更省事 |
swap 分区我要单独说一句。很多人扩容时发现 swap 卡在中间,导致空闲空间不连续,就想把它挪走。swap 里的数据没有任何保留价值,正确做法是swapoff后直接删掉分区,扩完再在合适位置新建一个,改/etc/fstab里对应的 UUID。比“调整 swap 大小”这种操作干净得多,也快得多。
2.3 1 MiB 对齐与扇区换算
这是最容易被忽略、又实实在在影响性能的一环。机械硬盘时代讲“柱面对齐”,SSD 时代讲的是“擦除块对齐”。SSD 内部按页读写、按块擦除,如果一个分区的起始位置没有落在闪存页边界上,一次逻辑写入可能触发两个物理页的读改写,写放大上去了,寿命和速度都受影响。现在的通用做法是让分区起始于 1 MiB 的整数倍位置,也就是 2048 个 512 字节扇区,或者 256 个 4K 扇区。
GParted 默认就按 MiB 对齐,你在对话框里填 “30 GiB”,它会自己把边界吸附到对齐位置。但如果你手动切到“扇区”视图,自己填起始扇区,就得保证那个数字是 2048 的倍数。我见过有人为了“精确”填了个 2047 或 2050,性能测试跑出来 4K 随机写掉了三成,查了半天以为是驱动问题,最后发现是对齐偏了。
具体到大小换算,resize2fs和 GParted 认的都是块和 MiB。1024 MiB 等于 1 GiB,这个没歧义。但要注意 GParted 里输入的数值是“分区新大小”,不是“增加多少”。比如根分区现在 40 GiB,想变成 70 GiB,输入的是 71680 MiB,不是 30720 MiB。界面上会有 “Free space preceding” 和 “Free space following” 两个数字,前者是分区左边留多少空闲,后者是右边留多少。缩小 sda4 时把 following 设成 30720 MiB,就相当于从右边切掉 30 GiB。
还有个经验值:ext4 分区别缩到使用率的 100%。resize2fs算最小尺寸时会留一点余量,但如果你把分区缩到跟已用数据几乎一样大,后续系统跑起来立刻又满,等于白折腾。我一般按“已用空间 × 1.3”来估目标大小,实在拿不准就多留 5 到 10 GiB。根分区尤其如此,日志、包管理器缓存、内核更新都会往里写,留出 15% 以上的空闲比较稳妥。
3. Live ISO 的制作与启动
镜像制作这一步,翻车率其实比分区操作本身还高。我见过写盘写到一半拔 U 盘的,见过拿存着资料的 U 盘直接开写的,也见过用老版本镜像启动后认不出 NVMe 硬盘、在 GParted 界面里对着一块空磁盘发呆的。这一节把从下载到进入桌面的每一步都过一遍。
3.1 镜像获取与完整性校验
GParted Live 的镜像在项目官网发布,选amd64架构的 ISO,大小通常在三四百兆。版本选择上有个原则:新硬件用新版本。镜像里的内核版本决定了它能认出多少种存储控制器,太老的镜像碰上新的芯片组或者 USB 转接方案,会出现“启动成功但看不到硬盘”的情况。反过来,特别老的机器(十几年前的)可能反倒需要旧版本,因为新内核砍掉了一些老驱动。
下载完先校验,这一步别省。用sha256sum对一下官网公布的摘要值,一个字符都不能差。镜像下载不完整、被中间环节篡改,写进 U 盘后可能启动到一半内核 panic,你在那儿排查半天 BIOS 设置,其实是镜像本身就坏了。
sha256sum gparted-live-*.iso # 与官网公布的校验值逐位比对3.2 写盘:dd 与图形工具的选择
Linux 下最直接的是dd。设备名一定要确认,/dev/sdX写错一个字母就是把自己系统盘覆盖掉。写之前先用lsblk看清楚 U 盘是哪个设备,拔插一次对比前后输出是最稳的确认方式。
lsblk -o NAME,SIZE,TRAN,MODEL sudo dd if=gparted-live-amd64.iso of=/dev/sdX bs=4M status=progress oflag=sync syncbs=4M是经验值,太小速度上不去,太大内存占用高;oflag=sync保证写完的数据真正落盘再返回;最后的sync是双保险。图形工具那边,balenaEtcher 一路下一步就行,Rufus 要注意模式选择——GParted Live 的镜像是混合镜像,选 DD 模式写入,别选 ISO 模式,后者会尝试改造引导结构导致启动失败。
写完 U 盘插回电脑,你会看到它容量变小了,只剩几百兆,里面是一堆启动文件。这是正常的,镜像把 U 盘前部当作光盘结构写入了。想恢复成普通 U 盘,用分区工具把整盘重新格式化成 exFAT 就行。别拿存着重要资料的 U 盘干这个事,写盘过程是无条件覆盖,没有回收站。
3.3 启动参数、Secure Boot 与显示问题
开机进固件设置,把 U 盘调到启动顺序第一位,或者开机时按启动菜单键临时选择。UEFI 和 Legacy 两种模式,具体用哪个取决于你目标系统原本的引导方式——如果原系统是 UEFI + GPT,用 UEFI 模式启动 Live 环境,两者看到的分区结构一致,操作起来不容易出岔子。
Secure Boot 是常见的拦路虎。部分版本的 GParted Live 没有做 Secure Boot 签名,固件会直接拒绝引导,屏幕上可能只显示一行简短的拒绝信息。解决办法是在固件设置里临时关闭 Secure Boot,操作完再打开。这是临时措施,不是让你永久关掉。
启动菜单里通常有几个选项:默认启动、进内存运行、安全图形模式、以及各种分辨率参数。如果启动后花屏或者黑屏,选带nomodeset的那一项,强制用固件的简易显示模式。键盘布局那一步按实际情况选,选错了顶多是打字时符号对不上,不影响鼠标操作。语言选中文或英文都行,英文界面的术语更统一,我个人习惯用英文,查报错信息时方便对照。
进入桌面后第一件事不是打开 GParted,而是开个终端确认硬件识别情况:
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS,MODEL sudo parted -l sudo blkidlsblk能看到目标盘和分区,说明控制器和驱动没问题;看不到,先换 USB 口(优先用主板后置口,别用前面板或扩展坞),再不行就换更新的镜像版本。parted -l会把分区表类型、每个分区的起止扇区、文件系统类型都列出来,这份输出最好截图存下来,它是你操作前的“基线”,出问题时能对照。
4. 扩容实战:从缩小到扩展的完整流程
好,进入正题。下面这套流程我按“备份、采集、排队、执行、验证”五段走,中间会穿插参数怎么算、为什么这么点。整个操作是在 Live 环境里完成的,所有命令都以 root 身份执行。
4.1 备份与信息采集:花 10 分钟省 10 小时
分区操作是有风险的动作,动之前先做三件事。第一,重要数据拷到另一块物理盘上,别拷到同一块盘的其他分区——盘要是真出问题,同一块盘上的分区一起完蛋。第二,备份分区表。GPT 用sgdisk,MBR 用sfdisk,输出文件存到 U 盘或者另一块盘。
sudo sgdisk --backup=/mnt/usb/sda-gpt-backup.bin /dev/sda sudo sfdisk -d /dev/sda > /mnt/usb/sda-sfdisk-backup.txt sudo dd if=/dev/sda of=/mnt/usb/sda-mbr.bin bs=512 count=1第三条命令是给 MBR 盘准备的后路,只备份前 512 字节,也就是引导代码加分区表,体积小到可以忽略。真出了分区表错乱,用sgdisk --load-backup或者dd写回去,至少能把分区结构恢复原样,数据还在。
第三,记录当前状态。blkid的输出全部存下来,里面是每个分区的 UUID 和 TYPE;/etc/fstab复制一份;df -h和lsblk -f各截一张图。这些东西在扩容后核对“有没有变化”时特别有用。UUID 理论上不变,但你要有办法证明它没变,而不是凭印象。
4.2 操作队列:GParted 的“先排程后执行”
GParted 有个设计跟大多数人的直觉相反:你在界面上做的每一个操作,比如缩小、移动、删除、新建,都不会立刻执行,而是加进一个操作队列,界面上以“待处理操作”的形式列在下方。所有操作排完之后,点工具栏上那个绿色对勾,才真正开始写磁盘。这个设计的好处是你能在动手前完整看一遍自己的操作序列,坏处是无数人点完“Resize/Move”看没反应,以为软件卡了,重复点了好几次。
队列里的操作可以撤销,点撤销箭头一步步回退即可。但一旦点了应用,就没有撤销了,磁盘上的数据是真的在搬。所以在点对勾之前,把队列里的条目从上到下读一遍,确认顺序符合预期。GParted 会按队列顺序依次执行,如果顺序排错了,比如先扩后缩,它会自己做依赖检查并拒绝执行,但更常见的情况是顺序“能跑通但结果不是你想要的”,这种最麻烦。
我的习惯是分批执行。缩小和移动属于高风险动作,因为它们涉及数据搬移;扩展属于低风险动作,只是改边界。所以我会先把“缩小 sda4、移动 sda4”排进队列执行完,看一下结果,确认没问题,再把“扩展 sda3”作为第二批执行。中间多花几分钟,但万一第一批出岔子,损失范围小得多。
| 操作阶段 | 操作内容 | 风险等级 | 耗时特征 |
|---|---|---|---|
| 第一批 | 缩小 sda4 右侧 30 GiB | 中 | 取决于文件系统检查速度 |
| 第一批 | 将 sda4 整体右移 30 GiB | 高 | 与 sda4 数据量正相关,可能很久 |
| 第二批 | 扩展 sda3 至 70 GiB | 低 | 秒级到分钟级 |
| 收尾 | 检查文件系统、核对 UUID | 低 | 秒级 |
4.3 缩小分区:先让文件系统瘦身
选中/dev/sda4,右键选 “Resize/Move”。对话框上方是拖动条,下方有三个输入框:新大小、前置空闲、后置空闲。目标是右边空出 30720 MiB,所以把“Free space following”填成 30720,新大小会自动算出来。这里的数字别自己手算,让对话框联动,改一个另外两个跟着变,能避免加减错误。
填完之后点 “Resize/Move”,操作进入队列。这时候 GParted 可能会弹一个警告,说文件系统将被缩小,部分数据可能丢失。这个警告是模板化的,必弹,跟你的操作是否安全无关。真正要看的是有没有弹出文件系统检查的提示——ext4 缩小前必须做e2fsck -f,GParted 一般会自动跑,跑完没问题才继续。如果检查报错,比如超级块损坏、块位图不一致,那说明文件系统本身就有问题,先停下来处理错误,别硬着头皮缩。
注意:缩小操作在队列里执行时,界面会显示进度条和一个“正在执行”的提示。这个阶段绝对不能断电、不能拔 U 盘、不能强制关机。如果卡住超过预期时间(比如缩一个 100 GiB 的分区超过一两个小时),先看磁盘指示灯有没有在闪,有闪就继续等,闪都不闪了再考虑强制结束。
执行完之后,GParted 界面上 sda4 会变短,右边出现一块灰色的“unallocated”。这块空闲空间目前还挨着 sda4 的尾部,离 sda3 隔着整个 sda4,下一步就是把它挪过去。
4.4 移动分区:把空闲空间“推”到目标身边
再次选中 sda4,右键 “Resize/Move”。这次要动的是位置,把整个分区的左边界往右拖,或者直接在 “Free space preceding” 里填 30720 MiB。注意,填前置空闲意味着分区整体向右平移,分区大小不变,但起始扇区变了。GParted 会实时显示新的起始扇区号,确认它是不是 2048 的整数倍,正常默认就是对齐的。
这一步是整个流程里最慢、也最危险的操作。它不像扩展那样只改边界,而是要把分区里的数据从头到尾搬一遍,因为分区在磁盘上的物理位置变了。搬多少数据,就耗时多久,跟分区总大小关系不大,跟实际占用关系大——一个 460 GiB 但只用了 60 GiB 的分区,移动时间主要花在那 60 GiB 上。机械盘上,60 GiB 可能跑几十分钟;SSD 快一些,但也不是秒级的事。移动期间如果断电,分区里会有一段数据处于“已写新位置、未写新位置”的中间态,这就是分区损坏的来源。所以这一步我建议接上 UPS,或者至少确保笔记本电池有电。
界面上会有一个细节:当你拖动分区位置时,如果起始扇区显示的不是对齐值,GParted 会标红提示。看到红色就手动把数值调回 2048 的倍数,别无视。
移动执行完,磁盘布局变成:sda3 后面跟着 30720 MiB 的未分配空间,然后是向右平移过的 sda4。空闲空间终于紧挨着根分区了。
4.5 扩展分区与文件系统同步
选中 sda3,右键 “Resize/Move”,把右边界往右拖到底,吃满那块 30 GiB 的空闲空间,或者直接在 “Free space following” 里填 0,让新大小等于 40 GiB 加 30 GiB。点确定,队列里多了一条“grow sda3 from 40960 MiB to 71680 MiB”。
这个操作快得多,因为不涉及数据搬移,只是改分区表项,然后让文件系统在后面追加新的块组。GParted 会自动调用resize2fs完成文件系统层面的扩容,你不需要单独再跑命令。如果你是在命令行里手工做,顺序是:先用parted或sfdisk改分区表,再e2fsck -f检查,最后resize2fs /dev/sda3。少跑一步,df -h看到的空间就不会变,因为文件系统还不认这块新地盘。
扩展完成后,界面上 sda3 变长,未分配空间消失。点一下“Information”(快捷键可以看分区详情),确认文件系统大小和分区大小一致。不一致就说明resize2fs没跑成功,需要手工补一次。
4.6 LVM 与加密卷的特殊处理
上面讲的是普通分区。如果根分区上面套了 LVM,操作要多几层。分区这层扩容之后,物理卷(PV)还没认到新空间,得先pvresize;接着卷组(VG)里多出空闲的物理扩展块,要lvextend给逻辑卷;最后才是resize2fs扩文件系统。三步缺一不可,只看df -h没变化就以为失败,其实是卡在中间某一步。
sudo pvresize /dev/sda3 sudo pvs sudo lvextend -l +100%FREE /dev/vg0/root sudo resize2fs /dev/mapper/vg0-root df -h /LUKS 加密卷更绕。GParted 对加密容器内部的文件系统支持有限,稳妥做法是在 Live 环境里先用cryptsetup open把加密卷解锁,得到/dev/mapper/xxx设备,再对这个映射设备做resize2fs。分区层扩容照常用 GParted 做,加密层用cryptsetup resize让容器认到新大小,最后才扩文件系统。顺序搞错的话,文件系统会以为自己还是原来的大小,扩了等于没扩。
5. 常见问题与排查速查
这一节是我这些年攒下来的报错清单。有些是工具本身的限制,有些是操作环境的问题,有些是硬件层面的坑。按症状来找,能省不少排查时间。
5.1 未分配空间不相邻,扩不上去
最常见的一个:“我看到磁盘末尾有一大块 unallocated,为什么不能扩到根分区?”原因前面讲过,空闲空间必须紧邻。解决办法只有两个:要么移动中间的分区,把空闲空间挪过去(慢、有风险),要么把中间的分区缩掉一部分,让空闲空间从它尾部延伸到目标分区旁边。
还有一种变体:两块未分配空间被一个分区隔开,想把它们合并成一块。GParted 不支持跨分区合并空闲空间,只能把中间那个分区移走或删掉。如果中间那个分区恰好是 swap,删了重建最省事;如果是存数据的分区,就得衡量一下移动的耗时和风险值不值。
我遇到过一个更隐蔽的情况:空闲空间看起来挨着,但起始扇区差了几个,界面上显示是连着的,实际上中间有不到 1 MiB 的缝隙没对齐,GParted 就拒绝扩展。这种时候切到扇区视图,把目标分区的结束扇区和新分区的起始扇区对一下,差多少补多少,或者干脆让 GParted 自己用拖动条吸附。
5.2 文件系统检查失败与 NTFS 占用
ext4 缩小时报“文件系统有错误,请先运行 e2fsck”,这不是工具在刁难,是它在保护你。手工跑一次强制检查,把错误修掉:
sudo e2fsck -f -y /dev/sda4-f是强制检查,即使文件系统看起来干净也走一遍完整流程;-y是对所有询问自动回答 yes。修完再回到 GParted 重试。如果e2fsck报大量错误、修不完,那说明文件系统本身已经有严重问题,这时候别继续做分区操作,先把数据抢救出来。
NTFS 的坑主要在“不干净”上。Windows 的快速启动功能会让关机时文件系统处于休眠状态,GParted 一看就拒绝处理,提示需要先关闭休眠。处理方式是在 Windows 里以管理员身份跑两条命令:
powercfg /h off chkdsk C: /f第一条关掉休眠文件,第二条安排一次磁盘检查,需要重启才执行。重启进 Windows 让它把检查跑完,再正常关机(不是重启,是关机),然后才去 Live 环境操作。少做一步,GParted 那边就还是那句“NTFS is hibernated”。
5.3 扩容后起不来:引导与挂载的排查顺序
理论上 UUID 不变,扩容后应该能正常启动。但如果操作过程中误删了分区、重建了分区,或者动了/boot所在的位置,启动就可能失败。排查顺序按这个走:
第一步,看是卡在引导阶段还是内核阶段。屏幕停在引导菜单,说明引导器配置有问题;能看到内核日志再报错,说明引导没问题,是挂载或文件系统的问题。
第二步,进 Live 环境挂载检查。blkid看 UUID 有没有变,跟之前备份的输出对比。变了就改/etc/fstab对应条目,或者用UUID=改成新的值。/etc/fstab里如果用PARTUUID=,也要同步改。
第三步,挂载根分区并chroot进去重装引导:
sudo mount /dev/sda3 /mnt sudo mount /dev/sda2 /mnt/boot sudo mount /dev/sda1 /mnt/boot/efi sudo mount --bind /dev /mnt/dev sudo mount --bind /proc /mnt/proc sudo mount --bind /sys /mnt/sys sudo chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg grub-install /dev/sda exitUEFI 系统还要确认 EFI 分区里的引导文件还在,必要时用efibootmgr重建启动项。双系统用户如果动过 Windows 分区,可能需要在 Windows 恢复环境里跑bcdboot修复它自己的引导记录——两个系统各修各的,别指望一个工具全包。
5.4 报错速查表
| 界面/命令报错 | 大概率原因 | 处理办法 |
|---|---|---|
| Unable to satisfy all constraints on the partition | 边界被相邻分区占住,或对齐不满足 | 切扇区视图核对起止位置,先移动相邻分区 |
| The filesystem is not clean | ext4 有未完成事务或错误标记 | e2fsck -f -y强制检查 |
| NTFS is hibernated / has inconsistencies | Windows 快速启动或休眠未关闭 | 关休眠、跑chkdsk /f、正常关机 |
| Could not perform this operation | 分区被挂载或内核仍持有旧表 | 确认 Live 环境未挂载,必要时重启 Live |
| GPT PMBR size mismatch | 备份 GPT 位置与实际磁盘末尾不符 | sgdisk -e /dev/sda或sgdisk -v检查 |
| Can't have a partition outside the disk | 分区表记录的结束位置超出磁盘容量 | 用parted打印确认,考虑sgdisk -e修复 |
| resize2fs: Nothing to do | 分区表改了但文件系统没扩 | 手工跑resize2fs /dev/sdXN |
| 启动进入 emergency mode | /etc/fstab里的 UUID 找不到对应设备 | 核对blkid,更新 fstab 或恢复分区 |
6. 我踩过的坑和几条硬规矩
流程讲完了,剩下的都是我这些年真金白银换来的经验。这些内容在任何官方文档里都不会写,但恰恰是决定你这次操作是“顺利收工”还是“通宵救数据”的分水岭。
6.1 移动分区之后必须确认的三件事
移动分区这个动作,表面上只是改了起始扇区,实际上牵连的东西比想象中多。我每次移动完都会确认三件事。
第一,文件系统挂载后df -h显示的容量对不对。数字对不上,说明分区表和文件系统两层没同步,可能还需要跑一次resize2fs。
第二,blkid输出的 UUID 有没有变。变了就改/etc/fstab,别嫌麻烦,改完再mount -a验证一遍,确认没有报错再重启。
第三,如果是双系统,进一次 Windows 看能不能正常启动。移动分区有可能影响 Windows 的引导记录,尤其是老式的 BIOS + MBR 布局,引导代码依赖物理位置。真起不来就进恢复环境修复,别慌。
还有一条:移动分区会改变分区的物理位置,但不会改变分区里的数据内容。所以文件校验和、数据库文件、虚拟磁盘镜像这些东西搬完之后应该完全一致。如果你发现某个文件损坏了,那说明移动过程中出过问题(通常是断电或硬盘坏道),不是“移动”这个操作本身的锅。
6.2 电源、接口与硬盘盒:硬件层面的隐形杀手
分区操作对硬件的稳定性要求比日常使用高得多。日常读写一两次失败,文件系统还能靠日志恢复;分区操作中间断一次,可能就是结构性损坏。所以有几条硬件规矩我一直守着。
第一,笔记本必须插电源,别指望电池。扩容大分区可能跑一两个小时,电池撑不住。台式机有条件就接 UPS,没有的话至少别在用电高峰期做这种操作。
第二,别用 USB 硬盘盒或转接线做移动分区。转接方案的稳定性参差不齐,长时间高负载读写时掉盘的概率比内置接口高得多。真需要处理外置盘,尽量用直连 SATA 或者质量可靠的硬盘盒,并且在整个过程中别碰线。
第三,操作期间别让机器休眠。Live 环境的电源管理有时不完善,长时间无操作会黑屏甚至挂起,分区操作跑到一半被挂起,醒来就是灾难。在 Live 桌面里把电源管理关掉,或者隔一会儿动一下鼠标。
6.3 分区表备份:一块盘的事,别嫌小
sgdisk --backup生成的那个文件只有几 KB,但它能在最坏的情况下救你整个分区布局。我见过分区表被误操作覆盖、分区全部“消失”的场面,数据其实还在磁盘上,只是没人告诉系统它们在哪。这时候把备份的分区表写回去,重启,分区原样回来。
备份文件一定放在另一块物理盘上,别放在正在操作的那块盘的分区里。放 U 盘、放网络存储、发自己邮箱,都行,就是别放同一块盘。恢复的命令也一并记下来:
sudo sgdisk --load-backup=/mnt/usb/sda-gpt-backup.bin /dev/sda sudo partprobe /dev/sdaMBR 的恢复更粗暴,把备份的 512 字节写回去就行:dd if=sda-mbr.bin of=/dev/sda bs=512 count=1。写之前确认磁盘上没有别的分区表结构在等着被覆盖。
最后分享一个我常用的练手方法:别拿生产机当试验田。找一台闲置机器,或者用虚拟机挂一块虚拟磁盘,把“缩小、移动、扩展”这套流程完整走一遍,包括故意制造一次失败(比如缩到比数据还小、中途取消操作),看看报错长什么样、怎么恢复。在虚拟机上把坑踩完,真机上就能一次做对。分区操作这东西,看十遍教程不如自己完整跑一遍,因为界面上的每个提示、每次等待、每个弹窗,只有亲手点过才知道哪些该停、哪些该继续。