银河麒麟桌面操作系统 V11-2603 更新失败(#051)根因分析与解决方案

适用范围:系统更新反复失败,日志报错 #051(grub-mkconfig 退出码 1)
本报告记录该问题的现象、根因、定位方法与解决方案,供遇到同类问题的维护人员参考。


1. 问题现象

系统更新在「部署阶段」失败,日志出现以下记录(本次共出现 4 次,时间分别为 08-19 17:13、08-27 17:47 / 18:58 / 19:17):

[ERROR]: Bootloader write config: /usr/sbin/grub-mkconfig: 子进程已退出,代码 1 (1)
DeployUpdatFinished success = False , error_code = #051 ,
         error_desc = Bootloader write config: /usr/sbin/grub-mkconfig: 子进程已退出,代码 1
系统更新异常,您的电脑即将在5 秒后重启。

特征:

  • 错误码固定为 #051(更新器将 OSTree 退出码映射为 #05 + 1)。
  • 均在 bootloader 写入阶段失败,随后强制重启,更新不生效
  • 与维护/正常模式无关,多次重试结果一致。

2. 根因

Kylin 定制的 OSTree GRUB 生成器(ostree admin instutil grub2-generate)在多个部署共享同一内核版本时,生成的「历史版本」子菜单递归嵌套,且闭合括号数量计算错误,导致 grub-mkconfig 自检失败(退出码 1)。

触发条件(本次全部满足):

  1. 系统存在 ≥2 个 OSTree 部署;
  2. 其中两个部署引用同一内核版本(本次为 6.6.0-76-generic,同时被当前部署与待部署的新版本使用);
  3. 更新时部署新版本,BLS 条目由 2 条扩展为 3 条。

证据:

  • 失败产物 /boot/loader.1/grub.cfg.new 括号统计 {=41、}=38,缺 3 个。
  • grub-script-check 在文件末尾(289 行)报语法错误,属「块未闭合至 EOF」的典型特征。
  • 「历史版本」submenu 被递归嵌套 3 层(第 178/200/222 行)。
  • 在 END 标记前补 3 个 }grub-script-check 通过(EXIT=0)。

更新器本身无缺陷,仅透传 OSTree 的失败;缺陷位于 GRUB 生成器。


3. 定位方法

步骤 操作 结论
1 查看日志 DeployUpdatFinished success = False 的错误码 均为 #051,停留在 bootloader 写入
2 grub-script-check /boot/loader.1/grub.cfg.new 289 行语法错误,EXIT=1
3 统计括号并逐行追踪 15_ostree 段 41/38 不平衡,嵌套 3 层,深度未归零
4 补 3 个 } 后再校验 通过,确认根因即括号闭合
5 /etc/grub.d/15_ostree 末行 exec ostree admin instutil grub2-generate,确认生成方
6 对比 loader.0/entries(2 条,成功)与 loader.1/entries(3 条,失败) 确认触发条件为 BLS 扩展至 3 条
7 临时切换 /boot/loaderloader.1grub-mkconfig 复现同样的失败(38/36 不平衡),切回后成功

排除的错误假设:清理 /usr/lib/modules 残留模块目录无效(生成器依据 BLS 条目而非模块目录);$menuentry_id_option 参数错误假设不成立(修复括号后原样保留仍通过校验)。


4. 解决方案

核心思路:缩减部署数量,使下次部署时 BLS 条目保持 2 条(成功场景),绕开生成器缺陷。

注意:该操作会删除系统回退(rollback)保险。操作前请备份重要数据。

如何确定要解除的部署:执行 sudo ostree admin status,输出中带 * 的为当前运行的部署(绝对不能删);带 (rollback) 标记或 Pinned: yes 的即为回退部署(本次要删的对象)。索引从 0 开始计数(第一行=0,第二行=1)。可交叉验证当前运行部署:cat /proc/cmdlineostree/ostree-<哈希> 与带 * 行的哈希一致。

# 1) 查看部署列表,确定要删除的 rollback 部署(索引从 0 开始)
sudo ostree admin status

# 2) 解除 Pinned 标记(pinned 部署须先 unpin 才能删除)
sudo ostree admin pin --unpin 1

# 3) 删除该部署
sudo ostree admin undeploy 1

# 4) 清理残留 checkout
sudo ostree admin cleanup

# 5) 验证:仅剩 1 个当前部署
sudo ostree admin status

# 6) 预验证 grub 生成恢复正常
sudo grub-mkconfig -o /tmp/grub.cfg.verify ; echo "EXIT=$?"   # 预期 EXIT=0

完成后在正常模式下重新触发更新:

sudo /opt/update-module/current/usr/bin/kylin-update-trigger

验证结果:重新部署成功(日志 Deploy finished with result: True),grub-mkconfig 未再报 #051;重启后 ostree admin status 显示新版本 2205d981 生效。


5. 解决方案的副作用

本方案存在一项可能的副作用(非必然发生):

数据迁移报 #0308(依赖冲突)。升级到「数据迁移」阶段时,若用户自定义软件包与新系统存在依赖冲突,日志可能出现:

DeployUpdatFinished success = False , error_code = #0308 ,
         error_desc = 数据迁移安装失败,请检查环境配置或联系管理员

原因:数据迁移通过 apt 将用户自定义安装的软件包重装进新系统时,用户侧 Qt5 开发包(qtbase5-dev 等 0.33 版)强依赖 libqt5dbus5t64 = 0.33,而新系统内 Qt5 库已升级至 0.39,依赖解析失败。

说明:

  • 该副作用仅在用户自定义软件与新系统存在依赖冲突时发生;若无冲突,数据迁移正常完成,升级全程无报错。
  • 本次实例中因 Qt5 版本冲突触发,属于上述可能场景之一。

影响评估:

  • 即使触发,系统核心更新已成功(新部署生效),#0308 不影响系统切换。
  • 仅用户自定义软件(如 wps-office、linuxqq 等)未迁移至新系统,数据文件不受影响,可手动重装补齐。

结论:该副作用为可能场景,且即便发生也在可接受范围内,不影响更新目标。


6. 研发修复建议

  1. 修复 ostree admin instutil grub2-generate 在多部署共享内核时「历史版本」子菜单的嵌套与括号闭合计算缺陷;「历史版本」子菜单应平铺而非递归嵌套。
  2. 生成器输出后自行校验括号平衡(深度归零)或调用 grub-script-check,不合格即报错回滚,避免写入 /boot。
  3. 环境变量缺失时(如直接运行 grub2-generate)应优雅报错,而非 C 断言 abort。
  4. 数据迁移重装用户包时,应容忍/跳过与新系统版本冲突的旧包,避免整体失败。
  5. 复现路径:存在 ≥2 个共享内核的部署时执行 sudo grub-mkconfig -o /tmp/x

7. 相关文件与日志

以下为排查中涉及的系统内客观存在的路径;排查时生成的证据副本(失败产物、修复后文件、演示脚本)保存在本机分析目录,他人可依据下表路径自行定位。

项目 路径
升级日志 /var/log/kylin-system-updater/kylin-system-updater.log.1#051:194/1140/1525/1842 行;#0308:8812/8834 行)
失败产物 失败时生成于 /boot/loader.1/grub.cfg.new(括号不平衡,可用 grub-script-check 校验)
生成脚本 /etc/grub.d/15_ostree(末行 exec ostree admin instutil grub2-generate
错误码映射 backend/SystemUpdater/backend/BackendOstreeNext.py(185-205 行)
2 个赞