为什么 Linux 只读 remount 失败,只能重启?

文件系统只读有两种:卷只读和 Linux 只读。卷只读是存储侧控制,能恢复;Linux 只读是存储 IO 错误触发的保护机制,remount 基本失败,只能重启。 现象 虚拟机文件系统变成只读: root@host:~# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT vda 253:0 0 20G 0 disk └─vda1 253:1 0 20G 0 part / vdb 253:16 0 4G 0 disk [SWAP] vdc 253:32 0 100G 0 disk root@host:~# touch test touch: cannot touch 'test': Read-only file system 同事说另一个类型的虚拟机只读了能恢复,这个怎么恢复。 排查 先要分清是"卷只读"还是"Linux 只读",两者恢复方式完全不同。 再确认存储是否中断过,因为 Linux 只读通常由存储 IO 错误触发。 根因 同事那个能恢复,是因为不是 Linux 只读,而是卷只读。那个卷是我们公司自己的存储,能控制其读写权限。 但这里 Linux 只读,一般是存储读写有 IO error,触发了 Linux 保护机制,系统只读。 我问他是不是存储中断过,他说是的。 这种 Linux 只读没法恢复,remount 基本失败,只能重启虚拟机。 小结 Linux 文件系统只读,通常是存储 IO 错误触发的保护机制; 卷只读(存储侧控制)可以恢复,Linux 只读(IO 错误触发)基本无法 remount 恢复; 排查时先确认是"卷只读"还是"Linux 只读",两者恢复方式完全不同; Linux 只读只能重启虚拟机恢复。

July 11, 2026 · 1 min · 93 words · 文叨叨

nbd-server 连接被误清理:tcp6 双栈的坑

虚拟机通过 nbd 秒级启动,但 nbd-server 连接总被误清理。根因是新版本 nbd-server 默认用 tcp6 双栈监听,而清理代码用 netstat -4 只过滤 tcp4,把 tcp6 上的连接误判为"无连接"而误清理。 现象 虚拟机通过 nbd 可以实现秒级启动,之前跑的好好的。 最近一个测试环境,总是会出现 nbd 连接丢失的情况。 排查是 base img 的 nbd-server 进程被 kill。 且通过日志看,就是我们的程序给 kill 的。 但是我们的程序是正常的清理,会判断这个 nbd-server 没有连接,才会去 kill。 到底是哪里的问题?是真没有连接了,还是哪里判断有问题。 排查 代码会先检查已经有连接的,这些是肯定不会去 kill: exec_cmd("netstat -4 --tcp -p -n | grep ESTABLISHED | grep nbd-server | awk '{print $4}' | awk -F':' '{print $2}' | sort -u > %s" % tmp_file) 代码已经十年了,看着也很完善,没出过类似问题。 后发现是 tcp6 和 tcp4 的原因,和 nbd-server 的版本有关系: ...

July 5, 2026 · 2 min · 247 words · 文叨叨

裸金属报固件错误:bnx2x 加载不了固件文件

裸金属创建时报固件错误,网卡驱动 bnx2x 加载不了固件文件,导致 bond 从设备打开失败。根因是镜像里缺少驱动需要的固件,用 modinfo 查出来补上即可。 现象 创建裸金属报固件错误,带外上看,保持类似如下: bnx2x: Can't load firmware file bnx2x/bnx2x-e2-7.13.11.0.fw bnx2x: Error loading firmware bond0: (slave eth110): Opening slave failed 排查 把镜像通过 qemu-nbd 挂载上来, 然后用 modinfo 查看这个驱动, 里面会列出需要的固件: filename: /mnt/bootcoree/lib/modules/5.4.0-59-generic/kernel/drivers/net/ethernet/broadcom/bnx2x/bnx2x.ko firmware: bnx2x/bnx2x-e2-7.13.11.0.fw firmware: bnx2x/bnx2x-e1h-7.13.11.0.fw firmware: bnx2x/bnx2x-e1-7.13.11.0.fw 根因与解决 根因是镜像里缺少 bnx2x 驱动需要的固件文件。 把 modinfo 查到的固件下载下来, 放到镜像的 /lib/firmware 对应目录中,就可以了。 小结 网卡驱动加载固件失败,会导致 bond 从设备打开失败; 用 modinfo 查看驱动模块声明的 firmware 字段,就能知道需要哪些固件文件; 把固件放到镜像的 /lib/firmware 对应目录即可解决; 排查固件类问题,modinfo 是最直接的入口。

