Nvme盘加载调速失败

版本节点:openUBMC 25.12 LTS SP1
Nvme热插拔遍历,在Disk22槽位发现没有温感,定位后发现没有调速没有识别到在位。


有相关日志报错,应该是没有走入正常流程:
storage ERROR: tasks.lua(92): task [update_policy_connector22] error: ./opt/bmc/libmc/lualib/mc/orm/object.lua:515: attempt to index field ‘__mdb_obj’ (a boolean value)

但是这部分暂时没有线索,因为环境目前并没有复现,算是概率性问题。希望帮忙从代码层面看下,什么情况下会触发这样的打印?
KunLun2280V2_2102315QRW10S1100001_20260318-1045.tar.gz (2.9 MB)

答案内容由AI生成,仅供参考:

总结

项目 内容
根本原因 Presence状态为0导致设备未被识别在位,进而引发ORM对象初始化失败,在后续策略任务中尝试访问未创建的对象字段而报错
直接表现 Presence = 0 + attempt to index field '__mdb_obj' (a boolean value)
触发条件 Presence信号未正确上报或初始化失败(可能由硬件抖动、I2C延迟、配置错误等引起)
修复方向 1. 增强对象访问前的状态校验
2. 优化Presence检测与防抖机制
3. 加强热插拔流程日志追踪

:light_bulb: 建议优先在代码中加入对象有效性判断,防止此类低级错误引发连锁异常;同时结合trace日志复现场景,定位首次Presence丢失的根本原因。

点击此处查看详细分析解答

NVMe盘加载调速失败问题分析

问题现象

在对NVMe盘进行热插拔遍历时,系统发现Disk22槽位的NVMe盘没有温度感知(无温感),进一步定位发现调速策略未能正确加载,且设备未被识别为在位状态。相关日志显示存在持续性的任务执行错误。

关键现象总结:

  • Disk22槽位NVMe盘未触发正常调速流程。
  • 系统日志中出现重复错误:attempt to index field '__mdb_obj' (a boolean value)
  • connector_Policy_01010217 对象的 .Presence 属性值为 0,表明系统未检测到该连接器在位。
  • 故障为概率性复现,当前环境无法稳定重现。

关键证据分析

1. 配置对象状态异常

从截图获取的 connector_Policy_01010217 配置信息显示:

.Presence : 0  ←(关键字段,红色箭头指向)
.Slot     : 22
.Bom      : "14140224"
.Id       : "POLICY"
.LoadStatus : 255
  • .Presence = 0 表明系统认为该连接器未就位(not present),这是导致调速策略未加载的根本原因之一。
  • 即使NVMe盘已物理插入,若Presence信号未正确上报或未通过防抖判断,系统将不会启动后续初始化和策略加载流程。

2. 核心错误日志分析

日志中多次出现以下错误:

storage ERROR: tasks.lua(92): task [update_policy.connector22] error: 
./opt/bmc/libmc/lualib/mc/orm/object.lua:515: 
attempt to index field '__mdb_obj' (a boolean value)

该错误表示:

  • 代码试图访问一个名为 __mdb_obj 的字段(预期为table类型),但实际得到的是布尔值(boolean)。
  • 典型场景是:对象未成功创建或初始化失败,导致返回 false 或其他布尔值,而非预期的对象实例。

这说明在执行 update_policy.connector22 任务时,对应的ORM对象未正确加载或初始化失败,从而无法继续执行调速策略更新操作。


根本原因推测

可能原因一:Presence检测失败导致初始化中断

  • NVMe盘的Presence信号由硬件寄存器(如Scanner)提供。
  • 若Presence信号因硬件抖动、I2C通信延迟或寄存器读取失败,导致首次读取为0且未满足“成功防抖次数”,系统将判定设备不在位。
  • 根据硬件发现机制(Hardware Discovery),非在位设备不会触发后续的策略加载与对象创建流程
  • 结果:connector 对象虽存在配置,但未完成实例化,__mdb_obj 初始化失败 → 返回布尔值 → 触发索引错误。

:white_check_mark:.Presence = 0 完全吻合。


