Windows + Ubuntu 双系统扩容实践:从 Windows 划出 300GB,将 /home 迁移到独立 ext4 分区
本文记录一次真实的 Ubuntu 扩容过程。
我的电脑是 Windows 11 + Ubuntu 双系统,Ubuntu 最初只分配了约 108GB。随着 Zephyr SDK、STM32 工具链、Conda、VS Code、机器人开发环境等不断增加,Ubuntu 根分区最终只剩不到 1GB。考虑到直接移动根分区风险较高,我最后采用了更稳妥的方案:
从 Windows 压缩出 300GB → 新建 ext4 分区 → 将
/home迁移到新分区。
最终效果:
/dev/nvme0n1p5 → / 106GB,剩余约 59GB
/dev/nvme0n1p6 → /home 295GB,剩余约 226GB
这篇文章既记录具体操作,也重点总结其中几个容易踩坑的地方,适合有相同需求的同学或公司同事参考。
一、我的磁盘为什么会不够用
一开始执行:
df -h
得到:
文件系统 大小 已用 可用 已用% 挂载点
/dev/nvme0n1p5 106G 100G 约1G 100% /
而 Windows 分区有 845GB,实际只使用了约 127GB。
Ubuntu 里的主要空间占用包括:
/home 约 60GB
/opt 约 14GB
/var 约 7GB
/usr 约 10GB
进一步查看 /home:
du -hd1 ~ 2>/dev/null | sort -h
其中比较大的目录包括:
11G ~/zephyr-sdk-1.0.1
9G ~/zephyrproject
5G ~/.cache
5G ~/.zephyr_ide
4.8G ~/miniconda3
2.2G ~/STM32Cube
...
这类开发环境大部分都位于 /home。因此,与其直接移动整个 Ubuntu 根分区,不如给 /home 单独分配一个大分区。
二、最终选择:不直接扩根分区,而是独立 /home
我的原始分区布局大致如下:
[EFI][MSR][Windows p3][Ubuntu p5][Windows Recovery p4]
其中:
/dev/nvme0n1p1 EFI
/dev/nvme0n1p2 Microsoft Reserved
/dev/nvme0n1p3 Windows NTFS
/dev/nvme0n1p5 Ubuntu ext4,挂载为 /
/dev/nvme0n1p4 Windows Recovery
理论上,可以从 Windows 尾部压缩空间,再将 Ubuntu 根分区向左扩展。
但由于未分配空间位于 Ubuntu 分区左侧,直接扩根分区需要移动 ext4 分区的起始位置。这意味着要搬移大量数据,操作时间长,断电或异常中断的风险也更高。
所以我选择:
原布局:
[Windows p3][Ubuntu p5 /][Recovery p4]
调整后:
[Windows p3][新 ext4 p6 /home][Ubuntu p5 /][Recovery p4]
这个方案的优点是:
-
不移动原来的 Ubuntu 根分区;
-
不修改 Ubuntu 分区起始位置;
-
不碰 EFI 和 Windows 恢复分区;
-
即使迁移失败,旧
/home数据仍然保留; -
后续重装系统时,也可以考虑继续复用独立
/home。
三、操作前先确认真实分区结构
df -h 只能查看已经挂载的文件系统,不能完整展示分区布局。
建议先执行:
lsblk -o NAME,SIZE,FSTYPE,FSAVAIL,MOUNTPOINTS,PARTLABEL
以及:
sudo parted -l
我的原始结果类似:
编号 起始点 结束点 大小 文件系统
1 ... ... 273MB fat32
2 ... ... 16.8MB
3 ... ... 907GB ntfs
5 ... ... 116GB ext4
4 ... ... 1035MB ntfs
这里还出现了:
分区表记录没有按磁盘顺序
这通常只是因为 GPT 分区编号和实际物理顺序不一致。例如 p4 可能物理上位于 p5 后面,并不代表磁盘损坏。
四、先备份重要文件
在进行分区操作前,我先将重要代码和文档备份到 Windows 分区。
例如:
rsync -aH --info=progress2 \
~/JforceGlove \
~/STM32_Proj \
~/SEA_test \
~/my_zephyr_apps \
~/0602_NewGalbot_test \
~/文档 \
/media/galbot/Windows/Ubuntu_Backup/
不过这里有一个非常重要的注意事项:
1. 备份前必须确认 Windows 分区真的已经挂载
不要只看目录是否存在。
因为:
/media/galbot/Windows
即使 Windows 分区没有挂载,也可能只是根分区中的一个普通空目录。
备份前应执行:
findmnt -T /media/galbot/Windows/Ubuntu_Backup
以及:
df -hT /media/galbot/Windows/Ubuntu_Backup
必须明确看到目标来源是:
/dev/nvme0n1p3
文件系统类型为:
ntfs3
否则数据可能会被复制到 Ubuntu 根分区,反而进一步占满磁盘。
可以增加一道检查:
mountpoint -q /media/galbot/Windows \
&& echo "Windows 分区已挂载,可以备份" \
|| echo "Windows 分区未挂载,请停止操作"
2. NTFS 备份不能完整保留 Linux 元数据
将普通代码、文档、图片备份到 NTFS 没问题,但 NTFS 不一定能完整保留:
-
Linux UID、GID;
-
ACL;
-
扩展属性;
-
特殊权限;
-
部分软链接;
-
Unix socket 和特殊文件。
因此,Windows 分区上的备份更适合保存:
代码
文档
工程文件
普通数据集
而不是作为完整、可直接恢复的 Linux /home 镜像。
五、公司环境下的一个特殊踩坑:飞连 EDLP 占满根分区
在备份过程中,我发现根分区空间突然从约 8GB 降到了不足 500MB。
重新统计:
sudo du -xhd1 / 2>/dev/null | sort -h
发现:
/opt 由约 14GB 增长到了 22GB
进一步定位:
sudo du -xhd3 /opt/apps/com.volcengine.feilian/files 2>/dev/null \
| sort -h | tail -50
主要空间集中在:
6.4G /opt/apps/com.volcengine.feilian/files/data/edlp/back_paks
1.7G /opt/apps/com.volcengine.feilian/files/data/edlp/back_files
也就是说,在公司终端安全环境中,大量文件复制可能会触发 DLP 文件审计、存证或备份机制。
这种情况不建议直接手动删除安全客户端目录,因为可能:
-
触发重新生成;
-
造成客户端异常;
-
影响企业网络准入;
-
产生审计告警。
应优先联系公司 IT 或安全管理员处理。
此外,我当时还清理了 ~/.cache。由于部分程序仍持有已经删除的文件,出现了:
du 统计较小
df 仍然显示空间被占用
重启后,相关进程关闭,空间从约 500MB 恢复到了约 12GB。
这属于 Linux 中典型的:
文件已经删除,但仍被进程打开
可以通过下面的命令检查:
sudo lsof +L1 2>/dev/null
六、在 Windows 中压缩 C 盘
1. 检查 BitLocker
管理员 CMD 中执行:
manage-bde -status C:
我的结果是:
BitLocker 版本: 无
转换状态: 完全解密
已加密百分比: 0.0%
保护状态: 保护关闭
密钥保护器: 找不到
说明没有启用 BitLocker,因此不需要备份恢复密钥,也不需要暂停保护。
如果显示 BitLocker 已启用,应先保存恢复密钥并暂停保护。
不要把下面两个操作混淆:
manage-bde -protectors -disable C:
这是暂停保护。
而:
manage-bde -off C:
会开始解密整个 C 盘,不是这次操作需要的。
2. 关闭休眠和快速启动
管理员 CMD 中执行:
powercfg /h off
这样可以避免 Windows 休眠或快速启动导致 NTFS 分区处于未完全关闭状态。
3. 压缩 Windows 分区
按:
Win + R
输入:
diskmgmt.msc
找到 C 盘,右键选择:
压缩卷
我准备划出 300GB,因此输入:
307200 MB
压缩完成后得到:
300GB 未分配空间
这里不要:
-
新建简单卷;
-
格式化为 NTFS;
-
分配盘符。
保持“未分配”状态即可。
完成后彻底关机:
shutdown /s /t 0
七、在 Ubuntu 中创建新的 ext4 分区
通常更推荐使用 Ubuntu Live USB 操作。
但我的公司不允许插入私人 U 盘,因此采用了:
在当前 Ubuntu 中,只对未分配空间新建分区,不移动、不调整现有根分区。
因为这次操作只是:
未分配空间 → 新建分区
不会修改已经挂载的 /dev/nvme0n1p5。
打开 GParted:
sudo gparted
确认磁盘为:
/dev/nvme0n1
当时看到的布局为:
/dev/nvme0n1p3 Windows
unallocated 300GiB
/dev/nvme0n1p5 Ubuntu /
/dev/nvme0n1p4 Windows Recovery
在 300GiB 未分配空间上右键选择:
New
设置:
创建为:主分区
文件系统:ext4
卷标:ubuntu_home
对齐:MiB
然后应用操作。
完成后执行:
lsblk -f
得到:
nvme0n1p5 ext4 UUID=... 挂载到 /
nvme0n1p6 ext4 ubuntu_home UUID=... 尚未挂载
这里出现两个 ext4 完全正常:
p5:原来的 Ubuntu 根分区
p6:新建的 /home 分区
八、进入 TTY,尽量减少 /home 的读写
在桌面环境中,很多程序会持续写入 /home,例如:
Chrome
VS Code
微信
飞书
Conda
GNOME 配置
PipeWire
各种后台服务
因此不建议直接在桌面环境中复制。
按下:
Ctrl + Alt + F3
进入 TTY。
登录后,建议先切换到不位于 /home 的目录:
cd /
停止 GNOME 图形登录管理器:
sudo systemctl stop gdm3
执行后屏幕可能会黑掉,只剩左上角光标闪烁。这通常只是图形界面关闭后的显示切换,不代表系统损坏。
重新按:
Ctrl + Alt + F3
即可回到 TTY。
检查状态:
systemctl status gdm3 --no-pager
正常应看到:
inactive (dead)
还可以检查 /home 是否仍有进程使用:
sudo lsof +D /home 2>/dev/null | head -30
少量当前 shell 或系统服务记录不一定有问题,但应尽量关闭:
Chrome
Code
微信
飞书
Python 任务
编译任务
下载程序
九、将新分区临时挂载到 /mnt/newhome
创建临时挂载目录:
sudo mkdir -p /mnt/newhome
挂载新分区:
sudo mount /dev/nvme0n1p6 /mnt/newhome
检查:
df -h /mnt/newhome
我的结果类似:
文件系统 大小 已用 可用 挂载点
/dev/nvme0n1p6 295G 28K 280G /mnt/newhome
查看内容:
ls -la /mnt/newhome
新建的 ext4 分区通常只有:
.
..
lost+found
这里的 /mnt/newhome 只是临时挂载目录,最终分区会挂载到 /home。
十、使用 rsync 迁移 /home
执行:
sudo rsync -aAXH \
--numeric-ids \
--info=progress2 \
/home/ \
/mnt/newhome/
注意源目录和目标目录最后的 /:
/home/
/mnt/newhome/
这样复制后的结构是:
/mnt/newhome/galbot
而不是:
/mnt/newhome/home/galbot
参数含义:
-a 归档模式,保留大部分权限、时间、软链接等
-A 保留 ACL
-X 保留扩展属性
-H 保留硬链接
--numeric-ids 按数值保存 UID/GID
复制完成后检查:
sudo du -sh /home
sudo du -sh /mnt/newhome
我的结果两边都约为:
54G
再执行:
sync
确保缓存数据写入磁盘。
如果 /home 特别大,可以先在桌面环境中进行一次预复制,关闭图形界面后再执行第二次 rsync,只同步变化部分,以缩短维护时间。
十一、配置 /etc/fstab
查看新分区 UUID:
sudo blkid /dev/nvme0n1p6
我的结果为:
/dev/nvme0n1p6:
UUID="6fffcf0a-7941-4cab-8532-a1f21ca5c654"
TYPE="ext4"
先备份:
sudo cp /etc/fstab /etc/fstab.backup-home-migration
编辑:
sudo nano /etc/fstab
在末尾加入:
UUID=6fffcf0a-7941-4cab-8532-a1f21ca5c654 /home ext4 defaults,noatime 0 2
这里的 UUID 必须替换成自己电脑实际查询到的值。
如果 TTY 中不方便复制,可以直接追加:
echo 'UUID=6fffcf0a-7941-4cab-8532-a1f21ca5c654 /home ext4 defaults,noatime 0 2' \
| sudo tee -a /etc/fstab
写完后检查:
tail -5 /etc/fstab
重新加载 systemd 配置:
sudo systemctl daemon-reload
测试 fstab:
sudo mount -a
没有报错后检查:
findmnt /home
应显示:
/home /dev/nvme0n1p6 ext4
再执行:
df -h /home
应显示新的 300GB 分区。
十二、重启并验证新 /home
执行:
sudo reboot
重新进入桌面后先检查:
findmnt /home
确认:
/home → /dev/nvme0n1p6
再查看:
df -h
迁移后,我当时看到:
/dev/nvme0n1p5 106G 100G 5.2G 96% /
/dev/nvme0n1p6 295G 54G 226G 20% /home
这里根分区仍然很满,是因为:
p5 中原来的
/home数据还存在,只是被新挂载的 p6 遮住了。
随后测试重要环境:
ls ~/zephyrproject
conda env list
code --version
ls ~/STM32_Proj
还可以测试写入:
touch ~/home_partition_test
ls -l ~/home_partition_test
rm ~/home_partition_test
确认所有项目、配置和权限正常后,再清理旧数据。
十三、为什么旧 /home 还占空间
迁移前,p5 内部结构为:
p5
└── /
├── etc
├── usr
├── opt
├── var
└── home
└── galbot
迁移后,p6 被挂载到 /home:
当前目录树:
/
├── etc 来自 p5
├── usr 来自 p5
├── opt 来自 p5
├── var 来自 p5
└── home 来自 p6
└── galbot
p5 里面原来的 /home/galbot 并没有消失,只是访问 /home 时被新的 p6 覆盖了。
这和把一块新硬盘挂载到一个已有目录类似:
挂载前:目录里有旧数据
挂载后:看到的是新分区内容
卸载后,旧数据仍然存在。
十四、重新挂载 p5,查看被遮住的旧 /home
创建临时挂载目录:
sudo mkdir -p /mnt/oldroot
将 p5 再挂载一次:
sudo mount /dev/nvme0n1p5 /mnt/oldroot
这里需要说明:
/dev/nvme0n1p5
仍然是当前系统的根分区,只是现在通过 /mnt/oldroot 又增加了一个访问入口。
检查:
findmnt -T /mnt/oldroot/home
我的结果为:
TARGET SOURCE
/mnt/oldroot /dev/nvme0n1p5
说明:
/mnt/oldroot/home
确实位于 p5,而不是新 p6。
检查旧数据大小:
sudo du -sh /mnt/oldroot/home
结果:
54G /mnt/oldroot/home
十五、安全清理旧 /home
这里是整次操作中风险最高的一步。
在删除前,至少确认以下三项:
findmnt /home
必须显示:
/home → /dev/nvme0n1p6
然后:
findmnt -T /mnt/oldroot/home
必须显示来源为:
/dev/nvme0n1p5
最后确认大小:
sudo du -sh /mnt/oldroot/home
确认是旧副本。
更推荐的删除方式
不要直接删除整个 home 目录,建议只删除旧用户目录:
sudo rm -rf --one-file-system /mnt/oldroot/home/galbot
如果有多个用户,应分别确认后删除:
/mnt/oldroot/home/user1
/mnt/oldroot/home/user2
保留空的:
/mnt/oldroot/home
作为 /home 挂载点更规范。
我实际遇到的现象
我当时执行的是:
sudo rm -rf --one-file-system /mnt/oldroot/home
最后报错:
rm: 无法删除 '/mnt/oldroot/home': 设备或资源忙
一开始我以为整个删除失败了。
但检查:
sudo du -sh /mnt/oldroot/home
结果只剩:
4.0K
再执行:
df -h
发现根分区从:
100G 已用
下降到了:
46G 已用
也就是说,rm -rf 已经递归删除了旧 /home 中约 54GB 的内容,只是在最后尝试删除最外层 home 目录时,因为该目录对应当前 /home 的活动挂载位置而返回了 Device or resource busy。
最终结果反而正好是:
旧用户数据被删除
空的 /home 挂载目录被保留
不过不建议依赖这种行为。更稳妥的方式仍然是只删除:
/mnt/oldroot/home/用户名
十六、清理临时挂载目录
确认旧 /home 已经为空:
sudo ls -la /mnt/oldroot/home
sudo du -sh /mnt/oldroot/home
然后:
cd ~
sudo umount /mnt/oldroot
sudo rmdir /mnt/oldroot
如果之前还保留了 /mnt/newhome:
sudo rmdir /mnt/newhome
前提是它已经没有挂载任何分区:
findmnt /mnt/newhome
没有输出后才能删除。
十七、最终结果
最终执行:
df -h
得到:
文件系统 大小 已用 可用 已用% 挂载点
/dev/nvme0n1p5 106G 46G 59G 44% /
/dev/nvme0n1p6 295G 54G 226G 20% /home
现在的磁盘结构相当于:
p5:Ubuntu 系统分区
├── /
├── /usr
├── /opt
├── /var
└── /home 空挂载点
p6:用户数据分区
└── /home
└── galbot
├── zephyrproject
├── miniconda3
├── STM32Cube
├── 项目代码
└── 用户配置
十八、本次扩容最重要的经验
1. 分区操作前必须确认物理布局
至少执行:
lsblk -f
sudo parted -l
不要只根据 df -h 判断磁盘结构。
2. Windows 系统分区尽量在 Windows 中压缩
不要直接在 Linux 中随意缩小 Windows C 盘。
正确方式是:
Windows 磁盘管理 → 压缩卷
3. 未分配空间可以新建分区,但不要随意移动已挂载根分区
本次方案的低风险点在于:
只新建 p6
不移动 p5
不修改 p5 起始位置
4. 迁移 /home 要保留 Linux 权限和属性
推荐:
rsync -aAXH --numeric-ids
普通的:
cp -r
不适合完整迁移 Linux 用户目录。
5. /etc/fstab 写完后不要直接重启
应先执行:
sudo systemctl daemon-reload
sudo mount -a
再用:
findmnt /home
确认挂载来源。
6. 备份目标目录存在,不代表对应分区已经挂载
一定要检查:
findmnt -T 目标路径
df -hT 目标路径
否则可能将备份写回根分区。
7. df 和 du 差异很大时,检查已删除但仍被占用的文件
执行:
sudo lsof +L1
程序仍然打开着已删除文件时:
du 看不到
df 仍然统计占用
关闭相关程序或重启后空间才会释放。
8. rm -rf 报错不代表之前的文件都没有删除
rm -rf 目录 的过程是:
先删除目录内部内容
最后删除目录本身
如果最后目录删除失败,前面的文件可能已经全部删掉。
所以任何删除操作后都要重新检查:
du -sh
df -h
ls -la
9. 删除旧数据前必须确认两个路径分别属于哪个分区
至少执行:
findmnt /home
findmnt -T /mnt/oldroot/home
路径相似并不代表它们属于同一个文件系统。
10. 对公司电脑,还要考虑终端安全软件
大量复制可能触发:
DLP 审计
文件存证
杀毒扫描
缓存和日志增长
公司终端出现异常空间占用时,除了检查 /home、/var,还应关注:
/opt
企业安全客户端目录
不要未经授权删除公司安全软件的数据。
十九、总结
这次扩容表面上只是“给 Ubuntu 增加了 300GB”,但整个过程让我真正理解了几个 Linux 文件系统中的核心概念:
-
分区决定磁盘空间如何划分;
-
ext4、NTFS 是建立在分区上的文件系统;
-
挂载是把一个文件系统接入 Linux 目录树;
-
/home只是一个路径,它可以位于根分区,也可以来自另一块独立分区; -
新分区挂载到
/home后,旧目录不会自动删除,只是被遮住; -
同一个文件系统可以通过不同挂载点访问;
-
删除前最重要的不是看路径名字,而是确认路径对应的真实块设备。
最终我没有通过移动根分区来扩容,而是将 /home 迁移到了独立分区。这种方式风险相对更低,也更符合我的实际使用特点:系统文件变化不大,但各种 SDK、工具链、项目和用户缓存会持续增长。
对于和我一样使用 Windows + Ubuntu 双系统,并且 Ubuntu 根分区空间不足的人来说,独立 /home 是一个值得考虑的方案。
不过必须强调:
分区和
rm -rf都属于高风险操作。
文中的/dev/nvme0n1p5、p6和 UUID 只适用于我的电脑,不能直接照抄。操作前一定要通过lsblk、findmnt和blkid确认自己的实际设备。
参考命令速查
# 查看空间
df -h
sudo du -xhd1 / 2>/dev/null | sort -h
# 查看分区
lsblk -f
sudo parted -l
# 查看路径属于哪个文件系统
findmnt -T /some/path
df -hT /some/path
# 挂载新 home
sudo mount /dev/nvme0n1p6 /mnt/newhome
# 复制 home
sudo rsync -aAXH --numeric-ids --info=progress2 \
/home/ /mnt/newhome/
# 查询 UUID
sudo blkid /dev/nvme0n1p6
# 测试 fstab
sudo systemctl daemon-reload
sudo mount -a
# 确认 /home
findmnt /home
df -h /home
# 查看旧 home
sudo mount /dev/nvme0n1p5 /mnt/oldroot
sudo du -sh /mnt/oldroot/home
# 清理旧用户目录
sudo rm -rf --one-file-system /mnt/oldroot/home/用户名
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)