news 2026/9/17 3:56:55

Linux磁盘扩容实战:用LVM将/home空间在线分配给/root

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux磁盘扩容实战:用LVM将/home空间在线分配给/root

1. 先搞清楚现状:你的磁盘到底是LVM还是裸分区

我翻了一圈网上的求助帖,发现问“home空间怎么给root”的人,十个里有八个是当年装系统时随手选了自动分区,后面磁盘告急才想起来补救。还有不少人是买的VPS或云主机,厂商默认给的系统盘规划就很离谱——比如根分区只有20G,/home竟然占了100G,可实际上/home里除了一些没用的示例文件,几乎什么都没有。

这个操作本身不难,但真正难的是:你的磁盘用的是LVM逻辑卷管理,还是传统裸分区。这两套方案的操作逻辑完全不同,搞错了轻则白折腾,重则直接把系统搞崩溃。所以动手之前,先把下面这几条命令敲一遍,摸清家底:

# 查看磁盘和分区结构 lsblk # 查看文件系统使用情况 df -hT # 查看LVM相关状态 pvs vgs lvs

看输出结果的时候,重点盯三件事:

第一,lsblk的输出里有没有LVM字样。

如果看到类似sda3 lvm /或者vg-root这种结构,说明你用的是LVM,那么恭喜你,后面要走的路线非常顺,在线就能完成,不用重启、不用进救援模式、不用U盘启动。如果lsblk显示的是/dev/sda1直接挂载到//dev/sda2直接挂载到/home这种纯裸设备结构,那就得走另一条更麻烦的路子(后面第三章详细说)。

第二,/home用的什么文件系统。

df -hT看,如果是xfs,记住xfs文件系统不支持缩小,这是Linux文件系统的一个硬性限制。如果是ext4,那就没问题,可以随便折腾。这个点直接决定了你的操作顺序和方案选择,后面细说。

第三,LVM卷组里有没有空闲空间。

vgs看,如果VFree列不是0,说明卷组里还有空闲空间没分配,事情就好办很多;如果VFree是0,那就要从现有的逻辑卷里挤空间出来,也就是把/home的容量退还一部分给卷组,再分配给/root。

我先说个生活化的比喻,把LVM讲明白:传统分区就好比买房子的时候直接把墙体砌死了,客厅多大就是多大,真想改格局就得砸墙。而LVM相当于一个精装房里的活动隔断,客厅、卧室之间用的都是可拆卸的隔板,想调整空间大小,只需要挪动隔板就行,不需要动房子的承重结构。

所以,如果你的系统是LVM,那这篇博客的核心操作你都能用得上。如果你是非LVM的裸分区,看到第四章也有折中方案。

2. LVM方案实操:把/home的空间在线转给/root

先把话放在前面:任何涉及磁盘分区的操作都有风险,请务必先备份数据再动手。以下流程我在CentOS 7/8、Ubuntu 20.04/22.04、以及银河麒麟、统信UOS这些国产系统上都验证过,流程是一致的,但每台机器环境不同,谨慎为上。

2.1 备份/home里的数据

很多人觉得这一步多余,尤其是那些/home下基本没什么个人文件的机器。但我见过太多翻车现场:有人误以为lvremove只是把逻辑卷“卸载”,实际上它会把逻辑卷整个删除,连同里面的数据一起抹掉,连进回收站的机会都没有。所以,备份不是可选项,是必选项。

备份方法很简单,直接打包:

