extend filesystem 这件事在Linux服务器维护里几乎算得上必考项目。尤其是 root 分区满了服务起不来日志写不进去人还在异地那种压力只有经历过的人才懂。这篇文章我打算一次性把 Linux 上扩展文件系统的完整路径理清楚既有 root 根分区的 LVM 在线扩容实操也有非 LVM 分区的处理方式同时把 ext4、xfs 两种主流文件系统的扩容差异讲明白。文章面向的人群很明确——刚接手服务器运维的同行、自己搭过 NAS 或 HomeLab 的玩家以及被磁盘满报警逼到不得不动手的开发者。只要你照着做最后能看到 df -h 里的空间数字真正变大而不是好像扩了但系统不认。1. 扩展文件系统前需要想清楚的三件事1.1 从磁盘-分区-文件系统三层结构说起很多人在扩容时翻车不是因为命令敲错而是脑子里对扩的是哪一层没有概念。物理服务器或者虚拟机里的磁盘先要被系统识别为一块块块设备比如 /dev/sda、/dev/sdb然后块设备上要建立分区比如 /dev/sda1、/dev/sda2最后分区之上才挂载或承载文件系统ext4、xfs 这类才算文件系统。日常使用的 df -h 看到的是文件系统这一层的使用率lsblk 看到的是分区和块设备这一层的结构fdisk -l 则是同时把两者之间的关系列出来。扩容的本质是让最上层的文件系统获得更多空间但空间不会凭空出现必须从下面一层一层的喂上来。磁盘扩容了分区不扩文件系统不会感知分区扩了LVM 的物理卷和逻辑卷不动文件系统同样无感。这就是很多人扩了半天 df 没变化的根本原因。1.2 LVM 和传统分区是两条完全不同的路线Linux 安装时如果选了自动分区大多数发行版默认会用 LVM 方案尤其是 RHEL、CentOS、RockyLinux 系列。LVM 的经典结构是物理卷PV→ 卷组VG→ 逻辑卷LV最后在 LV 上格式化出文件系统。它的好处是像搭积木一样把多块磁盘的空间汇入一个池子卷组再从池子里切出任意大小的逻辑卷。扩容时只需把新磁盘变成 PV加入 VG再给 LV 增加空间最后刷新文件系统全程在线不需要停机。但如果当初安装时用的是标准分区比如只创建了 /dev/sda1 挂载 /那扩容路径就完全不同了。你只能把分区本身扩大然后直接扩展文件系统。整个过程要涉及分区表重建风险比 LVM 高不少操作前必须有充分备份。所以拿到一台服务器第一件事就是分清走的是哪条路线而不是直接上网抄一条 lvextend 命令。1.3 文件系统类型决定了最后一步的刷新生效命令就算 LVM 层面已经把 LV 扩大了文件系统也不会自动感知新空间。最后一步必须针对文件系统类型执行扩展命令。ext4 家族ext3/ext4用 resize2fsxfs 用 xfs_growfs两者不能混用。特别提醒一下resize2fs 既可以扩大也可以缩小分区但 xfs 只能扩大不能缩小。生产环境中根分区默认用 xfs 的情况非常多操作前一定要用 df -T 确认文件系统类型否则一条 resize2fs 上去直接报错。2. 实战准备查清现状与规划扩容方案2.1 用 df、lsblk、fdisk 把家底盘清楚拿到一台需要扩容的机器我习惯按固定顺序先看三组信息。第一组是 df -hT目的是确认哪个挂载点快满了、它是什么文件系统类型。比如输出里 /dev/mapper/rhel-root 挂载在 /类型是 xfs容量 50G已用 47G那就说明 root 分区确实告急。第二组是 lsblk看整体块设备结构判断当前系统是不是 LVM。lsblk 输出中如果有 vg 相关的层级关系比如rhel-root、rhel-swap这类名字基本可以确定是 LVM。第三组是 vgs、pvs、lvs看卷组里是否还有空余空间。如果 VFree 已经是 0那不管你是想在 root LV 上直接扩还是新建 LV都得先想办法增加物理空间。看完了还要顺手确认分区表格式。fdisk -l 输出里如果出现 Disklabel type: gpt 就是 GPT如果是 dos 就是 MBR。GPT 和 MBR 的扩展操作在部分工具上存在细微差异尤其是老系统里 MBR 分区数量超过 4 个时会强制要求用扩展分区这些细节在后面的实操部分再具体展开。2.2 不同场景下的扩容路径选择根据现状可以大致分成四种场景我列个表格方便大家直接对照场景现状扩容路径场景ALVM 卷组里还有空闲空间直接 lvextend resize2fs / xfs_growfs场景BLVM 卷组满了但底层磁盘还能扩大扩磁盘/新加盘 → 建分区 → pvcreate → vgextend → lvextend → 刷新文件系统场景C非 LVM 单分区底层磁盘有剩余空间扩磁盘 → 分区重建/ growpart → resize2fs场景D非 LVM 但完全没有剩余空间新加盘并挂载到新目录或通过 rsync 迁移数据这四个场景基本覆盖了现实中 95% 的扩容需求。场景A最简单甚至不需要重新识别磁盘但实际生产中遇到最多的是场景B也就是文题里root and other的典型情况——根分区所在的 LVM 卷组已经把现有磁盘榨干了。我遇到过不少用户直接在场景B里执行 lvextend结果 LV 还是那么大原因就是 VG 根本没有空闲空间可用lvextend 实际执行其实是失败的但因为某些脚本把错误信息吞掉了df 看着没变化。2.3 先确认底层扩容动作已经在磁盘层生效还有一个经常被忽略的检查项如果你的服务器是虚拟机底层磁盘扩容是在虚拟化平台完成的比如 VMware、KVM、Proxmox、云主机控制台那么在操作系统内部磁盘可能不会自动识别到新增的空间。这时候需要让内核重新扫描一下磁盘。常见手段有对 /dev/sda 执行echo 1 /sys/class/block/sda/device/rescan或者用partprobe有的云平台甚至要求重启实例才能让磁盘识别新空间。先跑一遍 lsblk 看底层磁盘容量有没有变化这种小习惯能帮你省掉后面一整轮排查。3. 实操LVM 根分区在线扩容最常见场景3.1 给虚拟磁盘加容量VMware、KVM、云主机的差异先说底层扩容这一步。如果你用的是 VMware vSphere 或 Workstation可以直接在虚拟机设置里把硬盘大小调大这一步不需要关机对现代 Linux 发行版来说也基本能做到热添加。KVM 环境通常用qemu-img resize修改磁盘镜像大小但需要确保虚拟机内有 virtio-scsi 驱动来识别新空间。云主机更简单在控制台里对云盘发起扩容操作然后在系统内部执行growpart或者重启不同云厂商的在线扩容机制略有差异但最终都是让底层的 /dev/sda 或 /dev/vda 在 lsblk 里看到更大的容量。这一步做完lsblk 里 disk 这一行的 SIZE 应该已经变大了比如从 100G 变成 200G但分区比如 sda2的大小还是原来那样这就对了说明底层扩容动作已经在磁盘层生效。3.2 用 fdisk 创建新分区并并入卷组假设原来只有一块 100G 的磁盘 /dev/sda上面划了 sda1/boot、sda2LVM PV包含了 root LV 和 swap LV现在底层把它扩成了 200G。这时 VG 里没有多余空间所以要先把 sda2 分区扩大。如果 sda2 后面没有任何分区最方便的方式是用 fdisk 删除 sda2 再重新创建注意起始扇区必须和原来完全一致结束扇区用默认值也就是磁盘末尾这样分区就从原来的大小扩到了整个可用空间。操作如下fdisk /dev/sda # 按 p 打印分区记录 sda2 的 Start 扇区 # 按 d 删除分区sda2 # 按 n 新建分区分区号选 2First sector 填刚才记录的 StartLast sector 直接回车 # 注意fdisk 会提示是否删除已有签名选择 n 保留 # 按 t 修改分区类型需要设为 8eLinux LVM # 按 w 写入分区表这里有个必须强调的点删除分区并不会删除数据删除的只是分区表里的描述真正的数据区直到新分区写入前都还在。但一旦新分区起始扇区变了数据就全乱了好在新分区把起始扇区设定为原值就能完整保留数据。不过即便如此这步操作在有些老系统上还是可能触发内核重新读取分区表导致数据访问异常稳妥做法是先备份再操作。写入完成后执行partprobe /dev/sda让内核重新读取分区表再用lsblk确认 sda2 已经变成 199G 左右。接下来把扩大的分区转成正儿八经的物理卷然后扩展卷组pvresize /dev/sda2 # 如果原来没有在这个分区上建过 PV需要先 pvcreate /dev/sda2 vgs # 看到 VFree 有值了说明卷组获得了新空间 lvextend -l 100%FREE /dev/mapper/rhel-rootpvresize这个命令的作用是让物理卷感知底层分区的新大小对应到场景B中间那些新建分区→pvcreate→vgextend的步骤这里因为是在原 PV 上扩大所以只需要一步。如果你的情况是新增了一块磁盘 /dev/sdb那么流程则是fdisk 创建 /dev/sdb1 → partprobe → pvcreate /dev/sdb1 → vgextend rhel /dev/sdb1。两种路径最终都是让 VFree 多出空间来。3.3 扩展逻辑卷并刷新文件系统类型感知LV 扩展这步我习惯用百分比而不是绝对大小因为省心。-l 100%FREE表示把卷组里所有剩余空间全部划给当前 LV。如果你的卷组还要留给其他 LV比如 swap那就不能全给要留一部分。之后根据文件系统类型执行最后一步# 如果是 xfs xfs_growfs / # 如果是 ext4 resize2fs /dev/mapper/rhel-rootxfs_growfs 的参数是挂载点目录不是块设备路径这一点和 resize2fs 完全不同。执行完后用 df -h 验证正常情况下 root 的容量已经翻倍了。整个过程中除了 fdisk 删建分区那一步有理论上的风险其余全部可以在线完成这也是 LVM 方案最大的价值。实际工作中我就靠这条链路在用户几乎无感知的情况下把一台跑着 MySQL 的服务器 root 分区从 40G 扩到了 200G整个过程服务没有中断过。3.4 非 LVM 根分区如何使用 growpart 扩展如果你装系统时选了标准分区没有 LVM 这一层那就走 growpart resize 路线。假设 /dev/sda1 是 root 分区底层磁盘已经扩容分区后面有可用空间执行growpart /dev/sda 1 resize2fs /dev/sda1 # 如果 root 是 xfs用 xfs_growfs /growpart 比 fdisk 安全得多它不会删除重建分区而是直接在分区表层面修改分区结束扇区保留起始扇区不变天然规避了删除分区的风险。部分旧版本系统没有 growpart可以通过yum install cloud-utils-growpart或apt install cloud-guest-utils安装。非 LVM 场景处理 xfs 根分区时尤其要小心不能先卸载根分区再扩容因为根分区卸载了系统就没法运行了growpart 和 xfs_growfs 都是在线操作切记不要随意重启重启可能导致分区表读取异常。3.5 顺带处理 swap 的扩容如果服务器内存增加swap 也需要跟着扩。LVM 环境下 swap 通常是一个独立的 LV比如 rhel-swap。操作步骤是 swapoff 停用、lvextend 扩大 LV、mkswap 重新格式化、swapon 启用。注意 mkswap 之前一定要确保交换分区已经 swapoff否则会出现设备忙的错误。我一般会同时编辑 /etc/fstab 确认 swap 的 UUID 没有变化如果变化了就用 blkid 拿到新 UUID 更新 fstab否则重启后 swap 无法自动挂载。这个操作比较冷门但正好属于other分区的典型需求顺手记下来。4. 常见问题与排查技巧实录4.1 扩容后 df 没变化手动刷新分区表扩容后 df -h 显示还是老容量这是最常见的翻车现场。先说结论八成是分区表没有被内核重新读取或者扩容命令根本没落在正确的层级。排查顺序建议是先 lsblk 看底层 disk 容量是否已变大再看分区是否变大再看 PV 是否变大最后看 LV 和文件系统。每一层都有对应的查看命令。如果 disk 已经变大但分区没变多半需要 partprobe 或重启如果分区变了但 PV 大小没变需要 pvresize如果 PV 变了但 LV 没变补 lvextend如果 LV 变了但 df 没变执行 resize2fs 或 xfs_growfs。这一条链路捋下来绝大多数扩容问题都能定位。4.2 xfs 扩容后的常见报错挂载点参数写错xfs_growfs 误写成 xfs_growfs /dev/mapper/rhel-root然后提示 is not a mounted XFS filesystem。原因就是 xfs_growfs 后面应该跟的是挂载点路径而不是设备路径。好多人第一次用这个命令都会踩这个坑其实也不怪大家ext4 的 resize2fs 又是传设备路径两者模式不同太容易混了。我自己的习惯是用df -h /确认挂载点然后直接xfs_growfs /不猜不绕。另外 xfs 扩容时还有一个小提示如果是非 root 的 xfs 数据分区挂载在 /data那就执行xfs_growfs /data。4.3 磁盘真的满了导致命令敲不动磁盘用到 100% 的时候系统表现非常诡异Tab 补全卡顿、journald 疯狂写日志、sshd 可能连不上因为 root 的 home 目录也没空间写 .bash_history 了。这个时候别慌先用 df -h 确认到底是哪个挂载点满了如果 root 满了优先清理能立刻释放空间的目录/var/log/journal 下的历史日志、docker 的 overlay2 目录、/tmp 下的临时文件。有一个取巧的办法是查哪些大文件被删除了但仍然被进程占用这会导致 df 显示满但 du 找不到大文件用lsof | grep deleted能找到它们重启对应进程或直接重启机器即可释放空间。扩容操作放在清理出一定余量之后再做会更从容不然满盘状态下创建分区表临时文件都可能失败。4.4 扩容时忘了保留起始扇区导致数据异常非 LVM 分区用 fdisk 删除重建时如果起始扇区填错轻则分区无法挂载重则数据被覆盖。这个错误的根源是操作时没看仔细或者拿到的 fdisk 版本输出格式和旧教程对不上。最稳妥的做法是删除前用fdisk -l输出里记录 Start 列的具体数字重建时直接输入该数字不要依赖默认值。如果你的系统支持 growpart优先用 growpart它能从工具层面保证起始扇区不变。这个点我踩过不只一次写在这里是真心希望大家能避开。4.5 常见问题速查表现象原因处理方式扩容后 df 无变化某层没有刷新从 disk→分区→PV→LV→文件系统逐级检查提示没有空闲空间VG 里没空间了确认底层磁盘是否已扩容然后 pvresize 或 vgextendxfs_growfs 报错不是 xfs参数传成了设备路径改成挂载点路径比如 xfs_growfs /resize2fs 报错设备忙文件系统正在使用/挂载中对根分区不要卸载确保是标准分区直接用 resize2fsfdisk 删除重建后分区消失起始扇区错误或未保存备份数据后重建分区表或换 growpart 操作lsblk 里磁盘没变大底层虚拟化平台未生效在虚拟化平台确认扩容必要时 rescan 或重启实例swap 扩容后重启不生效fstab 中的 UUID 变了用 blkid 获取新 UUID 更新 /etc/fstab4.6 在线操作前的最后一道保险备份与回收站心态虽然 LVM 扩容的大部分步骤可以热操作但 fdisk 删建分区这种操作永远是有风险的。生产环境里我坚持两条原则一是操作前一定要有备份或快照虚拟化平台可以打快照物理机至少要把关键数据 rsync 到别的机器二是操作窗口选在业务低峰期万一出状况有足够的回滚时间。很多刚入门的朋友有一个误区觉得扩容不要钱、分区重建很安全就放松了警惕。实际上分区表是整个存储系统的目录目录坏了数据就在那里但你读不出来那个代价比磁盘满本身要高得多。所以在动手扩容前花十分钟做一次快照或备份比什么都值。最后再分享一点个人体会extend filesystem 这类操作最怕的不是命令不会敲而是对系统当前状态判断失误。我接手过的故障里至少有一半是一开始就判断错了 LVM 分区结构然后照着网上的通用教程硬套最后越搞越乱。建议每一位自己管理 Linux 服务器的朋友把上面第四节的前两个命令df -hT 和 lsblk练成肌肉记忆看到一台机器先摸清它的存储结构再谈扩容。这套流程我用了很多年基本没出过岔子希望对正在解决 root 或数据盘扩容问题的你有实际帮助。