July 4, 2026 · 1 min · 65 words · 文叨叨

裸金属网卡乱序导致 iSCSI 加载不了:IPAPPEND 2 的妙用

裸金属装机一直卡在 iscsistart,根因是 ethX 网卡乱序,iSCSI 连接建在了错误的网卡上。在 PXELINUX 配置里加 IPAPPEND 2,让引导程序自动把引导网卡的 MAC 追加给内核,即可解决。 现象 创建裸金属时,网卡乱序导致 iSCSI 镜像加载不了,装机一直卡在 iscsistart。 排查 看 PXELINUX 配置: /pxelinux.cfg# cat 01-8c-96-a5-2d-fb-70 DEFAULT linux LABEL linux menu default menu label Linux KERNEL vmlinuz APPEND initrd=initrd.img ip=10.0.0.64:10.0.0.185::255.255.255.0:bm-example:eth0:off ISCSI_TARGET_NAME=iqn.2012-04.example.com:bm-example-boot.img ISCSI_TARGET_IP=10.0.0.185 ISCSI_TARGET_PORT=3260 root=UUID=4a99650e-84e7-4c6a-83f9-1b1c964f39de rw net.ifnames=0 biosdevname=0 这里 APPEND 里有个重要参数:eth0,就是通过 eth0 建立 iSCSI 连接,切换 rootfs。 根因 问题就在这里:ethX 天生就有乱序问题。 我们期望网卡 1 是 eth0,物理链路上和 iSCSI 在一个网络上。 但是因为乱序问题,网卡 2 名称是 eth1,这样 iSCSI 就不通了,因为物理链路就不通。 这个时候 BM 装机就一直卡在 iscsistart。 解决办法 在 PXELINUX 配置中加上 IPAPPEND 2。 ...

June 28, 2026 · 1 min · 153 words · 文叨叨

创建裸金属一直刷 NBP:UEFI 与 Legacy 引导差异

创建裸金属时一直刷 NBP file downloaded successfully,但怎么都进不去系统。根因是启动方式被改成了 UEFI,而裸金属注册时一般是 Legacy,两者的 NBP 文件完全不同。 现象 创建裸金属(BM)时,一直刷 NBP file downloaded successfully,但怎么都跑不进去。 NBP 是 Network Bootstrap Program(网络引导程序)。 看起来 PXE 的程序已经获取成功了,但怎么都跑不进去。 然后只刷这个页面,只不过每次会换一个网卡,看起来还挨个网卡去找 PXE 服务端。 排查 后注意到启动方式是 UEFI,但是我们 BM 注册的时候一般是 Legacy。 且 UEFI 的 NBP 和 Legacy 的 NBP 也不一样,所以肯定是启动不起来的。 后修改裸金属的启动方式为 Legacy,部署成功。 根因:UEFI 与 Legacy 的 NBP 差异 启动模式 常见 NBP 文件名 对应软件 / 来源 Legacy BIOS pxelinux.0 SYSLINUX 引导工具 Legacy BIOS undionly.kpxe / ipxe.pxe iPXE 开源网络引导固件 UEFI 64-bit bootx64.efi / syslinux.efi UEFI 版 SYSLINUX UEFI 64-bit grubx64.efi GNU GRUB2 引导器 小结 NBP 是网络引导程序,PXE 获取成功但进不去,往往是引导模式不匹配; UEFI 和 Legacy 的 NBP 文件完全不同,不能混用; 裸金属注册时一般是 Legacy,如果启动方式被改成了 UEFI,就会一直刷 NBP 但起不来; 排查时先确认启动模式(UEFI / Legacy),再确认对应的 NBP 文件是否正确。

June 27, 2026 · 1 min · 102 words · 文叨叨

ZFS 副本为什么比主本占用大:raidZ 条带与块大小不适配

