Linux分区表重新加载:partprobe/partx/blockdev/kpartx实战指南

📅 发布时间:2026/10/20 13:28:55
Linux分区表重新加载:partprobe/partx/blockdev/kpartx实战指南
前两天我在一台测试机上用 fdisk 给第二块数据盘加了一个分区分区表写完之后我顺手 lsblk 一看新分区并没有出现。多数人第一反应是“分区没建成功”可我分明已经按 p 看到新分区了。真正的原因在于 Linux 内核没有主动重新读取分区表——它还在用旧的内存缓存。想不通这一点后面所有折腾都会绕远路。围绕“分区表重新加载”这个主题我打算把自己实际用过的几套办法完整捋一遍partprobe、partx、blockdev --rereadpt、kpartx什么场景用哪个为什么有时候命令报了成功却还是看不到设备以及最让人头疼的 Device or resource busy 要怎么处理。这篇文章适合正在学 Linux 分区管理的同学也适合工作中常跟磁盘打交道的运维朋友。掌握了这些命令你就不需要为一次分区修改去重启机器省下的时间和风险都很可观。1. 为什么分区表需要“重新加载”1.1 内核眼中的分区表启动时读一次之后就变了Linux 内核在磁盘设备被发现时会读取一次设备上的分区表然后把分区信息维护在内存里同时通过内核事件通知 udev 去创建 /dev/sda1、/dev/sdb2 这类设备节点。此后如果你用 fdisk、parted、gdisk 在用户态修改了磁盘扇区上的分区表内核本身并不会立刻感知。可以把它想象成酒店前台拿着的一份房态表。前台在入住高峰期登记完所有房间后后面客人退房、换房前台如果不去更新那张表新客人就找不到空房。fdisk 这类工具做的事是“实际换房”而内核重载分区表就是“让前台刷新房态表”。这两个动作必须先后发生否则系统看到的房间情况永远是旧的。我曾经碰到过一种情况某台机器上有一块盘fdisk 删除了一个旧分区并新建了两个分区退出 fdisk 时它没有提示自动重新读取然后我立刻用 df 想看挂载点结果当然是什么都没有。这不是分区没写完而是内核还牢牢抓着旧的分区列表不放手。1.2 “整盘重扫”和“单分区增删”两条技术路线Linux 提供实时感知分区表变化的途径本质上有两条第一条是内核提供的 BLKRRPART 块设备请求意思是“重新读取整块磁盘的分区表并重建所有分区设备”。partprobe 和 blockdev --rereadpt 走的就是这条路。这种方式干净彻底但有一个前置条件整块磁盘上不能有正在使用中的分区否则内核会返回“Device or resource busy”。因为一旦重建所有分区设备正在读写的文件系统句柄就会失效内核不敢这么莽。第二条是 BLKPG 请求它的粒度更细可以在不整体重扫的情况下向内核添加或删除某一个分区。partx 走的是这条路。它的好处很明显磁盘上其他分区照常工作只把新分区告诉内核或者只把某个已经删除的分区从内核里抹掉。这不影响业务也不用卸盘所以非常适合生产环境下在线加盘、减盘的场景。理解了这两条路线再去看各种命令的行为就会非常清晰为什么 partprobe 在某些磁盘上总是失败为什么 partx 却能成功为什么 blockdev 看起来和 partprobe 差不多却偶尔更有效。接下来我逐个拆开说。2. 快速上手四个常用重载命令的定位和选型2.1 partprobe默认首选来自 parted 家族partprobe 是 parted 软件包里的一个小工具也是 Linux 上提到“重载分区表”时最先跳出来的命令。最简单的用法是直接指定磁盘设备partprobe /dev/sdb不带参数时它会尝试遍历所有块设备不过我个人建议还是显式指定设备这样输出和结果更可控。partprobe 的核心动作就是触发 BLKRRPART让内核重新读取 /dev/sdb 上的分区表然后 udev 根据新的分区信息创建或删除对应的 /dev/sdb1、/dev/sdb2 节点。在大部分新磁盘、未挂载磁盘的场景下partprobe 是最好用的。比如你刚给一块新盘写好了分区表执行一次 partprobelsblk 立刻就能看到新分区。它的问题也出在“整盘重扫”上如果磁盘上有挂载中的分区或者有进程占用了分区设备它会直接报错。在部分老版本内核、或者某些特殊驱动上它对 GPT 分区表的同步也偶尔有些小脾气所以它只适合“磁盘有空档”的情况。2.2 partx按分区精准操作的“精细手术刀”partx 来自 util-linux 工具集绝大多数发行版默认都装了。它既能查看分区表也能单独把某个分区加入或移出内核。常用命令分成几类partx -l /dev/sdb # 读取磁盘分区表列出里面所有分区 partx -a /dev/sdb # 把分区表里全部分区都通知内核创建对应设备 partx -a /dev/sdb 1 # 只加载 1 号分区可以写成 partx -a /dev/sdb1 partx -d /dev/sdb1 # 把 1 号分区从内核中删除 partx -u /dev/sdb # 更新内核里的分区信息让内核和磁盘上的分区表一致它的原理不是整盘重扫而是通过 BLKPG 请求对分区设备进行个体增删。正因为这样即使磁盘上某个分区正在挂载使用你仍然可以用 partx 去加载一个刚创建的新分区而不会惊动已经挂载的旧分区。这一点在在线扩容场景里堪称救命技能。对初学者来说partx 是比 partprobe 更“讲理”的工具它不会因为一个分区忙就把整张表拒绝掉。适合在分区表与内核状态不一致时精准地修正某一项。2.3 blockdev --rereadpt简单粗暴的整盘重扫blockdev 是 util-linux 里用来查询和控制块设备的命令其中 --rereadpt 选项就是让内核重新读取分区表blockdev --rereadpt /dev/sdb # 或简写 blockdev -r /dev/sdb它本质上也调用 BLKRRPART和 partprobe 站在同一条技术路线。区别在于行为更直接几乎不做多余处理对脚本和排查问题来说输出也更干净。在磁盘未占用的情况下用 blockdev --rereadpt 常常比 partprobe 可靠因为 partprobe 背后还牵扯 parted 库的一些分区表判断逻辑偶尔会遇到“明明执行成功但 /dev 下没有新设备”的尴尬。如果磁盘上存在挂载或占用blockdev --rereadpt 会直接报错不会像 partx 那样只处理单个分区。所以它可以类比为“重启内核分区模块”的硬操作适合确认磁盘没有任何繁忙进程时使用。2.4 kpartx设备映射族专用kpartx 是 multipath-tools 软件包里的工具设计初衷是让 Linux 能够从 dm 设备或磁盘镜像中识别分区。它读取指定设备上的分区表然后在 /dev/mapper 下创建对应的映射设备比如 /dev/mapper/loop0p1、/dev/mapper/mpatha1。kpartx -a /dev/sdb # 为 /dev/sdb 的分区创建 dm 映射 kpartx -d /dev/sdb # 删除映射这个命令和前面三个有本质区别partprobe、partx、blockdev 都是让内核直接认识磁盘上的分区而 kpartx 是通过 Device Mapper 再创建一个“逻辑分区设备”。在普通 SATA/SAS 磁盘上一般不需要 kpartx直接 partx 就够了。但在以下场景里kpartx 是绕不开的用 losetup 挂载了一个整盘镜像镜像里有分区想直接挂载里面的某个分区LVM 物理卷或多路径设备需要识别分区表某些虚拟化平台上磁盘呈现为 dm 设备内核默认不会自动识别其中的分区。很多人第一次遇到 kpartx 是在处理 .img 镜像文件时后面我会在实操部分给出一个完整示例。命令原理路径是否影响已使用分区典型场景partprobeBLKRRPART 整盘重扫磁盘忙时失败新磁盘写完分区表快速识别blockdev --rereadptBLKRRPART 整盘重扫磁盘忙时失败脚本中强制重读无占用场景partxBLKPG 单分区增删不影响其他分区磁盘在线时加载/删除新分区kpartxDM 映射设备创建独立映射镜像文件、dm、多路径设备3. 实操指南五个常见场景的分区表重载3.1 场景一新磁盘分区后让所有新分区立即生效这是最常规的情况。假设你刚给机器插上了一块新硬盘 /dev/sdb用 fdisk 分了两个区完成后想立刻看到设备节点。操作顺序如下sudo fdisk /dev/sdb # 在 fdisk 中创建分区写入后退出 sudo partprobe /dev/sdb lsblk正常情况下lsblk 应该就能看到 sdb1 和 sdb2。如果没看到先用 partx -l 确认磁盘上的分区表内容sudo partx -l /dev/sdb如果 partx -l 能看到分区但 /dev 和 /proc/partitions 里没有说明内核还没收到消息可以用sudo partx -a /dev/sdb把全部分区一次性加载进去。这条命令在 fdisk 后经常比 partprobe 更可靠因为 fdisk 退出时并不会保证触发内核重扫而 partx 做的就是把磁盘上已有的分区信息主动告诉内核。我习惯的做法是fdisk 写盘后直接执行 partprobe如果 lsblk 没反应马上用 partx -l 对照再决定是否 partx -a。绝大多数问题都在这一步解决。3.2 场景二磁盘正忙用 partx 单独加载新分区生产环境里最怕的并不是“分区表没加载”而是“磁盘上已经有业务在跑”。比如 /dev/sdb1 已经挂载到 /data 上提供服务你通过在线扩容工具给同一块盘加了新分区 sdb2。这时如果执行 partprobe /dev/sdb几乎必报 busy因为整盘重载会让内核尝试重建所有分区设备而被占用的 sdb1 会阻止这一步。正确做法是只加载新分区sudo partx -a /dev/sdb2 # 或者明确指定分区号 sudo partx -a /dev/sdb 2执行后lsblk 应该能看到新的 sdb2而 sdb1 的挂载和业务不会受到任何影响。这里我踩过一个坑一开始以为必须把整块盘的通知补上结果在线的分区差点被搞出问题。后来才明白partx 的本职就是做精细操作它不会碰其他分区。这种在线加载新分区的思路也适用于拨入新磁盘后直接对整盘分区而不想重启实例的场景。只要系统能识别到磁盘设备本身比如云主机在线挂载新云盘后 lsscsi 能看到那么对这块新盘执行 fdisk 写表再用 partx -a 加载整个过程都可以不断业务。3.3 场景三删除分区后把“僵尸分区”从内核里清掉有时候你用 fdisk 删除了一个分区但 lsblk 仍然能看到旧分区设备甚至 fdisk -l 已经看不到它了这就是内核缓存与磁盘上分区表不一致的典型表现。如果磁盘没有挂载分区直接重扫即可sudo partprobe /dev/sdb如果磁盘上还有其他分区正在使用或者你只想清理某一个僵尸分区可以用 partx 精确删除sudo partx -d /dev/sdb1注意partx -d 后面写的是“内核里要删除的设备”而不是磁盘上的分区号。如果你写的是整块磁盘sudo partx -d /dev/sdb它会一次性移除该磁盘下所有分区设备。这适合你想完全刷新分区状态的场景但前提是确保没有分区正在使用。删除之后如果还需要重新加载磁盘上真实存在的分区再用 partx -a 加回来。这里有两点必须提醒第一如果僵尸分区还有进程在访问删除设备节点不会杀死进程但后续 I/O 会出问题最好先用 lsof 确认。第二删除正在挂载的分区设备是危险的很容易让文件系统进入不可靠状态。对于挂载中的分区正确流程是卸载、确认无占用、再删除。3.4 场景四原始磁盘完整重读 GPT/MBR 分区表如果磁盘没有被挂载也没有任何进程占用你想做一次从零开始的完整重读最稳妥的方式是组合使用 sync、blockdev 和 udevadm。sudo sync sudo blockdev --rereadpt /dev/sdc sudo udevadm settlesync 确保文件系统元数据回到磁盘blockdev --rereadpt 强制内核重新解析分区表udevadm settle 等待设备事件全部处理完毕避免命令刚执行完 lsblk 还没刷新的假象。这里提一个容易混淆的概念blockdev --rereadpt 和 partprobe 都调 BLKRRPART但在某些发行版和内核版本上partprobe 会附带一部分自己的分区表解析逻辑对部分损坏的 GPT 分区表可能会有“吞错误”的行为。blockdev 则更直接如果分区表本身有问题错误信息往往更明显。所以我在排查分区表异常时会优先上 blockdev --rereadpt而不是反复试 partprobe。不过也要说清楚如果磁盘上有分区挂载blockdev --rereadpt 同样会报 Device or resource busy。它不解决“磁盘正忙”的在线重载问题只解决“分区表变了但内核没刷新”的同步问题。3.5 场景五处理磁盘镜像和 dm 设备losetup kpartx这个场景在运维里不常遇到但一旦遇到就非常典型你有一个整盘镜像文件 disk.img里面分了两个区想直接挂载其中的第二个分区而不需要把它烧写到物理盘上。先建立一个 loop 设备再用 kpartx 读取镜像中的分区表sudo losetup -f disk.img sudo losetup -l /dev/loop0 # 确认分配的 loop 设备 sudo kpartx -a /dev/loop0 ls /dev/mapper/如果一切正常/dev/mapper 下会出现 loop0p1、loop0p2 这样的设备。这时你可以直接挂载第二个分区sudo mount /dev/mapper/loop0p2 /mnt/image用完以后先卸载再删除 kpartx 映射和 loop 设备sudo umount /mnt/image sudo kpartx -d /dev/loop0 sudo losetup -d /dev/loop0我早期处理镜像时用的是 partx -a /dev/loop0然后去 /dev/loop0p2 挂载其实也有效。但后来发现在遇到分区表偏移特殊、或者镜像本身由 DM 承载时kpartx 更省心。它相当于在设备映射层重新实现了一套“虚拟分区”不依赖内核默认的分区扫描结果。所以如果你在一个新环境里发现 partx 对 loop 设备加载分区不生效优先试试 kpartx。4. 踩坑记录重载失败时的高效排查清单4.1 “Device or resource busy”到底是谁占用了磁盘这是我在评论区见到最多的问题。报这个错说明内核拒绝了对整个磁盘的分区表重扫原因是至少有一个分区处于使用状态。排查思路按顺序来# 1. 查看挂载情况 findmnt /dev/sdb # 2. 查看哪个进程打开了分区设备 sudo lsof /dev/sdb1 sudo fuser -vm /dev/sdb1 # 3. 确认是否被 swap 或 LVM 占用 sudo swapon --show sudo pvs如果是普通挂载分区要么卸载要么改用 partx 只处理新增分区。如果是 swap 分区需要先 swapoff。如果是 LVM 物理卷情况会复杂很多通常不建议在在线状态下直接重载整盘分区表优先考虑用 pvresize 等 LVM 自身的扩容方式处理。值得强调的是报 busy 不是命令“失效”而是内核在保护正在使用的数据。你不需要硬来换一条更精细的路径partx往往就解决了。4.2 分区表改了但 /proc/partitions 和 /dev 里就是没有这类问题大多不是单个命令能解决的需要检查链路。第一步确认分区表是否真写进了磁盘sudo fdisk -l /dev/sdb如果 fdisk -l 能看到新分区但 /proc/partitions 没有继续执行sudo partx -l /dev/sdb sudo partx -a /dev/sdb如果 partx -l 本身就看不到新分区说明分区表没有被正确写入或者工具选择的结束扇区有问题需要回到分区工具去看。第二步检查 udev 是否创建了节点。即使内核已经认识新分区udev 也可能因为规则或环境原因没有生成 /dev/sdb2。此时执行sudo udevadm settle sudo udevadm trigger --subsystem-matchblock然后再次 lsblk。大多数情况下udevadm trigger 能补上缺失的设备节点。这一步我一开始经常漏掉后来才意识到重载分区表其实包含“内核感知”和“设备节点创建”两件事少了哪一件用户感知都是“没生效”。4.3 GPT 的保护性 MBR 被破坏重载也没用有同学遇到过一块盘明明用 gdisk 写的是 GPT 分区表但机器只把它当空磁盘partprobe 也没反应。这往往不是重载的问题而是 GPT 分区表“保护性 MBR”被破坏了。GPT 规范要求在磁盘开头保留一个假的 MBR用来告诉老式工具“这块盘是 GPT 格式不要乱改”。如果这个保护性 MBR 被某些工具覆盖内核或驱动可能无法识别这是一张 GPT 表自然也不会重建分区设备。这时不要盲目执行重载命令应该先用 gdisk 检查sudo gdisk -l /dev/sdb它会提示 GPT 和 MBR 是否一致必要时会询问你是否修复。修复后再执行 partprobe 或 blockdev --rereadpt。注意这类修复涉及分区表元数据如果分区表本身已经损坏数据找回就是另一个话题了。千万别在不了解风险的情况下执行清除类操作。4.4 工具版本和发行版差异带来的错觉partx、blockdev、partprobe 在不同发行版的实现有差异老版本 partx 可能没有 -u 选项parted 包未安装时 partprobe 直接 command not foundbusybox 环境里 blockdev 只支持部分参数。所以就“看起来没生效”的问题先确认命令本身可用、参数匹配当前版本再下结论。我在最小化安装的系统上吃过亏fdisk 分区完成后执行 partprobe 发现没有这个命令以为工具链坏了。后来才发现是最小化环境没装 parted。解决办法很简单基于发行版安装# Debian/Ubuntu sudo apt install parted util-linux # RedHat/CentOS sudo yum install parted util-linux多路径设备上做分区重载还要更谨慎一些。如果磁盘是被 multipathd 管理的单纯对单个底层设备执行重载往往没有意义你需要让 multipathd 感知分区变化sudo multipath -r之后再查看 /dev/mapper/mpatha1 是否出现。这一步和前面提到的 kpartx 也是配套关系多路径环境的复杂点就在于你面对的是底层磁盘和映射设备两层对象。4.5 重载失败时的一个安全底线分区表重载只是让内核重新认识磁盘上的分区布局它本身不会破坏数据但如果分区表本来就写错了或者你选错了设备名重载后状态可能看起来更糟。比如把 /dev/sda 的数据盘当成 /dev/sdb 去重读一旦分区表内容完全对不上系统可能短暂出现一堆错误设备节点。我的安全底线是执行任何重载命令前先确认设备名与实际目标一致再用 fdisk -l 或 gdisk -l 检查分区表内容。如果分区表内容看起来不符合预期就停下来不要强行 partprobe 或 blockdev --rereadpt。毕竟分区表只是磁盘上的元数据只要没有写入动作数据仍然还在留给你错误纠正的余地。为了防止误操作我还会在操作前把分区表备份一份sudo sgdisk --backup/root/sdb.gpt /dev/sdb万一分区表被搞乱用 sgdisk --load-backup 能恢复这比事后找人要省心得多。根据我个人的经验绝大多数“重载分区表后没生效”的情况都出在“以为命令执行了就万事大吉”上。partprobe 只是通知内核内核还要通过 udev 创建设备节点这中间任何一环被打断你看到的结果都是失败的。所以我把自己的操作习惯固定成了三连先 partx -l 确认分区表本身再决定用 partprobe 还是 partx -a最后用 udevadm settle 收尾。这套流程用下来翻车率很低。如果你的环境里也遇到了类似问题不妨先按这个思路排查一遍大概率比反复重启快得多。