tar -czvf /root/home_backup.tar.gz /home/*

如果/home里有大量文件而且不想打包,也可以用cp -a复制:

mkdir -p /root/home_backup cp -a /home/* /root/home_backup/

cp -a会保留权限、属主、时间戳等属性,恢复的时候直接拷回去就行。打包方式更保险,一个tar包不会漏文件,就是如果数据量很大的话时间比较长。

2.2 卸载/home并确保没有进程占用

卸载前要特别提醒:如果/home是一个独立的逻辑卷,才需要卸载;如果你根本看不到/home对应独立分区,那大概率/和/home是在同一个根分区里,这种情况不需要做任何操作

怎么确认?再看一眼df -h,如果/home不出现在独立行里,说明它就是根分区下的一个普通目录,根本不存在“把home扩容给root”的问题。这种情况你真正要解决的是根分区本身太小,处理思路完全不同。但既然你能看到/home和/是两个独立行,说明它们各自是独立的文件系统。

接下来卸载:

umount /home

如果系统提示target is busy,说明有进程还在/home下开着文件。用fuser找出并杀掉这些进程:

fuser -km /home

然后再次尝试卸载。-k是kill,-m是挂载点,意即杀掉所有占用/home的进程。

如果fuser没有安装,就手动查:

lsof +D /home

看看是哪个进程在用/home的文件。有时候是一些自启动服务(比如samba、docker、各种数据库)导致的,需要先停掉服务再卸载。

实在卸载不干净,最稳妥的办法是重启系统,然后进入单用户模式或者救援模式,挂载状态下不做任何操作,直接在未挂载的状态下卸载/home然后完成后续步骤。当然,如果是远程服务器,不推荐为了这个单独跑到机房去,尽量用fuser解决,或者干脆走后面说的备份恢复方案。

2.3 删除/缩小/home逻辑卷,腾出卷组空间

确认/home成功卸载之后,现在要腾出空间。这里有两种路数:

路数A:直接删除/home逻辑卷,重新建一个小的

适合/home里没数据或数据已备份,而且以后也不打算整太多东西的场景。参考命令:

lvremove /dev/vg_name/home

执行后会提示确认,输入y。注意:vg_name换成你实际的卷组名,用vgs查看。比如卷组叫centos,那就写/dev/centos/home

删除之后,卷组的空闲空间就变大了。可以用vgs确认。

路数B:不删卷,只是缩小(适用于ext4,XFS不行)

如果/home是ext4文件系统,可以用lvreduce直接缩小逻辑卷:

# 先把文件系统缩小到目标大小(例如20G) resize2fs /dev/vg_name/home 20G # 再把逻辑卷缩小到同样大小 lvreduce -L 20G /dev/vg_name/home

但是,如果你的/home是xfs文件系统,这条路走不通。xfs不支持在线缩小,唯一能把xfs的/home空间让出来的办法就是:备份 -> 删除/重建逻辑卷 -> 恢复数据。所以方案B仅限ext4。

我个人更推荐方案A,因为简单直接,也很少出幺蛾子。前提是数据备份好。

2.4 把腾出来的空间全部或部分划给/root

/home的空间腾出来之后,接下来就是给根目录扩容。先看根目录对应的逻辑卷名:

df -h /

输出里能看到类似/dev/mapper/centos-root/dev/vg_name/root这样的路径。也就是/dev/vg_name/root

接下来用lvextend扩展逻辑卷。如果想把卷组里所有空闲空间都划给根分区:

lvextend -l +100%FREE /dev/vg_name/root

-l +100%FREE的意思是:把卷组里所有空闲的PE(物理扩展块)都添加到root这个逻辑卷里。也可以用-L +80G指定增加80G空间,写法更直观。

执行完之后,逻辑卷大小已经变了,但文件系统还没有感知到这个变化。这时候要根据文件系统类型执行不同的命令:

如果根分区是xfs(CentOS/RHEL默认就是xfs):

xfs_growfs /

注意,xfs用的是xfs_growfs,后面跟挂载点,不需要指定设备路径。

如果根分区是ext4(很多Ubuntu/国产系统是ext4):

resize2fs /dev/vg_name/root

这两个命令的作用都是让文件系统扩展到逻辑卷的新大小。区别在于一个针对xfs,一个针对ext4。

2.5 重建/home并恢复数据

现在给/home重新分配空间。如果你刚才直接删除了home逻辑卷,需要重建它:

# 创建新的home逻辑卷,比如分配20G lvcreate -L 20G -n home vg_name # 格式化,这里看你的需求,ext4兼容性最好;如果你之前是xfs,也可以继续用xfs mkfs.ext4 /dev/vg_name/home

然后挂载回去:

mount /dev/vg_name/home /home

千万记得检查/etc/fstab里的配置。很多发行版在装系统的时候用的是UUID方式挂载,重新格式化之后UUID会变,导致开机无法自动挂载/home。先用blkid看一下新分区的UUID:

blkid /dev/vg_name/home

然后把/etc/fstab里对应的那行改成新的UUID,或者干脆改成设备路径(不推荐,但比UUID变来变去省事)。改完之后用mount -a验证一下,再reboot测试能否正常开机。

最后,把备份的数据恢复回去:

cd / && tar -xzvf /root/home_backup.tar.gz

或者拷贝回去:

cp -a /root/home_backup/* /home/

到这里,整条线就跑通了:/home的空间缩了,/root的空间涨了,数据也没丢。

3. 非LVM方案:没有逻辑卷怎么腾挪

如果你的lsblk输出里根本没有lvm这个字眼,根分区和/home分区就是两块独立的裸分区,那上面的操作完全不能用。这种场景下有几种解法,我按推荐程度排序。

3.1 备份删除重建法

说白了就是:把/home的数据备份走,然后删除/home分区,把磁盘上空出来的空间用growpart或者fdisk分配给根分区所在的物理分区,或者更极端一点——干脆home不要了,把整个磁盘的全部空间都给根分区。

这是最直白、风险也最高的一种方式,因为操作到分区表级别,一旦断电、命令写错,整个盘可能就全废了。

一个例子:系统盘是/dev/sda,根分区是/dev/sda1,home分区是/dev/sda2,而且home在sda2的末尾,正好可以把sda2删掉再把sda1扩展到整个磁盘。

# 1. 备份home数据到外部存储或root cp -a /home/* /root/home_backup/ # 2. 卸载home并删除分区 umount /home fdisk /dev/sda

在fdisk交互页面里,d删除分区,选择home所在的分区号(一般是2),w保存退出。然后用partprobe让内核重新读取分区表。

partprobe /dev/sda

再把根分区扩大到整个磁盘:

# 用growpart比较方便 growpart /dev/sda 1

growpart需要安装(yum install -y cloud-utils-growpartapt install -y cloud-guest-utils),它做的事情就是把根分区扩展到磁盘剩余空间。

最后扩展文件系统:

# 如果是ext4 resize2fs /dev/sda1 # 如果是xfs xfs_growfs /

然后新home怎么办?有两个选择:一是重建一个小的home分区,二是直接在根分区下建/home目录顶上,以后所有用户的家目录都落在根分区里。这个就看你的实际需求。

这个方案的痛点是:必须在卸载/home的状态下操作,而且一旦分区表写错就彻底完蛋。所以如果不是特别紧急,我一般不推荐新手直接干这个。

3.2 GParted图形化操作

如果你不怕麻烦,愿意启动到救援环境或U盘系统里,那GParted是最直观的工具。

准备一个Ubuntu系统U盘,启动后进入试用模式(Try Ubuntu),打开GParted,右键/home分区选择卸载(Unmount),然后右键选择Resize/Move,把大小缩小到目标值,再把根分区扩展,操作完成后点击应用。

这里要提醒一点:GParted操作分区表时不让目标分区处于挂载状态。所以你必须在Live CD环境下操作,不能在当前运行的系统里动当前分区的分区表。这个过程可视化、容错率高一些,但步骤其实和上面fdisk的方式差不多,只是把命令行换成了图形界面。

这个方法适合没有任何经验的新手,或者看得懂图但不放心敲命令的人。唯一的要求是:得有条件用U盘启动机器,远程服务器就没办法了。

3.3 折中方案:/home目录迁移

如果不想动分区表,风险最小但效果也不差的方案是:把/home的数据迁移到根分区下,重新挂载一个绑定的目录。

具体思路是:在/ root下新建一个目录比如/rootdiv/home_data(名字随意),把根分区的一部分空间当作/home来用,把原来/home里的数据都搬过去,以后所有用户的家目录实际落在根分区里,原来的/home分区里的空间就空着了。

这个方案适用于单个分区容量不够的双分区场景:把/home的业务数据迁移,然后把根分区扩容,最后把/home作为目录指到根分区里。

但说句实话,如果你的磁盘物理空间总量是固定的,这个方案并不能“凭空变出”空间来,本质是把原来分给home的空间浪费掉,对你root空间的增长没有任何帮助。唯一能真正利用home空间的做法,还是得删掉或者缩小原来的home分区。

打个比方:你只有一套两居室的房子,非要把客厅扩大一倍,就只能把卧室拆了。所谓“不拆墙”的折中方案其实只适用于“把家具挪个地方”的场景,没办法改变房间的实际面积。

所以在非LVM场景下,老实备份、删分区、扩展根分区,是最直接有效的路径。

4. 常见问题与排查技巧实录

4.1 lvextend之后df -h没变化

这是新手最容易懵的地方。逻辑卷已经从20G变成100G了,但df -h看根目录还是20G。原因很简单:lvextend只是扩展了逻辑卷,没有扩展文件系统

两个文件系统对应两个命令:

文件系统扩展命令说明
xfsxfs_growfs /针对挂载点,不用指定设备
ext4resize2fs /dev/xxx/root必须指定逻辑卷设备路径

执行完第4步之后,再df -h就能看到变化。如果还是没变,检查一下是不是逻辑卷名字写错了,用lvdisplay看看实际路径。

4.2 umount /home报错 target is busy

这个错误几乎每个人都会遇到,多半是当前shell的当前目录就在/home下、或者有服务在读写/home下的文件。解决办法:

cd / fuser -km /home sleep 2 umount /home

如果fuser没有,就用lsof查占用进程。实在不行就重启系统,在开机时按e编辑grub,进入单用户模式(single)再卸载/home操作。但这属于最后一招,一般用不到。

还有一个小细节:不要在/home目录下执行任何命令,否则你用的那个进程(bash)自身就站在/home里,怎么会让你卸载呢。闭着眼睛都知道会报busy。

4.3 删除home逻辑卷后,系统提示找不到用户目录

这大概率是你没把/home挂载回去,或者/etc/fstab里的挂载项没更新。系统开机后找不到/home分区,但登录用户又必须访问/home/用户名这个目录,所以能看到/home变成了一个挂在根目录下的空目录。

检查方法:

lsblk -f cat /etc/fstab

确保fstab里有一行/dev/vg_name/home /home xxx defaults 0 0(或对应的UUID),执行mount -a验证。

另外记得,新格式化的/home目录里有个lost+found是正常的,恢复数据的时候直接往下拷就行,不用理会lost+found目录。

4.4 root分区扩完之后,系统无法启动(进入紧急模式)

这个比较吓人,但多半不是你把系统搞坏了,而是fstab里的UUID变了、对应逻辑卷找不到了。开机进紧急模式后,登录root,执行:

journalctl -xb

看日志里有没有Timed out waiting for device或者UUID not found类似的报错。有的话,改一下/etc/fstab,把对不上号的UUID改成当前的,或者改成逻辑卷路径:

echo "/dev/vg_name/home /home ext4 defaults 0 0" >> /etc/fstab

这里要特别提醒:改fstab的时候一定要小心,不要随便删掉别的条目。fstab写错一条,开机就可能崩,所以建议改之前先备份:cp /etc/fstab /etc/fstab.bak

4.5 xfs文件系统的home也能缩吗

再强调一次:xfs文件系统不支持缩小,只能扩大。网上有人说什么xfs_growfs -D能缩小,那是误读文档,实际操作中没人成功过。所以如果你的home是xfs,别想着“缩小home”,直接备份->删卷->重建->恢复,这是唯一路线。

那xfs的home能不能不删,直接把数据迁移到别的分区,然后把home分区卸下来给root呢?思路可以,实现路径就是上面说的“备份删除重建法”,本质还是删卷重建,xfs自家没法缩。

4.6 为什么我lvextend之后,重启机器又变回去了?

重启后root尺寸变回原样,大概率是启动时内核加载的逻辑卷元数据不同步。一般出现在你用LVM操作后,忘了执行:

vgscan --mknodes vgchange -ay

这两条命令会让LVM重新扫描卷组并激活逻辑卷。如果还是不行,就重启一遍试试,通常重启后LVM会自己恢复正常。

5. 一点实践后的真心话

说回开头的问题。为什么很多人把/home空间划给/root后,后面还会觉得不够用、又要折腾一次?因为问题的根源根本不在“怎么扩容”,而在于最开始分区的时候就没有规划好

现在很多Linux发行版装系统时默认就把/root分得很小,比如CentOS默认只给根分区50G,而把剩下的全部丢给/home。对于服务器场景来说,/home往往是最不常用的目录,真正的数据都在/、/var、/opt、/srv下面,这种默认分区方案就是逼着用户日后折腾。

所以我的建议是:新装系统、买VPS、或者重装虚拟机的时候,如果不知道怎么分,就直接把整个系统盘都挂给/,只分一个根分区就完事。什么/boot、/home、/var单独分区,除非你明确知道自己的用途,否则一律不搞。你问LVM不就是为了灵活吗?可很多人到最后根本不用LVM的几个高级功能,就只把它当普通分区用。

如果你已经装了,而且遇到了本文开头的那个场景,按我给的LVM流程走一遍,基本十分钟内搞定。非LVM就委屈一点,备份数据、滚动操作,也别慌。这个操作实际上没有你想的那么神秘,读几遍命令再动手,成功率很高。

最后再送一个小技巧:操作完之后一定要顺手把分区情况记录下来。比如现在的逻辑卷布局、卷组名、UUID,写在一个笔记文件里或者贴在你服务器的/wiki上。下次再出现磁盘告急的时候,你不需要从头开始分析,直接照着笔记做就行。我敢打赌,一年后你会感谢现在的自己。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 3:56:05

OpenCode 跑 code-reviewer:Key 用 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 3:56:04

PEP 8实战指南:从缩进到自动化工具,打造高可读性Python代码

先给你看两段功能完全一样的代码,都是计算一个列表里所有偶数的平方和。第一段是新手常见的写法,第二段做了风格调整,你感受一下差别:# 写法一 def calc(nums):result0for i in nums:if i%20:resulti*ireturn result# 写法二 def …

作者头像 李华
网站建设 2026/9/17 3:55:51

用纯Bash实现单文件配环境Agent:自动检测、安装与验证

我上周刚拿到一台新开发机,装完系统以后光把 Node、Java、Go、Docker 这些轮子配齐,来回切窗口、找安装包、改 PATH、翻报错,就折腾了大半个下午。这不是第一次了。所以第三次重复做这件事的时候,我实在没忍住,把整套路…

作者头像 李华
网站建设 2026/9/17 3:54:59

Cucumber自动化测试实战:从BDD到Gherkin的完整指南

我第一次用 Cucumber,是在一个购物网站自动化改造项目里。当时团队已经维护了一套 Selenium 脚本,用例数量不少,但产品经理和项目负责人每次验收都要另开一场会,逐条解释“这个脚本到底验证了什么”。直到我们把用例全部改成 Gher…

作者头像 李华
网站建设 2026/9/17 3:54:54

SQL中count(1)、count(*)与count(列名)的区别及性能优化

年初我帮团队复盘一个慢SQL问题,优化完发现执行计划里count(1)被优化器和count(*)处理成了完全一样的东西。但到了count(列名),情况突然不一样了。群里当时吵了一轮:有人说 count(1) 比 count(*) 快,有人说 count(列名) 最快&…

作者头像 李华