ZFS 副本通过 zfs send 从主本复制过来,逻辑数据一样,但物理占用却大很多。根因是副本节点的 raidZ 布局(高可用 + 条带)与 16k 块大小不适配,造成空间膨胀。 现象 ZFS 副本比主本大很多。主本数据: root@node1:~# zfs get all vpool/vol-example NAME PROPERTY VALUE SOURCE vpool/vol-example type filesystem - vpool/vol-example creation Thu Apr 24 13:59 2025 - vpool/vol-example used 3.94T - vpool/vol-example available 6.02T - vpool/vol-example referenced 3.94T 上面是主本数据,下面是副本数据。 副本是通过 zfs send 过来的,按道理两者应该是一样的。 但是副本的 used 是 4.75T,主本是 3.94T: root@node2:~# zfs get all vpool/vol-example NAME PROPERTY VALUE SOURCE vpool/vol-example type filesystem - vpool/vol-example creation Sun Aug 23 10:48 2026 - vpool/vol-example used 4.75T - vpool/vol-example available 627G - vpool/vol-example referenced 4.75T 排查 后排查了解发现,实际逻辑数据也是一样的,都是 3.92T: ...

June 21, 2026 · 1 min · 126 words · 文叨叨

为什么 COPY --from 找不到文件?相对路径不相对 WORKDIR

多阶段构建里,COPY --from=<stage> 的源路径并不相对源阶段的 WORKDIR 解析,而是相对目标阶段根目录。所以跨阶段 COPY 时,相对路径会指向错误位置,报 “No such file or directory”。 现象 Docker 多阶段构建时,builder 阶段设置了 WORKDIR /src,文件实际位于 /src/internal/xmlbuild/cpu_rule.json 和 /src/cmd/configs/compute.yaml。 但 COPY --from=builder 后,internal/... 这种相对路径会被解析为相对于 /(即 /internal/...),而不是相对于 WORKDIR /src。 所以 Docker 找不到文件。 排查 先确认报错是不是 “No such file or directory”,且文件确实存在于源阶段。 再检查 COPY 的源路径写法,看是否用了相对路径。 根因 多阶段构建中,COPY --from=<stage> 的源路径是相对于构建上下文或目标阶段的根目录解析的,而不是相对于源阶段的 WORKDIR。 也就是说,COPY --from=builder 之后,就不能用上一个阶段的相对路径了。 比如你写: FROM builder AS build WORKDIR /src # ... 构建,生成 /src/internal/xmlbuild/cpu_rule.json FROM scratch COPY --from=build internal/xmlbuild/cpu_rule.json /app/ 这里的 internal/xmlbuild/cpu_rule.json 会被解析为 /internal/xmlbuild/cpu_rule.json,而不是 /src/internal/xmlbuild/cpu_rule.json,自然找不到文件。 ...

June 20, 2026 · 1 min · 105 words · 文叨叨

虚拟机无响应?重启后快速进 console 看内核日志

虚拟机无响应,virsh console 卡住进不去。一个思路是重启后快速进入 console,看内核启动日志,往往能直接暴露根因。 现象 虚拟机无响应,virsh console 卡在下面这个地方: virsh console vm-example Connected to domain vm-example Escape character is ^] 排查思路 virsh console 卡在这地方,分两步: 多等一会看看,能否进去,可能是启动慢; 等几分钟还不行,那就是有问题了。 一个思路是重新启动,然后快速的进入 virsh console,可能能看到 kernel 启动日志,可能有线索: virsh destroy vm-example; virsh create vm-example.xml virsh console vm-example 比如这里就打印了日志: [ 2.313329][ T1] Run /init as init process Fatal glibc error: CPU does not support x86-64-v2 # 这里就是关键点,cpu 不支持 x86-64-v2 [ 2.315336][ T1] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00007f00 [ 2.316635][ T1] CPU: 0 PID: 1 Comm: init Not tainted 6.6.0-28.0.0.34.oe2403.x86_64 #1 [ 2.317855][ T1] Hardware name: QingCloud E3, BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014 [ 2.319339][ T1] Call Trace: 根因 日志里 Fatal glibc error: CPU does not support x86-64-v2 就是关键线索——CPU 不支持 x86-64-v2 指令集,导致 init 进程直接 panic。 ...

June 14, 2026 · 1 min · 132 words · 文叨叨

清理网卡前先清理相关资源:unregister_netdevice 的坑