可能原因二:热插拔事件处理不完整

  • 在NVMe热插拔过程中,系统需完成以下步骤:

    1. 检测Presence变化
    2. 触发硬件自发现(Hardware Discovery)
    3. 加载对应SR策略文件(如 14140224_POLICY_xxx.sr
    4. 初始化ORM对象并挂载到D-Bus
    5. 执行调速策略加载任务
  • 若其中任一环节失败(如SR文件加载失败、I2C超时、数据库写冲突),可能导致对象初始化中断。

  • 日志中的 update_policy.connector22 错误表明策略更新任务已触发,但依赖对象未准备好


可能原因三:对象生命周期管理缺陷

错误发生在 mc/orm/object.lua:515,涉及ORM框架的对象访问逻辑。

  • 正常情况下,__mdb_obj 应为数据库映射对象(metatable/table)。
  • 当对象处于以下状态时,可能返回布尔值:
    • 初始化过程中发生异常,返回 false
    • 缓存加载失败,未正确构造对象
    • 多线程/异步加载冲突,导致局部变量覆盖

:warning: 此为代码层面的健壮性问题:未对对象状态做有效性校验即直接访问字段。


可能触发该错误的代码路径

-- 伪代码示意:tasks.lua 中 update_policy 任务逻辑
function update_policy(connector_id)
    local obj = orm.get_object(connector_id)  -- 返回 false 或 nil
    if not obj then return end
    
    -- 尝试访问 obj.__mdb_obj 字段(但 obj 可能是 boolean)
    local mdb = obj.__mdb_obj  -- ← 报错点:attempt to index field (boolean)
    ...
end

orm.get_object() 因初始化失败返回 false 时,后续访问 __mdb_obj 即会抛出运行时错误。


解决建议

1. 增强对象访问的安全性(推荐修复)

在访问任何对象字段前,增加类型检查:

if type(obj) == "table" and obj.__mdb_obj then
    -- 安全访问 __mdb_obj
else
    log.warn("Invalid object state for connector %s", connector_id)
    return
end

避免因初始化失败导致的崩溃性错误。


2. 优化Presence检测逻辑

  • 检查 Scanner 配置中的 FailureDebounceCountSuccessDebounceCount 是否合理。
  • 确保Presence信号有足够的防抖机制,避免误判。
  • 可增加Presence变更事件的日志追踪,便于定位首次检测失败时间点。

3. 增加热插拔初始化状态监控

  • Hardware Discovery 流程中增加日志:
    • 是否检测到Presence变化?
    • 是否尝试加载对应SR文件?
    • ORM对象是否成功创建?
  • 可添加调试命令,查看指定connector的完整生命周期状态。

4. 验证SR策略文件匹配逻辑

  • 确认 Bom="14140224" 是否正确匹配了预设的策略文件(如 14140224_POLICY_*.sr)。
  • 检查是否存在多个同BOM但不同策略的冲突配置。
  • 确保SR文件存在于系统路径中,并具备读取权限。

5. 日志补充建议

建议在以下位置增加诊断日志:

-- 在 tasks.lua 中增加:
local obj = orm.get_object(connector_id)
if not obj then
    log.error("Failed to get ORM object for connector %s", connector_id)
    return
end
if type(obj) ~= "table" then
    log.error("ORM object for connector %s is invalid type: %s", connector_id, type(obj))
    return
end

总结

项目 内容
根本原因 Presence状态为0导致设备未被识别在位,进而引发ORM对象初始化失败,在后续策略任务中尝试访问未创建的对象字段而报错
直接表现 Presence = 0 + attempt to index field '__mdb_obj' (a boolean value)
触发条件 Presence信号未正确上报或初始化失败(可能由硬件抖动、I2C延迟、配置错误等引起)
修复方向 1. 增强对象访问前的状态校验
2. 优化Presence检测与防抖机制
3. 加强热插拔流程日志追踪

:light_bulb: 建议优先在代码中加入对象有效性判断,防止此类低级错误引发连锁异常;同时结合trace日志复现场景,定位首次Presence丢失的根本原因。

参考这里,在dtor析构函数把update_policy_connector这个任务停了,疑似由于nvme拔盘,但这个任务还没停止,导致后续对象已经卸载了,但任务没有停止,导致一直调用一个bool类型的变量

function c_vpd_connect:dtor()
    local task_name = string.format('update_vpd_connector%s', self.Slot)
    local task = c_tasks.get_instance():get_task(task_name)
    if task then
        task:stop()
    end
end

这个dtor函数应该是VirtualVPDConnect对象消亡后自动触发的吧?目前环境上是Disk22在位,然后new_task起的任务访问出问题,没太理解跟dtor的关系在哪里。

一键日志收集中 这条错误日志从上一次硬盘拔出就开始打印了 在上次硬盘拔出时没有正确退出任务,后续硬盘插入后newtask时 发现已有这个任务了 不会再新起任务了,所以持续打印错误日志

任务退出失败有什么线索吗,是因为快速拔插吗? 另外有规避措施吗,看起来任务启动后如果因为异常导致没有正确退出,同槽位插入后拔出也无法结束这个异常的任务吧?是不是只能BMC重启了

解决方案上面写了,在自发现对象卸载时会调用dtor函数,在该函数内将任务停止

function c_vpd_connect:dtor()
    local task_name = string.format('update_vpd_connector%s', self.Slot)
    local task = c_tasks.get_instance():get_task(task_name)
    if task then
        task:stop()
    end
end

也可以不使用c_tasks创建任务,直接用self:new_task创建任务 ,这样子会在对象析构时自动结束属于该对象的所有任务

没搞懂。
在自发现对象卸载时会调用dtor函数,那目前来看就是没有正常触发dtor,导致对象不存在,但是task依然在运行吧?
这个不应该是去解决这个问题吗?或者init函数里触发new_task的task_name为string.format(‘update_vpd_connector%s’, self.Slot),按理说同槽位的应该是固定的task_name,创建新任务没有覆盖旧任务,甚至根本没有创建(如果创建了,调速按理说应该是可以加载的),这个机制是不是也不太合理?

一个是同名Task没法覆盖旧任务或者新起一个任务,也没有相关的日志打印。
另一个是dtor没有正常被调用退出,不知道是否有线索。
这两个点需要帮忙跟踪解决吧,或者明确一下是否有类似问题。

触发了dtor 因为dtor里没有stop任务啊。
new_task如果已有同名任务不会再新创任务了 这是框架的机制,防止重复生成任务。
如果使用self:new_task创建的任务 在obj卸载时 会自动停止任务, 现在用的c_tasks.xx这样不会 这样创出来的任务不属于这个对象,所以不会在对象卸载时停止,上面的回答也说了,两种修改方案
1.使用self:new_task起任务
2.在dtor中 手动stop任务

dtor里不是有一个task:stop()吗,是说这个在对象卸载后,访问self.Slot失败,然后local task变量找不到,从而没能触发任务停止吗?
self:new_task理解了,dtor里手动stop任务还是没太懂,是这个判断方法会有问题吗。

现在调速策略还有一个task 没停 update_policy_connector

带上这个PR 再验证下
【修改描述】修复NVMe盘频繁插拔场景未加载调速策略csr的问题-storage-AtomGit | GitCode