基于嵌入式 Linux 的设备通常需要一种更新应用程序和系统文件的机制。例如,具有 USB 端口的(非联网)实验室仪器可以从 USB 记忆棒获取软件更新。

运行脚本将文件复制到设备内部闪存上的位置是一件简单的事情。然而,存在设备在更新过程中断电并最终变砖的危险。

应用程序文件的情况要容易一些,因为有空间来复制应用程序目录、更新一个副本以及快速交换新旧目录,从而最大限度地减少故障窗口。

对于内核和系统文件来说,情况更加危险,因为它们分布在整个文件系统中。

我们在文件系统中使用硬链接和软链接来识别关键文件。我们使用文件和档案的哈希值来验证文件完整性。我们考虑过在内核中使用紧急 ramfs,以便在从更新的文件系统启动失败时提供后备。

您对这一要求采取了哪些方法?

有帮助吗?

解决方案

我会采用与应用程序文件相同的方法: 制作关键文件并完成自己的分区,链接到它们,然后复制分区。在你的所有init中,首先要检查链接是否显示所有相同的分区,如果没有,重置它们(到具有某个文件的最新日期的文件的分区)。如果你想更新只是将所有内容复制到新分区,如果一切正常(crcs ok)循环文件并为每个文件系统的链接设置为另一个文件系统。

这样,您的关键文件应始终处于理智状态。

方案:

  1. 将文件复制到新分区时更新失败

    没问题,因为链接仍显示旧的工作链接。

  2. 链接时更新失败

    没问题,因为所有新文件都有效且已经复制(否则重新链接步骤不会启动),设置检查正确

其他提示

如果必须确保可靠性,则可以使用两个闪存分区(甚至芯片),一个具有当前工作配置,另一个具有新配置。然后使用硬件看门狗,它将重置单元并将活动的引导闪存分区切换到“最后已知的商品”。配置。

至少有两个分区。我建议4个

  • 启动

  • 备用启动

  • 程序数据备份

  • 程序易失性数据

如果引导失败,请使用 grub 回退引导来备用引导。

因此,如果更新失败,替代方案也可以工作。

切勿更新引导加载程序。

如果数据分区已损坏,请重新格式化并复制备份数据分区。

现在,除非闪存盘失效,否则您不会失败。如果您使用的是 COTS 硬件,并且主磁盘是紧凑型闪存,那么您可以有一个物理隔离的备份,例如一个小 USB 密钥。

恕我直言,任何非原子的更新都可能破坏系统或使检查一致性非常困难。我同意必须避免更新引导加载程序,因为它不是断电安全的。 通常,制造商需要从固件x.x.x更新到版本y.y.y,而不必在更新内核和/或单个文件时烦恼。更新单个文件可能会成为服务的噩梦,因为很难理解客户硬件上运行的是什么。也许您正在将双拷贝方法(应用程序冗余)与单拷贝方法混合使用。我认为这没有多大帮助,因为系统的完整性是由链中的弱组件完成的。如果根文件系统的更新失败,则重复应用程序并不重要。

如果您需要,双重复制方法可以保证更新而不会停止服务。但它需要大量资源,因为所有组件都必须重复。就个人而言,我使用回退方法,如果主应用程序失败或上次更新不成功,则启动RAM中的小rootfs。如果出现任何问题,这个回退系统由引导加载程序自动启动,从USB笔更新系统(如果需要本地更新)。

我从未找到关于这些问题的OSS项目,最近我根据我之前的经验开始了一个新项目。我有几个产品运行它,我的客户很满意。

也许你可以看看它。你可以找到“swupdate”的来源。 ( github.com/sbabic/swupdate 上的(项目名称)。

斯特凡诺

我认为您在这里试图实现的是更新过程的原子性。原子性对于嵌入式设备至关重要,其中突出的原因之一是功耗;但可能还有其他问题,例如硬件/网络问题。我在更新上下文中使用的原子性定义是:

  • 更新总是要么完全完成,要么根本不完成
  • 除了更新程序之外,没有任何软件组件会看到安装了一半的更新

对于嵌入式 Linux,您可能需要更新多个软件组件,并有不同的设计可供选择;这里有一篇关于此的论文: https://mender.io/user/pages/04.resources/_white-papers/Software%20Updates.pdf

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top