LXC 销毁后,hyper 内核报 unregister_netdevice 网卡错误,困扰了很久。根因是网卡 down 后 IPv6 协议栈仍持有 netdevice 引用,在 hyper 中加一个 disable_ipv6=1 的操作就好了。 现象 LXC 销毁后,hyper 内核报网卡错误 unregister_netdevice,这个问题困扰了很久没有解决。 按道理,应该是清理网卡之前,清理相关资源。但我们的程序是直接 down 网卡。 后来有人在网卡 down 后加了一个清理 ipv6 neigh 的操作,然后就好了。卧槽。 排查 先看接口没 down 的时候,比如 eth0 上有 neigh: root@host:~# ip n s 10.0.0.252 dev eth1 lladdr 36:95:2f:f5:af:85 STALE 10.0.0.1 dev eth0 lladdr 02:54:d7:af:4b:cb STALE 10.0.0.253 dev eth1 lladdr 52:54:d7:c6:e8:47 STALE fe80::5054:d7ff:fec6:e847 dev eth1 lladdr 52:54:d7:c6:e8:47 router STALE fd00:2024:822:0:167:ffff:ffff:fffd dev eth1 lladdr 52:54:d7:c6:e8:47 router STALE fe80::e01e:53ff:fe85:5ca0 dev eth0 lladdr 02:54:d7:af:4b:cb router STALE 把接口 eth0 down 掉: ...

June 13, 2026 · 2 min · 275 words · 文叨叨

为什么新系统跑不起来?默认 qemu 指令集不够用

新系统跑不起来,报 “CPU does not support x86-64-v2”,根因是现代 OS 默认按较新指令集编译,而默认的 qemu64 模型只提供最基础指令。给虚拟机配上合适的 CPU 指令集就能解决。 现象 一台 primusos2403sp1x64 的虚拟机,没有配置 CPU 指令集的情况下,运行僵死。配置指令集后,就能正常运行了。 排查 用 virsh reset vm-example && virsh console vm-example 可以看到 glibc 打印的错误: [ 1.536627][ T1] Run /init as init process Fatal glibc error: CPU does not support x86-64-v2 [ 1.538855][ T1] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00007f00 [ 1.540681][ T1] CPU: 6 PID: 1 Comm: init Not tainted 6.6.0-103.0.0.106.oe2403sp1.x86_64 #1 [ 1.542633][ T1] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.1-0-ga5cab58e9a3f-prebuilt.qemu.org 04/01/2014 [ 1.545203][ T1] Call Trace: [ 1.545959][ T1] <TASK> [ 1.546568][ T1] dump_stack_lvl+0x32/0x50 [ 1.547593][ T1] panic+0x304/0x340 [ 1.548411][ T1] do_exit+0x3f4/0x410 [ 1.549284][ T1] do_group_exit+0x2d/0x80 [ 1.550272][ T1] __x64_sys_exit_group+0x14/0x20 [ 1.551151][ T1] do_syscall_64+0x55/0x100 [ 1.551963][ T1] entry_SYSCALL_64_after_hwframe+0x78/0xe2 [ 1.553370][ T1] RIP: 0033:0x7f40667d3db5 [ 1.557729][ T1] RSP: 002b:00007ffcb3db2f68 EFLAGS: 00000202 ORIG_RAX: 00000000000000e7 [ 1.559088][ T1] RAX: ffffffffffffffda RBX: 00007f40667cf490 RCX: 00007f40667d3db5 [ 1.560108][ T1] RDX: 0000000000000000 RSI: 00007ffcb3db2630 RDI: 000000000000007f [ 1.561078][ T1] RBP: 00007ffcb3db3140 R08: 0000000000000010 R09: 0000000000000000 [ 1.562048][ T1] R10: 0000000000000001 R11: 0000000000000202 R12: 00007f40667e2ab0 [ 1.563025][ T1] R13: 0000000000000000 R14: 0000000000000000 R15: 00007f40667b4000 [ 1.563990][ T1] </TASK> [ 1.564790][ T1] Kernel Offset: 0x38c00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff) [ 1.566210][ T1] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00007f00 ]--- 根因 这是已知问题:现代操作系统都开启了指令集优化,纯 qemu 的模拟指令无法满足运行的基本要求,必须配上指令集才能运行。 ...

June 7, 2026 · 2 min · 280 words · 文叨叨